--- /dev/null
+/* C K U F I O -- Kermit file system support for UNIX, Aegis, and Plan 9 */
+
+#define CK_NONBLOCK /* See zoutdump() */
+
+#ifdef aegis
+char *ckzv = "Aegis File support, 8.0.200, 4 Mar 2004";
+#else
+#ifdef Plan9
+char *ckzv = "Plan 9 File support, 8.0.200, 4 Mar 2004";
+#else
+char *ckzv = "UNIX File support, 8.0.200, 4 Mar 2004";
+#endif /* Plan9 */
+#endif /* aegis */
+/*
+ Author: Frank da Cruz <fdc@columbia.edu>,
+ Columbia University Academic Information Systems, New York City,
+ and others noted in the comments below. Note: CUCCA = Previous name of
+ Columbia University Academic Information Systems.
+
+ Copyright (C) 1985, 2004,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
+ compatible with C preprocessors that support only #ifdef, #else, #endif,
+ #define, and #undef. Please do not use #if, logical operators, or other
+ preprocessor features in any of the portable C-Kermit modules. You can,
+ of course, use these constructions in platform-specific modules where you
+ know they are supported.
+*/
+/* Include Files */
+
+#ifdef MINIX2
+#define _MINIX
+#endif /* MINIX2 */
+
+#include "ckcsym.h"
+#include "ckcdeb.h"
+#include "ckcasc.h"
+
+#ifndef NOCSETS
+#include "ckcxla.h"
+#endif /* NOCSETS */
+
+#ifdef COMMENT
+/* This causes trouble in C-Kermit 8.0. I don't remember the original */
+/* reason for this being here but it must have been needed at the time... */
+#ifdef OSF13
+#ifdef CK_ANSIC
+#ifdef _NO_PROTO
+#undef _NO_PROTO
+#endif /* _NO_PROTO */
+#endif /* CK_ANSIC */
+#endif /* OSF13 */
+#endif /* COMMENT */
+
+#include <errno.h>
+#include <signal.h>
+
+#ifdef MINIX2
+#undef MINIX
+#undef CKSYSLOG
+#include <limits.h>
+#include <time.h>
+#define NOFILEH
+#endif /* MINIX2 */
+
+#ifdef MINIX
+#include <limits.h>
+#include <sys/types.h>
+#include <time.h>
+#else
+#ifdef POSIX
+#include <limits.h>
+#else
+#ifdef SVR3
+#include <limits.h>
+#endif /* SVR3 */
+#endif /* POSIX */
+#endif /* MINIX */
+/*
+ Directory Separator macros, to allow this module to work with both UNIX and
+ OS/2: Because of ambiguity with the command line editor escape \ character,
+ the directory separator is currently left as / for OS/2 too, because the
+ OS/2 kernel also accepts / as directory separator. But this is subject to
+ change in future versions to conform to the normal OS/2 style.
+*/
+#ifndef DIRSEP
+#define DIRSEP '/'
+#endif /* DIRSEP */
+#ifndef ISDIRSEP
+#define ISDIRSEP(c) ((c)=='/')
+#endif /* ISDIRSEP */
+
+#ifdef SDIRENT
+#define DIRENT
+#endif /* SDIRENT */
+
+#ifdef XNDIR
+#include <sys/ndir.h>
+#else /* !XNDIR */
+#ifdef NDIR
+#include <ndir.h>
+#else /* !NDIR, !XNDIR */
+#ifdef RTU
+#include "/usr/lib/ndir.h"
+#else /* !RTU, !NDIR, !XNDIR */
+#ifdef DIRENT
+#ifdef SDIRENT
+#include <sys/dirent.h>
+#else
+#include <dirent.h>
+#endif /* SDIRENT */
+#else
+#include <sys/dir.h>
+#endif /* DIRENT */
+#endif /* RTU */
+#endif /* NDIR */
+#endif /* XNDIR */
+
+#ifdef UNIX /* Pointer arg to wait() allowed */
+#define CK_CHILD /* Assume this is safe in all UNIX */
+#endif /* UNIX */
+
+extern int binary, recursive, stathack;
+#ifdef CK_CTRLZ
+extern int eofmethod;
+#endif /* CK_CTRLZ */
+
+#include <pwd.h> /* Password file for shell name */
+#ifdef CK_SRP
+#include <t_pwd.h> /* SRP Password file */
+#endif /* CK_SRP */
+
+#ifdef HPUX10_TRUSTED
+#include <hpsecurity.h>
+#include <prot.h>
+#endif /* HPUX10_TRUSTED */
+
+#ifdef COMMENT
+/* Moved to ckcdeb.h */
+#ifdef POSIX
+#define UTIMEH
+#else
+#ifdef HPUX9
+#define UTIMEH
+#endif /* HPUX9 */
+#endif /* POSIX */
+#endif /* COMMENT */
+
+#ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
+#include <sys/utime.h> /* for extra fields required by */
+#else /* 88Open spec. */
+#ifdef UTIMEH /* or <utime.h> if requested */
+#include <utime.h> /* (SVR4, POSIX) */
+#ifndef BSD44
+#ifndef V7
+/* Not sure why this is here. What it implies is that the code bracketed
+ by SYSUTIMEH is valid on all platforms on which we support time
+ functionality. But we know that is not true because the BSD44 and V7
+ platforms do not support sys/utime.h and the data structures which
+ are defined in them. Now this worked before because prior to today's
+ changes the UTIMEH definition for BSD44 and V7 did not take place
+ until after SYSUTIMEH was defined. It also would not have been a
+ problem if the ordering of all the time blocks was consistent. All but
+ one of the blocks were BSD44, V7, SYSUTIMEH, <OTHER>. That one case
+ is where this problem was triggered.
+*/
+#define SYSUTIMEH /* Use this for both cases. */
+#endif /* V7 */
+#endif /* BSD44 */
+#endif /* UTIMEH */
+#endif /* SYSUTIMEH */
+
+#ifndef NOTIMESTAMP
+#ifdef POSIX
+#ifndef AS400
+#define TIMESTAMP
+#endif /* AS400 */
+#endif /* POSIX */
+
+#ifdef BSD44 /* BSD 4.4 */
+#ifndef TIMESTAMP
+#define TIMESTAMP /* Can do file dates */
+#endif /* TIMESTAMP */
+#include <sys/time.h>
+#include <sys/timeb.h>
+
+#else /* Not BSD44 */
+
+#ifdef BSD4 /* BSD 4.3 and below */
+#define TIMESTAMP /* Can do file dates */
+#include <time.h> /* Need this */
+#include <sys/timeb.h> /* Need this if really BSD */
+
+#else /* Not BSD 4.3 and below */
+
+#ifdef SVORPOSIX /* System V or POSIX */
+#ifndef TIMESTAMP
+#define TIMESTAMP
+#endif /* TIMESTAMP */
+#include <time.h>
+
+/* void tzset(); (the "void" type upsets some compilers) */
+#ifndef IRIX60
+#ifndef ultrix
+#ifndef CONVEX9
+/* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
+#ifndef Plan9
+extern long timezone;
+#endif /* Plan9 */
+#endif /* CONVEX9 */
+#endif /* ultrix */
+#endif /* IRIX60 */
+#endif /* SVORPOSIX */
+#endif /* BSD4 */
+#endif /* BSD44 */
+
+#ifdef COHERENT
+#include <time.h>
+#endif /* COHERENT */
+
+/* Is `y' a leap year? */
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from 1970 to `y' (not including `y' itself). */
+#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+
+#endif /* NOTIMESTAMP */
+
+#ifdef CIE
+#include <stat.h> /* File status */
+#else
+#include <sys/stat.h>
+#endif /* CIE */
+
+/* Macro to alleviate isdir() calls internal to this module */
+
+static struct stat STATBUF;
+#define xisdir(a) ((stat(a,&STATBUF)==-1)?0:(S_ISDIR(STATBUF.st_mode)?1:0))
+
+extern char uidbuf[];
+extern int xferlog;
+extern char * xferfile;
+int iklogopen = 0;
+static time_t timenow;
+
+#define IKSDMSGLEN CKMAXPATH+512
+
+static char iksdmsg[IKSDMSGLEN];
+
+extern int local;
+
+extern int server, en_mkd, en_cwd, en_del;
+
+/*
+ Functions (n is one of the predefined file numbers from ckcker.h):
+
+ zopeni(n,name) -- Opens an existing file for input.
+ zopeno(n,name,attr,fcb) -- Opens a new file for output.
+ zclose(n) -- Closes a file.
+ zchin(n,&c) -- Gets the next character from an input file.
+ zsinl(n,&s,x) -- Read a line from file n, max len x, into address s.
+ zsout(n,s) -- Write a null-terminated string to output file, buffered.
+ zsoutl(n,s) -- Like zsout, but appends a line terminator.
+ zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
+ zchout(n,c) -- Add a character to an output file, unbuffered.
+ zchki(name) -- Check if named file exists and is readable, return size.
+ zchko(name) -- Check if named file can be created.
+ zchkspa(name,n) -- Check if n bytes available to create new file, name.
+ znewn(name,s) -- Make a new unique file name based on the given name.
+ zdelet(name) -- Delete the named file.
+ zxpand(string) -- Expands the given wildcard string into a list of files.
+ znext(string) -- Returns the next file from the list in "string".
+ zxrewind() -- Rewind zxpand list.
+ zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
+ zclosf() -- Close input file associated with zxcmd()'s lower fork.
+ zrtol(n1,n2) -- Convert remote filename into local form.
+ zltor(n1,n2) -- Convert local filename into remote form.
+ zchdir(dirnam) -- Change working directory.
+ zhome() -- Return pointer to home directory name string.
+ zkself() -- Kill self, log out own job.
+ zsattr(struct zattr *) -- Return attributes for file which is being sent.
+ zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
+ zrename(old, new) -- Rename a file.
+ zcopy(source,destination) -- Copy a file.
+ zmkdir(path) -- Create the directory path if possible
+ zfnqfp(fname,len,fullpath) - Determine full path for file name.
+ zgetfs(name) -- return file size regardless of accessibility
+ zchkpid(pid) -- tell if PID is valid and active
+*/
+
+/* Kermit-specific includes */
+/*
+ Definitions here supersede those from system include files.
+ ckcdeb.h is included above.
+*/
+#include "ckcker.h" /* Kermit definitions */
+#include "ckucmd.h" /* For keyword tables */
+#include "ckuver.h" /* Version herald */
+
+char *ckzsys = HERALD;
+
+/*
+ File access checking ... There are two calls to access() in this module.
+ If this program is installed setuid or setgid on a Berkeley-based UNIX
+ system that does NOT incorporate the saved-original-effective-uid/gid
+ feature, then, when we have swapped the effective and original uid/gid,
+ access() fails because it uses what it thinks are the REAL ids, but we have
+ swapped them. This occurs on systems where ANYBSD is defined, NOSETREU
+ is NOT defined, and SAVEDUID is NOT defined. So, in theory, we should take
+ care of this situation like so:
+
+ ifdef ANYBSD
+ ifndef NOSETREU
+ ifndef SAVEDUID
+ define SW_ACC_ID
+ endif
+ endif
+ endif
+
+ But we can't test such a general scheme everywhere, so let's only do this
+ when we know we have to...
+*/
+#ifdef NEXT /* NeXTSTEP 1.0-3.0 */
+#define SW_ACC_ID
+#endif /* NEXT */
+
+/* Support for tilde-expansion in file and directory names */
+
+#ifdef POSIX
+#define NAMEENV "LOGNAME"
+#else
+#ifdef BSD4
+#define NAMEENV "USER"
+#else
+#ifdef ATTSV
+#define NAMEENV "LOGNAME"
+#endif /* ATTSV */
+#endif /* BSD4 */
+#endif /* POSIX */
+
+/* Berkeley Unix Version 4.x */
+/* 4.1bsd support from Charles E Brooks, EDN-VAX */
+
+#ifdef BSD4
+#ifdef MAXNAMLEN
+#define BSD42
+#endif /* MAXNAMLEN */
+#endif /* BSD4 */
+
+/* Definitions of some system commands */
+
+char *DELCMD = "rm -f "; /* For file deletion */
+char *CPYCMD = "cp "; /* For file copy */
+char *RENCMD = "mv "; /* For file rename */
+char *PWDCMD = "pwd "; /* For saying where I am */
+
+#ifdef COMMENT
+#ifdef HPUX10
+char *DIRCMD = "/usr/bin/ls -l "; /* For directory listing */
+char *DIRCM2 = "/usr/bin/ls -l "; /* For directory listing, no args */
+#else
+char *DIRCMD = "/bin/ls -l "; /* For directory listing */
+char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */
+#endif /* HPUX10 */
+#else
+char *DIRCMD = "ls -l "; /* For directory listing */
+char *DIRCM2 = "ls -l "; /* For directory listing, no args */
+#endif /* COMMENT */
+
+char *TYPCMD = "cat "; /* For typing a file */
+
+#ifdef HPUX
+char *MAILCMD = "mailx"; /* For sending mail */
+#else
+#ifdef DGUX540
+char *MAILCMD = "mailx";
+#else
+#ifdef UNIX
+#ifdef CK_MAILCMD
+char *MAILCMD = CK_MAILCMD; /* CFLAGS override */
+#else
+char *MAILCMD = "Mail"; /* Default */
+#endif /* CK_MAILCMD */
+#else
+char *MAILCMD = "";
+#endif /* UNIX */
+#endif /* HPUX */
+#endif /* DGUX40 */
+
+#ifdef UNIX
+#ifdef ANYBSD /* BSD uses lpr to spool */
+#ifdef DGUX540 /* And DG/UX */
+char * PRINTCMD = "lp";
+#else
+char * PRINTCMD = "lpr";
+#endif /* DGUX540 */
+#else /* Sys V uses lp */
+#ifdef TRS16 /* except for Tandy-16/6000... */
+char * PRINTCMD = "lpr";
+#else
+char * PRINTCMD = "lp";
+#endif /* TRS16 */
+#endif /* ANYBSD */
+#else /* Not UNIX */
+#define PRINTCMD ""
+#endif /* UNIX */
+
+#ifdef FT18 /* Fortune For:Pro 1.8 */
+#undef BSD4
+#endif /* FT18 */
+
+#ifdef BSD4
+char *SPACMD = "pwd ; df ."; /* Space in current directory */
+#else
+#ifdef FT18
+char *SPACMD = "pwd ; du ; df .";
+#else
+char *SPACMD = "df ";
+#endif /* FT18 */
+#endif /* BSD4 */
+
+char *SPACM2 = "df "; /* For space in specified directory */
+
+#ifdef FT18
+#define BSD4
+#endif /* FT18 */
+
+#ifdef BSD4
+char *WHOCMD = "finger ";
+#else
+char *WHOCMD = "who ";
+#endif /* BSD4 */
+
+/* More system-dependent includes, which depend on symbols defined */
+/* in the Kermit-specific includes. Oh what a tangled web we weave... */
+
+#ifdef COHERENT /* <sys/file.h> */
+#define NOFILEH
+#endif /* COHERENT */
+
+#ifdef MINIX
+#define NOFILEH
+#endif /* MINIX */
+
+#ifdef aegis
+#define NOFILEH
+#endif /* aegis */
+
+#ifdef unos
+#define NOFILEH
+#endif /* unos */
+
+#ifndef NOFILEH
+#include <sys/file.h>
+#endif /* NOFILEH */
+
+#ifndef is68k /* Whether to include <fcntl.h> */
+#ifndef BSD41 /* All but a couple UNIXes have it. */
+#ifndef FT18
+#ifndef COHERENT
+#include <fcntl.h>
+#endif /* COHERENT */
+#endif /* FT18 */
+#endif /* BSD41 */
+#endif /* is68k */
+
+#ifdef COHERENT
+#ifdef _I386
+#include <fcntl.h>
+#else
+#include <sys/fcntl.h>
+#endif /* _I386 */
+#endif /* COHERENT */
+
+extern int inserver; /* I am IKSD */
+int guest = 0; /* Anonymous user */
+
+#ifdef IKSD
+extern int isguest;
+extern char * anonroot;
+#endif /* IKSD */
+
+#ifdef CK_LOGIN
+#define GUESTPASS 256
+static char guestpass[GUESTPASS] = { NUL, NUL }; /* Anonymous "password" */
+static int logged_in = 0; /* Set when user is logged in */
+static int askpasswd = 0; /* Have OK user, must ask for passwd */
+#endif /* CK_LOGIN */
+
+#ifdef CKROOT
+static char ckroot[CKMAXPATH+1] = { NUL, NUL };
+static int ckrootset = 0;
+int ckrooterr = 0;
+#endif /* CKROOT */
+
+_PROTOTYP( VOID ignorsigs, (void) );
+_PROTOTYP( VOID restorsigs, (void) );
+
+/*
+ Change argument to "(const char *)" if this causes trouble.
+ Or... if it causes trouble, then maybe it was already declared
+ in a header file after all, so you can remove this prototype.
+*/
+#ifndef NDGPWNAM /* If not defined No Declare getpwnam... */
+#ifndef _POSIX_SOURCE
+#ifndef NEXT
+#ifndef SVR4
+/* POSIX <pwd.h> already gave prototypes for these. */
+#ifdef IRIX40
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef IRIX51
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef M_UNIX
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef HPUX9
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef HPUX10
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+#ifdef DCGPWNAM
+_PROTOTYP( struct passwd * getpwnam, (const char *) );
+#else
+_PROTOTYP( struct passwd * getpwnam, (char *) );
+#endif /* DCGPWNAM */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* M_UNIX */
+#endif /* IRIX51 */
+#endif /* IRIX40 */
+#ifndef SUNOS4
+#ifndef HPUX9
+#ifndef HPUX10
+#ifndef _SCO_DS
+_PROTOTYP( struct passwd * getpwuid, (PWID_T) );
+#endif /* _SCO_DS */
+#endif /* HPUX10 */
+#endif /* HPUX9 */
+#endif /* SUNOS4 */
+_PROTOTYP( struct passwd * getpwent, (void) );
+#endif /* SVR4 */
+#endif /* NEXT */
+#endif /* _POSIX_SOURCE */
+#endif /* NDGPWNAM */
+
+#ifdef CK_SHADOW /* Shadow Passwords... */
+#include <shadow.h>
+#endif /* CK_SHADOW */
+#ifdef CK_PAM /* PAM... */
+#include <security/pam_appl.h>
+#ifndef PAM_SERVICE_TYPE /* Defines which PAM service we are */
+#define PAM_SERVICE_TYPE "kermit"
+#endif /* PAM_SERVICE_TYPE */
+
+#ifdef SOLARIS
+#define PAM_CONST
+#else /* SOLARIS */
+#define PAM_CONST CONST
+#endif
+
+static char * pam_pw = NULL;
+
+int
+#ifdef CK_ANSIC
+pam_cb(int num_msg,
+ PAM_CONST struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr
+ )
+#else /* CK_ANSIC */
+pam_cb(num_msg, msg, resp, appdata_ptr)
+ int num_msg;
+ PAM_CONST struct pam_message **msg;
+ struct pam_response **resp;
+ void *appdata_ptr;
+#endif /* CK_ANSIC */
+{
+ int i;
+
+ debug(F111,"pam_cb","num_msg",num_msg);
+
+ for (i = 0; i < num_msg; i++) {
+ char message[PAM_MAX_MSG_SIZE];
+
+ /* Issue prompt and get response */
+ debug(F111,"pam_cb","Message",i);
+ debug(F111,"pam_cb",msg[i]->msg,msg[i]->msg_style);
+ if (msg[i]->msg_style == PAM_ERROR_MSG) {
+ debug(F111,"pam_cb","PAM ERROR",0);
+ fprintf(stdout,"%s\n", msg[i]->msg);
+ return(0);
+ } else if (msg[i]->msg_style == PAM_TEXT_INFO) {
+ debug(F111,"pam_cb","PAM TEXT INFO",0);
+ fprintf(stdout,"%s\n", msg[i]->msg);
+ return(0);
+ } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) {
+ debug(F111,"pam_cb","Reading response, no echo",0);
+ /* Ugly hack. We check to see if a password has been pushed */
+ /* into zvpasswd(). This would be true if the password was */
+ /* received by REMOTE LOGIN. */
+ if (pam_pw) {
+ ckstrncpy(message,pam_pw,PAM_MAX_MSG_SIZE);
+ } else
+ readpass((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE);
+ } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
+ debug(F111,"pam_cb","Reading response, with echo",0);
+ readtext((char *)msg[i]->msg,message,PAM_MAX_MSG_SIZE);
+ } else {
+ debug(F111,"pam_cb","unknown style",0);
+ return(0);
+ }
+
+ /* Allocate space for this message's response structure */
+ resp[i] = (struct pam_response *) malloc(sizeof (struct pam_response));
+ if (!resp[i]) {
+ int j;
+ debug(F110,"pam_cb","malloc failure",0);
+ for (j = 0; j < i; j++) {
+ free(resp[j]->resp);
+ free(resp[j]);
+ }
+ return(0);
+ }
+
+ /* Allocate a buffer for the response */
+ resp[i]->resp = (char *) malloc((int)strlen(message) + 1);
+ if (!resp[i]->resp) {
+ int j;
+ debug(F110,"pam_cb","malloc failure",0);
+ for (j = 0; j < i; j++) {
+ free(resp[j]->resp);
+ free(resp[j]);
+ }
+ free(resp[i]);
+ return(0);
+ }
+ /* Return the results back to PAM */
+ strcpy(resp[i]->resp, message); /* safe (prechecked) */
+ resp[i]->resp_retcode = 0;
+ }
+ debug(F110,"pam_cb","Exiting",0);
+ return(0);
+}
+#endif /* CK_PAM */
+
+/* Define macros for getting file type */
+
+#ifdef OXOS
+/*
+ Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
+ incorrectly, so we force their redefinition.
+*/
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* OXOS */
+
+#ifdef UTSV /* Same deal for Amdahl UTSV */
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* UTSV */
+
+#ifdef UNISYS52 /* And for UNISYS UTS V 5.2 */
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* UNISYS52 */
+
+#ifdef ICLSVR3 /* And for old ICL versions */
+#undef S_ISREG
+#undef S_ISDIR
+#endif /* ICLSVR3 */
+
+#ifdef ISDIRBUG /* Also allow this from command line */
+#ifdef S_ISREG
+#undef S_ISREG
+#endif /* S_ISREG */
+#ifdef S_ISDIR
+#undef S_ISDIR
+#endif /* S_ISDIR */
+#endif /* ISDIRBUG */
+
+#ifndef _IFMT
+#ifdef S_IFMT
+#define _IFMT S_IFMT
+#else
+#define _IFMT 0170000
+#endif /* S_IFMT */
+#endif /* _IFMT */
+
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif /* S_ISREG */
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif /* S_ISDIR */
+
+/* The following mainly for NeXTSTEP... */
+
+#ifndef S_IWUSR
+#define S_IWUSR 0000200
+#endif /* S_IWUSR */
+
+#ifndef S_IRGRP
+#define S_IRGRP 0000040
+#endif /* S_IRGRP */
+
+#ifndef S_IWGRP
+#define S_IWGRP 0000020
+#endif /* S_IWGRP */
+
+#ifndef S_IXGRP
+#define S_IXGRP 0000010
+#endif /* S_IXGRP */
+
+#ifndef S_IROTH
+#define S_IROTH 0000004
+#endif /* S_IROTH */
+
+#ifndef S_IWOTH
+#define S_IWOTH 0000002
+#endif /* S_IWOTH */
+
+#ifndef S_IXOTH
+#define S_IXOTH 0000001
+#endif /* S_IXOTH */
+/*
+ Define maximum length for a file name if not already defined.
+ NOTE: This applies to a path segment (directory or file name),
+ not the entire path string, which can be CKMAXPATH bytes long.
+*/
+#ifdef QNX
+#ifdef _MAX_FNAME
+#define MAXNAMLEN _MAX_FNAME
+#else
+#define MAXNAMLEN 48
+#endif /* _MAX_FNAME */
+#else
+#ifndef MAXNAMLEN
+#ifdef sun
+#define MAXNAMLEN 255
+#else
+#ifdef FILENAME_MAX
+#define MAXNAMLEN FILENAME_MAX
+#else
+#ifdef NAME_MAX
+#define MAXNAMLEN NAME_MAX
+#else
+#ifdef _POSIX_NAME_MAX
+#define MAXNAMLEN _POSIX_NAME_MAX
+#else
+#ifdef _D_NAME_MAX
+#define MAXNAMLEN _D_NAME_MAX
+#else
+#ifdef DIRSIZ
+#define MAXNAMLEN DIRSIZ
+#else
+#define MAXNAMLEN 14
+#endif /* DIRSIZ */
+#endif /* _D_NAME_MAX */
+#endif /* _POSIX_NAME_MAX */
+#endif /* NAME_MAX */
+#endif /* FILENAME_MAX */
+#endif /* sun */
+#endif /* MAXNAMLEN */
+#endif /* QNX */
+
+#ifdef COMMENT
+/* As of 2001-11-03 this is handled in ckcdeb.h */
+/* Longest pathname ... */
+/*
+ Beware: MAXPATHLEN is one of UNIX's dirty little secrets. Where is it
+ defined? Who knows... <param.h>, <mod.h>, <unistd.h>, <limits.h>, ...
+ There is not necessarily even a definition for it anywhere, or it might have
+ another name. If you get it wrong, bad things happen with getcwd() and/or
+ getwd(). If you allocate a buffer that is too short, getwd() might write
+ over memory and getcwd() will fail with ERANGE. The definitions of these
+ functions (e.g. in SVID or POSIX.1) do not tell you how to determine the
+ maximum path length in order to allocate a buffer that is the right size.
+*/
+#ifdef BSD44
+#include <sys/param.h> /* For MAXPATHLEN */
+#endif /* BSD44 */
+#ifdef COHERENT
+#include <sys/param.h> /* for MAXPATHLEN, needed for -DDIRENT */
+#endif /* COHERENT */
+#endif /* COMMENT */
+
+#ifdef MAXPATHLEN
+#ifdef MAXPATH
+#undef MAXPATH
+#endif /* MAXPATH */
+#define MAXPATH MAXPATHLEN
+#else
+#ifdef PATH_MAX
+#define MAXPATH PATH_MAX
+#else
+#ifdef _POSIX_PATH_MAX
+#define MAXPATH _POSIX_PATH_MAX
+#else
+#ifdef BSD42
+#define MAXPATH 1024
+#else
+#ifdef SVR4
+#define MAXPATH 1024
+#else
+#define MAXPATH 255
+#endif /* SVR4 */
+#endif /* BSD42 */
+#endif /* _POSIX_PATH_MAX */
+#endif /* PATH_MAX */
+#endif /* MAXPATHLEN */
+
+/* Maximum number of filenames for wildcard expansion */
+
+#ifndef MAXWLD
+/* Already defined in ckcdeb.h so the following is superfluous. */
+/* Don't expect changing them to have any effect. */
+#ifdef CK_SMALL
+#define MAXWLD 50
+#else
+#ifdef BIGBUFOK
+#define MAXWLD 102400
+#else
+#define MAXWLD 8192
+#endif /* BIGBUFOK */
+#endif /* CK_SMALL */
+#endif /* MAXWLD */
+
+static int maxnames = MAXWLD;
+
+/* Define the size of the string space for filename expansion. */
+
+#ifndef DYNAMIC
+#ifdef PROVX1
+#define SSPACE 500
+#else
+#ifdef BSD29
+#define SSPACE 500
+#else
+#ifdef pdp11
+#define SSPACE 500
+#else
+#ifdef aegis
+#define SSPACE 10000 /* Size of string-generating buffer */
+#else /* Default static buffer size */
+#ifdef BIGBUFOK
+#define SSPACE 65000 /* Size of string-generating buffer */
+#else
+#define SSPACE 2000 /* size of string-generating buffer */
+#endif /* BIGBUFOK */
+#endif /* aegis */
+#endif /* pdp11 */
+#endif /* BSD29 */
+#endif /* PROVX1 */
+static char sspace[SSPACE]; /* Buffer for generating filenames */
+#else /* is DYNAMIC */
+#ifdef BIGBUFOK
+#define SSPACE 500000
+#else
+#define SSPACE 10000
+#endif /* BIGBUFOK */
+char *sspace = (char *)0;
+#endif /* DYNAMIC */
+static int ssplen = SSPACE; /* Length of string space buffer */
+
+#ifdef DCLFDOPEN
+/* fdopen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * fdopen, (int, char *) );
+#endif /* DCLFDOPEN */
+
+#ifdef DCLPOPEN
+/* popen() needs declaring because it's not declared in <stdio.h> */
+_PROTOTYP( FILE * popen, (char *, char *) );
+#endif /* DCLPOPEN */
+
+extern int nopush;
+
+/* More internal function prototypes */
+/*
+ * The path structure is used to represent the name to match.
+ * Each slash-separated segment of the name is kept in one
+ * such structure, and they are linked together, to make
+ * traversing the name easier.
+ */
+struct path {
+ char npart[MAXNAMLEN+4]; /* name part of path segment */
+ struct path *fwd; /* forward ptr */
+};
+#ifndef NOPUSH
+_PROTOTYP( int shxpand, (char *, char *[], int ) );
+#endif /* NOPUSH */
+_PROTOTYP( static int fgen, (char *, char *[], int ) );
+_PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
+_PROTOTYP( static VOID addresult, (char *, int) );
+#ifdef COMMENT
+/* Replaced by ckmatch() */
+_PROTOTYP( static int match, (char *, char *) );
+#endif /* COMMENT */
+_PROTOTYP( char * whoami, (void) );
+_PROTOTYP( UID_T real_uid, (void) );
+_PROTOTYP( static struct path *splitpath, (char *p) );
+_PROTOTYP( char * zdtstr, (time_t) );
+_PROTOTYP( time_t zstrdt, (char *, int) );
+
+/* Some systems define these symbols in include files, others don't... */
+
+#ifndef R_OK
+#define R_OK 4 /* For access */
+#endif /* R_OK */
+
+#ifndef W_OK
+#define W_OK 2
+#endif /* W_OK */
+
+#ifndef X_OK
+#define X_OK 1
+#endif /* X_OK */
+
+#ifndef O_RDONLY
+#define O_RDONLY 000
+#endif /* O_RDONLY */
+
+/* syslog and wtmp items for Internet Kermit Service */
+
+extern char * clienthost; /* From ckcmai.c. */
+
+static char fullname[CKMAXPATH+1];
+static char tmp2[CKMAXPATH+1];
+
+extern int ckxlogging;
+
+#ifdef CKXPRINTF /* Our printf macro conflicts with */
+#undef printf /* use of "printf" in syslog.h */
+#endif /* CKXPRINTF */
+#ifdef CKSYSLOG
+#ifdef RTAIX
+#include <sys/syslog.h>
+#else /* RTAIX */
+#include <syslog.h>
+#endif /* RTAIX */
+#endif /* CKSYSLOG */
+#ifdef CKXPRINTF
+#define printf ckxprintf
+#endif /* CKXPRINTF */
+
+int ckxanon = 1; /* Anonymous login ok */
+int ckxperms = 0040; /* Anonymous file permissions */
+int ckxpriv = 1; /* Priv'd login ok */
+
+#ifndef XFERFILE
+#define XFERFILE "/var/log/iksd.log"
+#endif /* XFERFILE */
+
+/* wtmp logging for IKSD... */
+
+#ifndef CKWTMP /* wtmp logging not selected */
+int ckxwtmp = 0; /* Know this at runtime */
+#else /* wtmp file details */
+int ckxwtmp = 1;
+#ifdef UTMPBUG /* Unfortunately... */
+/*
+ Some versions of Linux have a <utmp.h> file that contains
+ "enum utlogin { local, telnet, rlogin, screen, ... };" This clobbers
+ any program that uses any of these words as variable names, function
+ names, macro names, etc. (Other versions of Linux have this declaration
+ within #if 0 ... #endif.) There is nothing we can do about this other
+ than to not include the stupid file. But we need stuff from it, so...
+*/
+#include <features.h>
+#include <sys/types.h>
+#define UT_LINESIZE 32
+#define UT_NAMESIZE 32
+#define UT_HOSTSIZE 256
+
+struct timeval {
+ time_t tv_sec;
+ time_t tv_usec;
+};
+
+struct exit_status {
+ short int e_termination; /* Process termination status. */
+ short int e_exit; /* Process exit status. */
+};
+
+struct utmp {
+ short int ut_type; /* Type of login */
+ pid_t ut_pid; /* Pid of login process */
+ char ut_line[UT_LINESIZE]; /* NUL-terminated devicename of tty */
+ char ut_id[4]; /* Inittab id */
+ char ut_user[UT_NAMESIZE]; /* Username (not NUL terminated) */
+
+ char ut_host[UT_HOSTSIZE]; /* Hostname for remote login */
+ struct exit_status ut_exit; /* Exit status */
+ long ut_session; /* Session ID, used for windowing */
+ struct timeval ut_tv; /* Time entry was made */
+ int32_t ut_addr_v6[4]; /* Internet address of remote host */
+ char pad[20]; /* Reserved */
+};
+
+#define ut_time ut_tv.tv_sec /* Why should Linux be like anything else? */
+#define ut_name ut_user /* ... */
+
+extern void
+logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
+ __const char *__ut_host));
+
+#else /* Not UTMPBUG */
+
+#ifndef HAVEUTMPX /* Who has <utmpx.h> */
+#ifdef SOLARIS
+#define HAVEUTMPX
+#else
+#ifdef IRIX60
+#define HAVEUTMPX
+#else
+#ifdef CK_SCOV5
+#define HAVEUTMPX
+#else
+#ifdef HPUX100
+#define HAVEUTMPX
+#else
+#ifdef UNIXWARE
+#define HAVEUTMPX
+#endif /* UNIXWARE */
+#endif /* HPUX100 */
+#endif /* CK_SCOV5 */
+#endif /* IRIX60 */
+#endif /* SOLARIS */
+#endif /* HAVEUTMPX */
+#ifdef HAVEUTMPX
+#include <utmpx.h>
+#else
+#ifdef OSF50
+/* Because the time_t in the utmp struct is 64 bits but time() wants 32 */
+#define __V40_OBJ_COMPAT 1
+#endif /* OSF50 */
+#include <utmp.h>
+#ifdef OSF50
+#undef __V40_OBJ_COMPAT
+#endif /* OSF50 */
+#endif /* HAVEUTMPX */
+#endif /* UTMPBUG */
+
+#ifndef WTMPFILE
+#ifdef QNX
+#define WTMPFILE "/usr/adm/wtmp.1"
+#else
+#ifdef LINUX
+#define WTMPFILE "/var/log/wtmp"
+#else
+#define WTMPFILE "/usr/adm/wtmp"
+#endif /* QNX */
+#endif /* LINUX */
+#endif /* WTMPFILE */
+char * wtmpfile = NULL;
+
+static int wtmpfd = 0;
+static char cksysline[32] = { NUL, NUL };
+
+#ifndef HAVEUTHOST /* Does utmp include ut_host[]? */
+#ifdef HAVEUTMPX /* utmpx always does */
+#define HAVEUTHOST
+#else
+#ifdef LINUX /* Linux does */
+#define HAVEUTHOST
+#else
+#ifdef SUNOS4 /* SunOS does */
+#define HAVEUTHOST
+#else
+#ifdef AIX41 /* AIX 4.1 and later do */
+#define HAVEUTHOST
+#endif /* AIX41 */
+#endif /* SUNOS4 */
+#endif /* LINUX */
+#endif /* HAVEUTMPX */
+#endif /* HAVEUTHOST */
+
+#ifdef UW200
+PID_T _vfork() { /* To satisfy a library foulup */
+ return(fork()); /* in Unixware 2.0.x */
+}
+#endif /* UW200 */
+
+VOID
+#ifdef CK_ANSIC
+logwtmp(const char * line, const char * name, const char * host)
+#else
+logwtmp(line, name, host) char *line, *name, *host;
+#endif /* CK_ANSIC */
+/* logwtmp */ {
+#ifdef HAVEUTMPX
+ struct utmpx ut; /* Needed for ut_host[] */
+#else
+ struct utmp ut;
+#endif /* HAVEUTMPX */
+ struct stat buf;
+ /* time_t time(); */
+
+ if (!ckxwtmp)
+ return;
+
+ if (!wtmpfile)
+ makestr(&wtmpfile,WTMPFILE);
+
+ if (!line) line = "";
+ if (!name) name = "";
+ if (!host) host = "";
+
+ if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) {
+ ckxwtmp = 0;
+ debug(F110,"WTMP open failed",line,0);
+ return;
+ }
+ if (!fstat(wtmpfd, &buf)) {
+ ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
+#ifdef HAVEUTHOST
+ /* Not portable */
+ ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif /* HAVEUTHOST */
+#ifdef HAVEUTMPX
+ time(&ut.ut_tv.tv_sec);
+#else
+#ifdef LINUX
+/* In light of the following comment perhaps the previous line should */
+/* be "#ifndef COMMENT". */
+ {
+ /*
+ * On 64-bit platforms sizeof(time_t) and sizeof(ut.ut_time)
+ * are not the same and attempt to use an address of
+ * ut.ut_time as an argument to time() call may cause
+ * "unaligned access" trap.
+ */
+ time_t zz;
+ time(&zz);
+ ut.ut_time = zz;
+ }
+#else
+ time(&ut.ut_time);
+#endif /* LINUX */
+#endif /* HAVEUTMPX */
+ if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp)) {
+#ifndef NOFTRUNCATE
+#ifndef COHERENT
+ ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */
+#else
+ chsize(wtmpfd, buf.st_size); /* Error, undo any partial write */
+#endif /* COHERENT */
+#endif /* NOFTRUNCATE */
+ debug(F110,"WTMP write error",line,0);
+ } else {
+ debug(F110,"WTMP record OK",line,0);
+ return;
+ }
+ }
+}
+#endif /* CKWTMP */
+
+#ifdef CKSYSLOG
+/*
+ C K S Y S L O G -- C-Kermit system logging function,
+
+ For use by other modules.
+ This module can, but doesn't have to, use it.
+ Call with:
+ n = SYSLG_xx values defined in ckcdeb.h
+ s1, s2, s3: strings.
+*/
+VOID
+cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; {
+ int level;
+
+ if (!ckxlogging) /* syslogging */
+ return;
+ if (!s1) s1 = ""; /* Fix null args */
+ if (!s2) s2 = "";
+ if (!s3) s3 = "";
+ switch (n) { /* Translate Kermit level */
+ case SYSLG_DB: /* to syslog level */
+ level = LOG_DEBUG;
+ break;
+ default:
+ level = m ? LOG_INFO : LOG_ERR;
+ }
+ debug(F110,"cksyslog s1",s1,0);
+ debug(F110,"cksyslog s2",s2,0);
+ debug(F110,"cksyslog s3",s3,0);
+ errno = 0;
+ syslog(level, "%s: %s %s", s1, s2, s3); /* Write syslog record */
+ debug(F101,"cksyslog errno","",errno);
+}
+#endif /* CKSYSLOG */
+
+
+/* Declarations */
+
+int maxnam = MAXNAMLEN; /* Available to the outside */
+int maxpath = MAXPATH;
+int ck_znewn = -1;
+
+#ifdef UNIX
+char startupdir[MAXPATH+1];
+#endif /* UNIX */
+
+int pexitstat = -2; /* Process exit status */
+
+FILE *fp[ZNFILS] = { /* File pointers */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* Flags for each file indicating whether it was opened with popen() */
+int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* Buffers and pointers used in buffered file input and output. */
+#ifdef DYNAMIC
+extern char *zinbuffer, *zoutbuffer;
+#else
+extern char zinbuffer[], zoutbuffer[];
+#endif /* DYNAMIC */
+extern char *zinptr, *zoutptr;
+extern int zincnt, zoutcnt;
+extern int wildxpand;
+
+static long iflen = -1L; /* Input file length */
+
+static PID_T pid = 0; /* pid of child fork */
+static int fcount = 0; /* Number of files in wild group */
+static int nxpand = 0; /* Copy of fcount */
+static char nambuf[CKMAXPATH+4]; /* Buffer for a pathname */
+
+#ifndef NOFRILLS
+#define ZMBUFLEN 200
+static char zmbuf[ZMBUFLEN]; /* For mail, remote print strings */
+#endif /* NOFRILLS */
+
+char **mtchs = NULL; /* Matches found for filename */
+char **mtchptr = NULL; /* Pointer to current match */
+
+/* Z K S E L F -- Kill Self: log out own job, if possible. */
+
+/* Note, should get current pid, but if your system doesn't have */
+/* getppid(), then just kill(0,9)... */
+
+#ifndef SVR3
+#ifndef POSIX
+#ifndef OSFPC
+/* Already declared in unistd.h for SVR3 and POSIX */
+#ifdef CK_ANSIC
+extern PID_T getppid(void);
+#else
+#ifndef PS2AIX10
+#ifndef COHERENT
+extern PID_T getppid();
+#endif /* COHERENT */
+#endif /* PS2AIX10 */
+#endif /* CK_ANSIC */
+#endif /* OSFPC */
+#endif /* POSIX */
+#endif /* SVR3 */
+
+int
+zkself() { /* For "bye", but no guarantee! */
+#ifdef PROVX1
+ return(kill(0,9));
+#else
+#ifdef V7
+ return(kill(0,9));
+#else
+#ifdef TOWER1
+ return(kill(0,9));
+#else
+#ifdef FT18
+ return(kill(0,9));
+#else
+#ifdef aegis
+ return(kill(0,9));
+#else
+#ifdef COHERENT
+ return(kill((PID_T)getpid(),1));
+#else
+#ifdef PID_T
+ exit(kill((PID_T)getppid(),1));
+ return(0);
+#else
+ exit(kill(getppid(),1));
+ return(0);
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+}
+
+static VOID
+getfullname(name) char * name; {
+ char *p = (char *)fullname;
+ int len = 0;
+ fullname[0] = '\0';
+ /* If necessary we could also chase down symlinks here... */
+#ifdef COMMENT
+ /* This works but is incompatible with wuftpd */
+ if (isguest && anonroot) {
+ ckstrncpy(fullname,anonroot,CKMAXPATH);
+ len = strlen(fullname);
+ if (len > 0)
+ if (fullname[len-1] == '/')
+ len--;
+ }
+ p += len;
+#endif /* COMMENT */
+ zfnqfp(name, CKMAXPATH - len, p);
+ while (*p) {
+ if (*p < '!') *p = '_';
+ p++;
+ }
+}
+
+/* D O I K L O G -- Open Kermit-specific ftp-like transfer log. */
+
+VOID /* Called in ckcmai.c */
+doiklog() {
+ if (iklogopen) /* Already open? */
+ return;
+ if (xferlog) { /* Open iksd log if requested */
+ if (!xferfile) /* If no pathname given */
+ makestr(&xferfile,XFERFILE); /* use this default */
+ if (*xferfile) {
+ xferlog = open(xferfile, O_WRONLY | O_APPEND | O_CREAT, 0660);
+ debug(F101,"doiklog open","",xferlog);
+ if (xferlog < 0) {
+#ifdef CKSYSLOG
+ syslog(LOG_ERR, "xferlog open failure %s: %m", xferfile);
+#endif /* CKSYSLOG */
+ debug(F101,"doiklog open errno","",errno);
+ xferlog = 0;
+ } else
+ iklogopen = 1;
+ } else
+ xferlog = 0;
+#ifdef CKSYSLOG
+ if (xferlog && ckxlogging)
+ syslog(LOG_INFO, "xferlog: %s open ok", xferfile);
+#endif /* CKSYSLOG */
+ }
+}
+
+/* Z O P E N I -- Open an existing file for input. */
+
+/* Returns 1 on success, 0 on failure */
+
+int
+zopeni(n,name) int n; char *name; {
+ int x;
+
+ debug(F111,"zopeni",name,n);
+ if ((x = chkfn(n)) != 0) {
+ debug(F111,"zopeni chkfn",ckitoa(n),x);
+ return(0);
+ }
+ zincnt = 0; /* Reset input buffer */
+ if (n == ZSYSFN) { /* Input from a system function? */
+#ifdef COMMENT
+/*** Note, this function should not be called with ZSYSFN ***/
+/*** Always call zxcmd() directly, and give it the real file number ***/
+/*** you want to use. ***/
+ return(zxcmd(n,name)); /* Try to fork the command */
+#else
+ debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
+ *nambuf = '\0'; /* No filename. */
+ return(0); /* fail. */
+#endif /* COMMENT */
+ }
+ if (n == ZSTDIO) { /* Standard input? */
+ if (is_a_tty(0)) {
+ fprintf(stderr,"Terminal input not allowed");
+ debug(F110,"zopeni: attempts input from unredirected stdin","",0);
+ return(0);
+ }
+ fp[ZIFILE] = stdin;
+ ispipe[ZIFILE] = 0;
+ return(1);
+ }
+#ifdef CKROOT
+ debug(F111,"zopeni setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zopeni setroot violation",name,0);
+ return(0);
+ }
+#endif /* CKROOT */
+ fp[n] = fopen(name,"r"); /* Real file, open it. */
+ debug(F111,"zopeni fopen", name, fp[n]);
+#ifdef ZDEBUG
+ printf("ZOPENI fp[%d]=%ld\n",n,fp[n]);
+#endif /* ZDEBUG */
+ ispipe[n] = 0;
+
+ if (xferlog
+#ifdef CKSYSLOG
+ || ((ckxsyslog >= SYSLG_FA) && ckxlogging)
+#endif /* CKSYSLOG */
+ ) {
+ getfullname(name);
+ debug(F110,"zopeni fullname",fullname,0);
+ }
+ if (fp[n] == NULL) {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FA && ckxlogging) {
+ syslog(LOG_INFO, "file[%d] %s: open failed (%m)", n, fullname);
+ perror(fullname);
+ } else
+#endif /* CKSYSLOG */
+ perror(name);
+ return(0);
+ } else {
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FA && ckxlogging)
+ syslog(LOG_INFO, "file[%d] %s: open read ok", n, fullname);
+#endif /* CKSYSLOG */
+ clearerr(fp[n]);
+ return(1);
+ }
+}
+
+#ifdef QNX
+#define DONDELAY
+#else
+#ifdef O_NDELAY
+#define DONDELAY
+#endif /* O_NDELAY */
+#endif /* QNX */
+
+/* Z O P E N O -- Open a new file for output. */
+
+/*ARGSUSED*/ /* zz not used */
+int
+zopeno(n,name,zz,fcb)
+/* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; {
+
+ char p[8];
+ int append = 0;
+
+/* As of Version 5A, the attribute structure and the file information */
+/* structure are included in the arglist. */
+
+#ifdef DEBUG
+ debug(F111,"zopeno",name,n);
+ if (fcb) {
+ debug(F101,"zopeno fcb disp","",fcb->dsp);
+ debug(F101,"zopeno fcb type","",fcb->typ);
+ debug(F101,"zopeno fcb char","",fcb->cs);
+ } else {
+ debug(F100,"zopeno fcb is NULL","",0);
+ }
+#endif /* DEBUG */
+
+ if (chkfn(n) != 0) /* Already open? */
+ return(0); /* Nothing to do. */
+
+ if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
+ fp[ZOFILE] = stdout;
+ ispipe[ZOFILE] = 0;
+#ifdef COMMENT
+ /* This seems right but it breaks client server ops */
+ fp[n] = stdout;
+ ispipe[n] = 0;
+#endif /* COMMENT */
+#ifdef DEBUG
+ if (n != ZDFILE)
+ debug(F101,"zopeno fp[n]=stdout","",fp[n]);
+#endif /* DEBUG */
+ zoutcnt = 0;
+ zoutptr = zoutbuffer;
+ return(1);
+ }
+
+/* A real file. Open it in desired mode (create or append). */
+
+#ifdef CKROOT
+ debug(F111,"zopeno setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zopeno setroot violation",name,0);
+ return(0);
+ }
+#endif /* CKROOT */
+
+ ckstrncpy(p,"w",8); /* Assume write/create mode */
+ if (fcb) { /* If called with an FCB... */
+ if (fcb->dsp == XYFZ_A) { /* Does it say Append? */
+ ckstrncpy(p,"a",8); /* Yes. */
+ debug(F100,"zopeno append","",0);
+ append = 1;
+ }
+ }
+
+ if (xferlog
+#ifdef CKSYSLOG
+ || ((ckxsyslog >= SYSLG_FC) && ckxlogging)
+#endif /* CKSYSLOG */
+ ) {
+ getfullname(name);
+ debug(F110,"zopeno fullname",fullname,0);
+ }
+ debug(F110,"zopeno fopen arg",p,0);
+ fp[n] = fopen(name,p); /* Try to open the file */
+ ispipe[ZIFILE] = 0;
+
+#ifdef ZDEBUG
+ printf("ZOPENO fp[%d]=%ld\n",n,fp[n]);
+#endif /* ZDEBUG */
+
+ if (fp[n] == NULL) { /* Failed */
+ debug(F101,"zopeno failed errno","",errno);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging)
+ syslog(LOG_INFO, "file[%d] %s: %s failed (%m)",
+ n,
+ fullname,
+ append ? "append" : "create"
+ );
+#endif /* CKSYSLOG */
+#ifdef COMMENT /* Let upper levels print message. */
+ perror("Can't open output file");
+#endif /* COMMENT */
+ } else { /* Succeeded */
+ extern int zofbuffer, zofblock, zobufsize;
+ debug(F101, "zopeno zobufsize", "", zobufsize);
+ if (n == ZDFILE || n == ZTFILE) { /* If debug or transaction log */
+ setbuf(fp[n],NULL); /* make it unbuffered. */
+#ifdef DONDELAY
+ } else if (n == ZOFILE && !zofblock) { /* blocking or nonblocking */
+ int flags;
+ if ((flags = fcntl(fileno(fp[n]),F_GETFL,0)) > -1)
+ fcntl(fileno(fp[n]),F_SETFL, flags |
+#ifdef QNX
+ O_NONBLOCK
+#else
+ O_NDELAY
+#endif /* QNX */
+ );
+ debug(F100,"zopeno ZOFILE nonblocking","",0);
+#endif /* DONDELAY */
+ } else if (n == ZOFILE && !zofbuffer) { /* buffered or unbuffered */
+ setbuf(fp[n],NULL);
+ debug(F100,"zopeno ZOFILE unbuffered","",0);
+ }
+
+#ifdef CK_LOGIN
+ /* Enforce anonymous file-creation permission */
+ if (isguest)
+ if (n == ZWFILE || n == ZMFILE ||
+ n == ZOFILE || n == ZDFILE ||
+ n == ZTFILE || n == ZPFILE ||
+ n == ZSFILE)
+ chmod(name,ckxperms);
+#endif /* CK_LOGIN */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging)
+ syslog(LOG_INFO, "file[%d] %s: %s ok",
+ n,
+ fullname,
+ append ? "append" : "create"
+ );
+#endif /* CKSYSLOG */
+ debug(F100, "zopeno ok", "", 0);
+ }
+ zoutcnt = 0; /* (PWP) reset output buffer */
+ zoutptr = zoutbuffer;
+ return((fp[n] != NULL) ? 1 : 0);
+}
+
+/* Z C L O S E -- Close the given file. */
+
+/* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
+
+int
+zclose(n) int n; {
+ int x = 0, x2 = 0;
+ extern long ffc;
+
+ debug(F101,"zclose file number","",n);
+ if (chkfn(n) < 1) return(0); /* Check range of n */
+ if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
+ x2 = zoutdump();
+
+ if (fp[ZSYSFN] || ispipe[n]) { /* If file is really pipe */
+#ifndef NOPUSH
+ x = zclosf(n); /* do it specially */
+#else
+ x = EOF;
+#endif /* NOPUSH */
+ debug(F101,"zclose zclosf","",x);
+ debug(F101,"zclose zclosf fp[n]","",fp[n]);
+ } else {
+ if ((fp[n] != stdout) && (fp[n] != stdin))
+ x = fclose(fp[n]);
+ fp[n] = NULL;
+#ifdef COMMENT
+ if (n == ZCTERM || n == ZSTDIO) /* See zopeno() */
+ if (fp[ZOFILE] == stdout)
+ fp[ZOFILE] = NULL;
+#endif /* COMMENT */
+ }
+ iflen = -1L; /* Invalidate file length */
+ if (x == EOF) { /* if we got a close error */
+ debug(F101,"zclose fclose fails","",x);
+ return(-1);
+ } else if (x2 < 0) { /* or error flushing last buffer */
+ debug(F101,"zclose error flushing last buffer","",x2);
+ return(-1); /* then return an error */
+ } else {
+ /* Print log record compatible with wu-ftpd */
+ if (xferlog && (n == ZIFILE || n == ZOFILE)) {
+ char * s, *p;
+ extern char ttname[];
+ if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */
+ debug(F101,"zclose iklogopen","",iklogopen);
+ if (iklogopen) {
+ int len;
+ char * fnam;
+
+ timenow = time(NULL);
+#ifdef CK_LOGIN
+ if (logged_in)
+ s = clienthost;
+ else
+#endif /* CK_LOGIN */
+ s = (char *)ttname;
+ if (!s) s = "";
+ if (!*s) s = "*";
+#ifdef CK_LOGIN
+ if (logged_in) {
+ p = guestpass;
+ if (!*p) p = "*";
+ } else
+#endif /* CK_LOGIN */
+ p = whoami();
+
+ len = 24 + 12 + (int)strlen(s) + 16
+ + (int)strlen(fullname) + 1 + 1 + 1 + 1
+ + (int)strlen(p) + 6 + 2 + 12;
+ fnam = fullname;
+ if (!*fnam) fnam = "(pipe)";
+
+ if (len > IKSDMSGLEN)
+ sprintf(iksdmsg, /* SAFE */
+ "%.24s [BUFFER WOULD OVERFLOW]\n",ctime(&timenow));
+ else
+ sprintf(iksdmsg, /* SAFE */
+ "%.24s %d %s %ld %s %c %s %c %c %s %s %d %s\n",
+ ctime(&timenow), /* date/time */
+ gtimer(), /* elapsed secs */
+ s, /* peer name */
+ ffc, /* byte count */
+ fnam, /* full pathname of file */
+ (binary ? 'b' : 'a'), /* binary or ascii */
+ "_", /* options = none */
+ n == ZIFILE ? 'o' : 'i', /* in/out */
+#ifdef CK_LOGIN
+ (isguest ? 'a' : 'r'), /* User type */
+#else
+ 'r',
+#endif /* CK_LOGIN */
+ p, /* Username or guest passwd */
+#ifdef CK_LOGIN
+ logged_in ? "iks" : "kermit", /* Record ID */
+#else
+ "kermit",
+#endif /* CK_LOGIN */
+ 0, /* User ID on client system unknown */
+ "*" /* Ditto */
+ );
+ debug(F110,"zclose iksdmsg",iksdmsg,0);
+ write(xferlog, iksdmsg, (int)strlen(iksdmsg));
+ }
+ }
+ debug(F101,"zclose returns","",1);
+ return(1);
+ }
+}
+
+/* Z C H I N -- Get a character from the input file. */
+
+/* Returns -1 if EOF, 0 otherwise with character returned in argument */
+
+int
+zchin(n,c) int n; int *c; {
+ int a;
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+ a = coninc(0);
+ if (*c < 0)
+ return(-1);
+ } else
+#endif /* IKSD */
+ /* (PWP) Just in case this gets called when it shouldn't. */
+ if (n == ZIFILE) {
+ a = zminchar(); /* Note: this catches Ctrl-Z */
+ if (a < 0) /* (See zinfill()...) */
+ return(-1);
+ } else {
+ a = getc(fp[n]);
+ if (a == EOF) return(-1);
+#ifdef CK_CTRLZ
+ /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
+ if (!binary && a == 0x1A && eofmethod == XYEOF_Z)
+ return(-1);
+#endif /* CK_CTRLZ */
+ }
+ *c = (CHAR) a & 0377;
+ return(0);
+}
+
+/* Z S I N L -- Read a line from a file */
+
+/*
+ Writes the line into the address provided by the caller.
+ n is the Kermit "channel number".
+ Writing terminates when newline is encountered, newline is not copied.
+ Writing also terminates upon EOF or if length x is exhausted.
+ Returns 0 on success, -1 on EOF or error.
+*/
+int
+zsinl(n,s,x) int n, x; char *s; {
+ int a, z = 0; /* z is return code. */
+ int count = 0;
+ int len = 0;
+ char *buf;
+ extern CHAR feol; /* Line terminator */
+
+ if (!s || chkfn(n) < 1) /* Make sure file is open, etc */
+ return(-1);
+ buf = s;
+ s[0] = '\0'; /* Don't return junk */
+
+ a = -1; /* Current character, none yet. */
+ while (x--) { /* Up to given length */
+ int old = 0;
+ if (feol) /* Previous character */
+ old = a;
+ if (zchin(n,&a) < 0) { /* Read a character from the file */
+ debug(F101,"zsinl zchin fail","",count);
+ if (count == 0)
+ z = -1; /* EOF or other error */
+ break;
+ } else
+ count++;
+ if (feol) { /* Single-character line terminator */
+ if (a == feol)
+ break;
+ } else { /* CRLF line terminator */
+ if (a == '\015') /* CR, get next character */
+ continue;
+ if (old == '\015') { /* Previous character was CR */
+ if (a == '\012') { /* This one is LF, so we have a line */
+ break;
+ } else { /* Not LF, deposit CR */
+ *s++ = '\015';
+ x--;
+ len++;
+ }
+ }
+ }
+ *s = a; /* Deposit character */
+ s++;
+ len++;
+ }
+ *s = '\0'; /* Terminate the string */
+ debug(F011,"zsinl",buf,len);
+ return(z);
+}
+
+/* Z X I N -- Read x bytes from a file */
+
+/*
+ Reads x bytes (or less) from channel n and writes them
+ to the address provided by the caller.
+ Returns number of bytes read on success, 0 on EOF or error.
+*/
+int
+zxin(n,s,x) int n, x; char *s; {
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+ int a, i;
+ a = ttchk();
+ if (a < 1) return(0);
+ for (i = 0; i < a && i < x; i++)
+ s[i] = coninc(0);
+ return(i);
+ }
+#endif /* IKSD */
+
+ return(fread(s, sizeof (char), x, fp[n]));
+}
+
+/*
+ Z I N F I L L -- Buffered file input.
+
+ (re)fill the file input buffer with data. All file input
+ should go through this routine, usually by calling the zminchar()
+ macro defined in ckcker.h. Returns:
+
+ Value 0..255 on success, the character that was read.
+ -1 on end of file.
+ -2 on any kind of error other than end of file.
+ -3 timeout when reading from pipe (Kermit packet mode only).
+*/
+int
+zinfill() {
+ extern int kactive, srvping;
+ errno = 0;
+
+#ifdef ZDEBUG
+ printf("ZINFILL fp[%d]=%ld\n",ZIFILE,fp[ZIFILE]);
+#endif /* ZDEBUG */
+
+#ifdef IKSD
+ if (inserver && !local && fp[ZIFILE] == stdin) {
+ int a, i;
+ a = ttchk();
+ if (a < 0) return(-2);
+ for (i = 0; i < a && i < INBUFSIZE; i++) {
+ zinbuffer[i] = coninc(0);
+ }
+ zincnt = i;
+ /* set pointer to beginning, (== &zinbuffer[0]) */
+ zinptr = zinbuffer;
+ if (zincnt == 0) return(-1);
+ zincnt--; /* One less char in buffer */
+ return((int)(*zinptr++) & 0377); /* because we return the first */
+ }
+#endif /* IKSD */
+
+ debug(F101,"zinfill kactive","",kactive);
+
+ if (!(kactive && ispipe[ZIFILE])) {
+ if (feof(fp[ZIFILE])) {
+ debug(F100,"ZINFILL feof","",0);
+#ifdef ZDEBUG
+ printf("ZINFILL EOF\n");
+#endif /* ZDEBUG */
+ return(-1);
+ }
+ }
+ clearerr(fp[ZIFILE]);
+
+#ifdef SELECT
+ /* Here we can call select() to get a timeout... */
+ if (kactive && ispipe[ZIFILE]) {
+ int secs, z = 0;
+#ifndef NOXFER
+ if (srvping) {
+ secs = 1;
+ debug(F101,"zinfill calling ttwait","",secs);
+ z = ttwait(fileno(fp[ZIFILE]),secs);
+ debug(F101,"zinfill ttwait","",z);
+ }
+#endif /* NOXFER */
+ if (z == 0)
+ return(-3);
+ }
+#endif /* SELECT */
+
+#ifdef DEBUG
+ if (deblog) {
+ int i;
+ debug(F101,"ZINFILL INBUFSIZE","",INBUFSIZE);
+#ifdef USE_MEMCPY
+ memset(zinbuffer, 0xFF, INBUFSIZE);
+#else
+ for (i = 0; i < INBUFSIZE; i++) {
+ zinbuffer[i] = 0xFF;
+#ifdef COMMENT /* Too much! */
+ debug(F101,"ZINFILL zinbuffer[i]","",i);
+#endif /* COMMENT */
+ }
+#endif /* USE_MEMCPY */
+ ckstrncpy(zinbuffer,"zinbuffer is a valid buffer",INBUFSIZE);
+ debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer);
+ }
+#endif /* DEBUG */
+
+/*
+ Note: The following read MUST be nonblocking when reading from a pipe
+ and we want timeouts to work. See zxcmd().
+*/
+ zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
+ debug(F101,"ZINFILL fread","",zincnt); /* Just the size */
+#ifdef ZDEBUG
+ printf("FREAD=%d\n",zincnt);
+#endif /* ZDEBUG */
+#ifdef CK_CTRLZ
+ /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
+ if (zincnt > 0 && !binary && eofmethod == XYEOF_Z) {
+ register int i;
+ for (i = 0; i < zincnt; i++) {
+ if (zinbuffer[i] == SUB) {
+ zincnt = i; /* Stop at first Ctrl-Z */
+ if (i == 0)
+ return(-1);
+ break;
+ }
+ }
+ }
+#endif /* CK_CTRLZ */
+
+ if (zincnt == 0) { /* Got nothing? */
+ if (ferror(fp[ZIFILE])) {
+ debug(F100,"ZINFILL ferror","",0);
+ debug(F101,"ZINFILL errno","",errno);
+#ifdef ZDEBUG
+ printf("ZINFILL errno=%d\n",errno);
+#endif /* ZDEBUG */
+#ifdef EWOULDBLOCK
+ return((errno == EWOULDBLOCK) ? -3 : -2);
+#else
+ return(-2);
+#endif /* EWOULDBLOCK */
+ }
+
+ /* In case feof() didn't work just above -- sometimes it doesn't... */
+
+ if (feof(fp[ZIFILE]) ) {
+ debug(F100,"ZINFILL count 0 EOF return -1","",0);
+ return (-1);
+ } else {
+ debug(F100,"ZINFILL count 0 not EOF return -2","",0);
+ return(-2);
+ }
+ }
+ zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
+ zincnt--; /* One less char in buffer */
+ return((int)(*zinptr++) & 0377); /* because we return the first */
+}
+
+/* Z S O U T -- Write a string out to the given file, buffered. */
+
+int
+zsout(n,s) int n; char *s; {
+ int rc = 0;
+ rc = chkfn(n);
+ if (rc < 1) return(-1); /* Keep this, prevents memory faults */
+ if (!s) return(0); /* Null pointer, do nothing, succeed */
+ if (!*s) return(0); /* empty string, ditto */
+
+#ifdef IKSD
+ /*
+ This happens with client-side Kermit server when a REMOTE command
+ was sent from the server to the client and the server is supposed to
+ display the text, but of course there is no place to display it
+ since it is in remote mode executing Kermit protocol.
+ */
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttol(s,((int)strlen(s)) < 0) ? -1 : 0);
+#else
+ return(0);
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if (n == ZSFILE)
+ return(write(fileno(fp[n]),s,(int)strlen(s)));
+ rc = fputs(s,fp[n]) == EOF ? -1 : 0;
+ if (n == ZWFILE)
+ fflush(fp[n]);
+ return(rc);
+}
+
+/* Z S O U T L -- Write string to file, with line terminator, buffered */
+
+int
+zsoutl(n,s) int n; char *s; {
+ if (zsout(n,s) < 0)
+ return(-1);
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttoc(LF));
+#else
+ return(0); /* See comments in zsout() */
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if (n == ZSFILE) /* Session log is unbuffered */
+ return(write(fileno(fp[n]),"\n",1));
+ else if (fputs("\n",fp[n]) == EOF)
+ return(-1);
+ if (n == ZDIFIL || n == ZWFILE) /* Flush connection log records */
+ fflush(fp[n]);
+ return(0);
+}
+
+/* Z S O U T X -- Write x characters to file, unbuffered. */
+
+int
+zsoutx(n,s,x) int n, x; char *s; {
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttol(s,x)); /* See comments in zsout() */
+#else
+ return(x);
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+#ifdef COMMENT
+ if (chkfn(n) < 1) return(-1);
+ return(write(fp[n]->_file,s,x));
+#endif /* COMMENT */
+ return(write(fileno(fp[n]),s,x) == x ? x : -1);
+}
+
+/* Z C H O U T -- Add a character to the given file. */
+
+/* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
+
+int
+#ifdef CK_ANSIC
+zchout(register int n, char c)
+#else
+zchout(n,c) register int n; char c;
+#endif /* CK_ANSIC */
+/* zchout() */ {
+ /* if (chkfn(n) < 1) return(-1); */
+
+#ifdef IKSD
+ if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
+#ifdef COMMENT
+ return(ttoc(c));
+#else
+ return(0); /* See comments in zsout() */
+#endif /* COMMENT */
+ }
+#endif /* IKSD */
+
+ if (n == ZSFILE) /* Use unbuffered for session log */
+ return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
+ /* Buffered for everything else */
+ if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
+ return(ferror(fp[n])?-1:0); /* Check to make sure */
+ else /* Otherwise... */
+ return(0); /* There was no error. */
+}
+
+/* (PWP) buffered character output routine to speed up file IO */
+
+int
+zoutdump() {
+ int x;
+ char * zp;
+ zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
+#ifdef DEBUG
+ if (deblog)
+ debug(F101,"zoutdump zoutcnt","",zoutcnt);
+#endif /* DEBUG */
+ if (zoutcnt == 0) { /* Nothing to output */
+ return(0);
+ } else if (zoutcnt < 0) { /* Unexpected negative argument */
+ zoutcnt = 0; /* Reset output buffer count */
+ return(-1); /* and fail. */
+ }
+
+#ifdef IKSD
+ if (inserver && !local && fp[ZOFILE] == stdout) {
+#ifdef COMMENT
+ x = ttol(zoutbuffer,zoutcnt);
+#else
+ x = 1; /* See comments in zsout() */
+#endif /* COMMENT */
+ zoutcnt = 0;
+ return(x > 0 ? 0 : -1);
+ }
+#endif /* IKSD */
+
+/*
+ Frank Prindle suggested that replacing this fwrite() by an fflush()
+ followed by a write() would improve the efficiency, especially when
+ writing to stdout. Subsequent tests showed a 5-fold improvement.
+*/
+#ifdef COMMENT
+ if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) ...
+#endif /* COMMENT */
+
+#ifndef CK_NONBLOCK
+ fflush(fp[ZOFILE]);
+#endif /* CK_NONBLOCK */
+ zp = zoutbuffer;
+ while (zoutcnt > 0) {
+ if ((x = write(fileno(fp[ZOFILE]),zp,zoutcnt)) > -1) {
+#ifdef DEBUG
+ if (deblog) /* Save a function call... */
+ debug(F101,"zoutdump wrote","",x);
+#endif /* DEBUG */
+ zoutcnt -= x; /* Adjust output buffer count */
+ zp += x; /* and pointer */
+ } else {
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"zoutdump write error","",errno);
+ debug(F101,"zoutdump write returns","",x);
+ }
+#endif /* DEBUG */
+ zoutcnt = 0; /* Reset output buffer count */
+ return(-1); /* write() failed */
+ }
+ }
+ return(0);
+}
+
+/* C H K F N -- Internal function to verify file number is ok */
+
+/*
+ Returns:
+ -1: File number n is out of range
+ 0: n is in range, but file is not open
+ 1: n in range and file is open
+*/
+int
+chkfn(n) int n; {
+ /* if (n != ZDFILE) debug(F101,"chkfn","",n); */
+ if (n < 0 || n >= ZNFILS) {
+ if (n != ZDFILE) debug(F101,"chkfn out of range","",n);
+ return(-1);
+ } else {
+ /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */
+ return((fp[n] == NULL) ? 0 : 1);
+ }
+}
+
+/* Z G E T F S -- Return file size regardless of accessibility */
+/*
+ Used for directory listings, etc.
+ Returns:
+ The size of the file in bytes, 0 or greater, if the size can be learned.
+ -1 if the file size can not be obtained.
+ Also (and this is a hack just for UNIX):
+ If the argument is the name of a symbolic link,
+ the global variable issymlink is set to 1,
+ and the global buffer linkname[] gets the link value.
+ And it sets zgfs_dir to 1 if it's a directory, otherwise 0.
+ This lets us avoid numerous redundant calls to stat().
+*/
+int zgfs_link = 0;
+int zgfs_dir = 0;
+time_t zgfs_mtime = 0;
+unsigned int zgfs_mode = 0;
+
+#ifdef CKSYMLINK
+char linkname[CKMAXPATH+1];
+#ifndef _IFLNK
+#define _IFLNK 0120000
+#endif /* _IFLNK */
+#endif /* CKSYMLINK */
+
+long
+zgetfs(name) char *name; {
+ struct stat buf;
+ char fnam[CKMAXPATH+4];
+ long size = -1L;
+ int x;
+ int needrlink = 0;
+ char * s;
+
+ if (!name) name = "";
+ if (!*name) return(-1);
+
+#ifdef UNIX
+ x = strlen(name);
+ if (x == 9 && !strcmp(name,"/dev/null"))
+ return(0);
+#endif /* UNIX */
+
+ s = name;
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ }
+#endif /* DTILDE */
+ x = ckstrncpy(fnam,s,CKMAXPATH);
+ s = fnam;
+ debug(F111,"zgetfs fnam",s,x);
+ if (x > 0 && s[x-1] == '/')
+ s[x-1] = '\0';
+
+ zgfs_dir = 0; /* Assume it's not a directory */
+ zgfs_link = 0; /* Assume it's not a symlink */
+ zgfs_mtime = 0; /* No time yet */
+ zgfs_mode = 0; /* No permission bits yet */
+
+#ifdef CKSYMLINK /* We're doing symlinks? */
+#ifdef USE_LSTAT /* OK to use lstat()? */
+ x = lstat(s,&buf);
+ debug(F101,"STAT","",1);
+ if (x < 0) /* stat() failed */
+ return(-1);
+ if ( /* Now see if it's a symlink */
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ ) {
+ zgfs_link = 1; /* It's a symlink */
+ linkname[0] = '\0'; /* Get the name */
+ x = readlink(s,linkname,CKMAXPATH);
+ debug(F101,"zgetfs readlink",s,x);
+ if (x > -1 && x < CKMAXPATH) { /* It's a link */
+ linkname[x] = '\0';
+ size = buf.st_size; /* Remember size of link */
+ x = stat(s,&buf); /* Now stat the linked-to file */
+ debug(F101,"STAT","",2);
+ if (x < 0) /* so we can see if it's a directory */
+ return(-1);
+ } else {
+ ckstrncpy(linkname,"(lookup failed)",CKMAXPATH);
+ }
+ }
+#else /* !USE_LSTAT */
+ x = stat(s,&buf); /* No lstat(), use stat() instead */
+ debug(F101,"STAT","",3);
+ if (x < 0)
+ return(-1);
+#endif /* USE_LSTAT */
+
+ /* Do we need to call readlink()? */
+
+#ifdef NOLINKBITS
+/*
+ lstat() does not work in SCO operating systems. From "man NS lstat":
+
+ lstat obtains information about the file named by path. In the case of a
+ symbolic link, lstat returns information about the link, and not the file
+ named by the link. It is only used by the NFS automount daemon and should
+ not be utilized by users.
+*/
+ needrlink = 1;
+ debug(F101,"zgetfs forced needrlink","",needrlink);
+#else
+#ifdef S_ISLNK
+ needrlink = S_ISLNK(buf.st_mode);
+ debug(F101,"zgetfs S_ISLNK needrlink","",needrlink);
+#else
+#ifdef _IFLNK
+ needrlink = (_IFMT & buf.st_mode) == _IFLNK;
+ debug(F101,"zgetfs _IFLNK needrlink","",needrlink);
+#else
+ needrlink = 1;
+ debug(F101,"zgetfs default needrlink","",needrlink);
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+#endif /* NOLINKBITS */
+
+ if (needrlink) {
+ linkname[0] = '\0';
+ errno = 0;
+ x = readlink(s,linkname,CKMAXPATH);
+#ifdef DEBUG
+ debug(F111,"zgetfs readlink",s,x);
+ if (x < 0)
+ debug(F101,"zgetfs readlink errno","",errno);
+ else
+ debug(F110,"zgetfs readlink result",linkname,0);
+#endif /* DEBUG */
+ if (x > -1 && x < CKMAXPATH) {
+ zgfs_link = 1;
+ linkname[x] = '\0';
+ }
+ }
+#else /* !CKSYMLINK */
+ x = stat(s,&buf); /* Just stat the file */
+ debug(F111,"zgetfs stat",s,x);
+ if (x < 0) /* and get the size */
+ return(-1);
+#endif /* CKSYMLINK */
+
+ zgfs_mtime = buf.st_mtime;
+ zgfs_mode = buf.st_mode;
+ zgfs_dir = (S_ISDIR(buf.st_mode)) ? 1 : 0; /* Set "is directory" flag */
+ debug(F111,"zgetfs size",s,size);
+ debug(F111,"zgetfs st_size",s,buf.st_size);
+ return((size < 0L) ? buf.st_size : size); /* Return the size */
+}
+
+
+/* Z C H K I -- Check if input file exists and is readable */
+
+/*
+ Returns:
+ >= 0 if the file can be read (returns the size).
+ -1 if file doesn't exist or can't be accessed,
+ -2 if file exists but is not readable (e.g. a directory file).
+ -3 if file exists but protected against read access.
+
+ For Berkeley Unix, a file must be of type "regular" to be readable.
+ Directory files, special files, and symbolic links are not readable.
+*/
+long
+zchki(name) char *name; {
+ struct stat buf;
+ char * s;
+ int x, itsadir = 0;
+ extern int zchkid, diractive, matchfifo;
+
+ if (!name)
+ return(-1);
+ x = strlen(name);
+ if (x < 1)
+ return(-1);
+ s = name;
+
+#ifdef UNIX
+ if (x == 9 && !strcmp(s,"/dev/null"))
+ return(0);
+ if (x == 8 && !strcmp(s,"/dev/tty"))
+ return(0);
+#endif /* UNIX */
+
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ }
+#endif /* DTILDE */
+
+#ifdef CKROOT
+ debug(F111,"zchki setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zchki setroot violation",name,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = stat(s,&buf);
+ debug(F101,"STAT","",5);
+ if (x < 0) {
+ debug(F111,"zchki stat fails",s,errno);
+ return(-1);
+ }
+ if (S_ISDIR (buf.st_mode))
+ itsadir = 1;
+
+ if (!(itsadir && zchkid)) { /* Unless this... */
+ if (!S_ISREG (buf.st_mode) /* Must be regular file */
+#ifdef S_ISFIFO
+ && (!matchfifo || !S_ISFIFO (buf.st_mode)) /* or FIFO */
+#endif /* S_ISFIFO */
+ ) {
+ debug(F111,"zchki not regular file (or fifo)",s,matchfifo);
+ return(-2);
+ }
+ }
+ debug(F111,"zchki stat ok:",s,x);
+
+ if (diractive) { /* If listing don't check access */
+ x = 1;
+ } else {
+#ifdef SW_ACC_ID
+ debug(F100,"zchki swapping ids for access()","",0);
+ priv_on();
+#endif /* SW_ACC_ID */
+ if ((x = access(s,R_OK)) < 0)
+ x = access(s,X_OK); /* For RUN-class commands */
+#ifdef SW_ACC_ID
+ priv_off();
+ debug(F100,"zchki swapped ids restored","",0);
+#endif /* SW_ACC_ID */
+ }
+ if (x < 0) { /* Is the file accessible? */
+ debug(F111,"zchki access failed:",s,x); /* No */
+ return(-3);
+ } else {
+ iflen = buf.st_size; /* Yes, remember size */
+ ckstrncpy(nambuf,s,CKMAXPATH); /* and name globally. */
+ debug(F111,"zchki access ok:",s,iflen);
+ return((iflen > -1L) ? iflen : 0L);
+ }
+}
+
+/* Z C H K O -- Check if output file can be created */
+
+/*
+ Returns -1 if write permission for the file would be denied, 0 otherwise.
+
+ NOTE: The design is flawed. There is no distinction among:
+ . Can I overwrite an existing file?
+ . Can I create a file (or directory) in an existing directory?
+ . Can I create a file (or directory) and its parent(s)?
+*/
+int
+zchko(name) char *name; {
+ int i, x, itsadir = 0;
+ char *s;
+ char * oname;
+ extern int zchkod; /* Used by IF WRITEABLE */
+
+ debug(F110,"zchko entry",name,0);
+
+ if (!name) return(-1); /* Watch out for null pointer. */
+
+ oname = name;
+
+#ifdef CKROOT
+ debug(F111,"zchko setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zchko setroot violation",name,0);
+ errno = EACCES;
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = (int)strlen(name); /* Get length of filename */
+ debug(F111,"zchko len",name,x);
+ debug(F111,"zchko zchkod",name,zchkod);
+
+#ifdef UNIX
+/*
+ Writing to null device is OK.
+*/
+ if (x == 9 && !strcmp(name,"/dev/null"))
+ return(0);
+ if (x == 8 && !strcmp(name,"/dev/tty"))
+ return(0);
+#endif /* UNIX */
+
+ s = name;
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ x = strlen(s);
+ }
+#endif /* DTILDE */
+ name = s;
+ s = NULL;
+/*
+ zchkod is a global flag meaning we're checking not to see if the directory
+ file is writeable, but if it's OK to create files IN the directory.
+*/
+ if (!zchkod && isdir(name)) /* Directories are not writeable */
+ return(-1);
+
+ s = malloc(x+3); /* Must copy because we can't */
+ if (!s) { /* write into our argument. */
+ fprintf(stderr,"zchko: Malloc error 46\n");
+ return(-1);
+ }
+ ckstrncpy(s,name,x+3);
+
+ for (i = x; i > 0; i--) { /* Strip filename from right. */
+ if (ISDIRSEP(s[i-1])) {
+ itsadir = 1;
+ break;
+ }
+ }
+ debug(F101,"zchko i","",i);
+ debug(F101,"zchko itsadir","",itsadir);
+
+#ifdef COMMENT
+/* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */
+ if (i == 0) /* If no path, use current directory */
+ strcpy(s,"./");
+ else /* Otherwise, use given one. */
+ s[i] = '\0';
+#else
+#ifdef COMMENT
+/*
+ The following does not work for "foo/bar" where the foo directory does
+ not exist even though we could create it: access("foo/.") fails, but
+ access("foo") works OK.
+*/
+/* So now we use "path/." if path given, or "." if no path given. */
+ s[i++] = '.'; /* Append "." to path. */
+ s[i] = '\0';
+#else
+/* So NOW we strip path segments from the right as long as they don't */
+/* exist -- we only call access() for path segments that *do* exist.. */
+/* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */
+/* succeeds when I have write access to foo and bar but baz doesn't exit.) */
+
+ if (itsadir && i > 0) {
+ s[i-1] = '\0';
+ while (s[0] && !isdir(s)) {
+ for (i = (int)strlen(s); i > 0; i--) {
+ if (ISDIRSEP(s[i-1])) {
+ s[i-1] = '\0';
+ break;
+ }
+ }
+ if (i == 0)
+ s[0] = '\0';
+ }
+ } else {
+ s[i++] = '.'; /* Append "." to path. */
+ s[i] = '\0';
+ }
+#endif /* COMMENT */
+#endif /* COMMENT */
+
+ if (!s[0])
+ ckstrncpy(s,".",x+3);
+
+#ifdef SW_ACC_ID
+ debug(F100,"zchko swapping ids for access()","",0);
+ priv_on();
+#endif /* SW_ACC_ID */
+
+ x = access(s,W_OK); /* Check access of path. */
+
+#ifdef SW_ACC_ID
+ priv_off();
+ debug(F100,"zchko swapped ids restored","",0);
+#endif /* SW_ACC_ID */
+
+ if (x < 0)
+ debug(F111,"zchko access failed:",s,errno);
+ else
+ debug(F111,"zchko access ok:",s,x);
+ free(s); /* Free temporary storage */
+
+ return((x < 0) ? -1 : 0); /* and return. */
+}
+
+/* Z D E L E T -- Delete the named file. */
+
+/* Returns: -1 on error, 0 on success */
+
+int
+zdelet(name) char *name; {
+ int x;
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-1);
+#endif /* CK_LOGIN */
+
+#ifdef CKROOT
+ debug(F111,"zdelet setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zdelet setroot violation",name,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = unlink(name);
+ debug(F111,"zdelet",name,x);
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging) {
+ fullname[0] = '\0';
+ zfnqfp(name,CKMAXPATH,fullname);
+ debug(F110,"zdelet fullname",fullname,0);
+ if (x < 0)
+ syslog(LOG_INFO, "file[] %s: delete failed (%m)", fullname);
+ else
+ syslog(LOG_INFO, "file[] %s: delete ok", fullname);
+ }
+#endif /* CKSYSLOG */
+ return(x);
+}
+
+/* Z R T O L -- Convert remote filename into local form */
+
+VOID
+zrtol(name,name2) char *name, *name2; {
+ nzrtol(name,name2,1,0,CKMAXPATH);
+}
+
+VOID
+nzrtol(name,name2,fncnv,fnrpath,max)
+ char *name, *name2; int fncnv, fnrpath, max;
+{ /* nzrtol */
+ char *s, *p;
+ int flag = 0, n = 0;
+ char fullname[CKMAXPATH+1];
+ int devnull = 0;
+ int acase = 0;
+ if (!name2) return;
+ if (!name) name = "";
+
+ debug(F111,"nzrtol name",name,fncnv);
+
+#ifdef DTILDE
+ s = name;
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (*s) name = s;
+ }
+#endif /* DTILDE */
+
+ /* Handle the path -- we don't have to convert its format, since */
+ /* the standard path format and our (UNIX) format are the same. */
+
+ fullname[0] = NUL;
+ devnull = !strcmp(name,"/dev/null");
+
+ if (!devnull && fnrpath == PATH_OFF) { /* RECEIVE PATHNAMES OFF */
+ zstrip(name,&p);
+ strncpy(fullname,p,CKMAXPATH);
+ } else if (!devnull && fnrpath == PATH_ABS) { /* REC PATHNAMES ABSOLUTE */
+ strncpy(fullname,name,CKMAXPATH);
+ } else if (!devnull && isabsolute(name)) { /* RECEIVE PATHNAMES RELATIVE */
+ ckmakmsg(fullname,CKMAXPATH,".",name,NULL,NULL);
+ } else { /* Ditto */
+ ckstrncpy(fullname,name,CKMAXPATH);
+ }
+ fullname[CKMAXPATH] = NUL;
+ debug(F110,"nzrtol fullname",fullname,0);
+
+#ifndef NOTRUNCATE
+/*
+ The maximum length for any segment of a filename is MAXNAMLEN, defined
+ above. On some platforms (at least QNX) if a segment exceeds this limit,
+ the open fails with ENAMETOOLONG, so we must prevent it by truncating each
+ overlong name segment to the maximum segment length before passing the
+ name to open(). This must be done even when file names are literal, so as
+ not to halt a file transfer unnecessarily.
+*/
+ {
+ char buf[CKMAXPATH+1]; /* New temporary buffer on stack */
+ char *p = fullname; /* Source and */
+ char *s = buf; /* destination pointers */
+ int i = 0, n = 0;
+ debug(F101,"nzrtol sizing MAXNAMLEN","",MAXNAMLEN);
+ while (*p && n < CKMAXPATH) { /* Copy name to new buffer */
+ if (++i > MAXNAMLEN) { /* If this segment too long */
+ while (*p && *p != '/') /* skip past the rest... */
+ p++;
+ i = 0; /* and reset counter. */
+ } else if (*p == '/') { /* End of this segment. */
+ i = 0; /* Reset counter. */
+ }
+ *s++ = *p++; /* Copy this character. */
+ n++;
+ }
+ *s = NUL;
+ ckstrncpy(fullname,buf,CKMAXPATH); /* Copy back to original buffer. */
+ debug(F111,"nzrtol sizing",fullname,n);
+ }
+#endif /* NOTRUNCATE */
+
+ if (!fncnv || devnull) { /* Not converting */
+ ckstrncpy(name2,fullname,max); /* We're done. */
+ return;
+ }
+ name = fullname; /* Converting */
+
+ p = name2;
+ for (; *name != '\0' && n < maxnam; name++) {
+ if (*name > SP) flag = 1; /* Strip leading blanks and controls */
+ if (flag == 0 && *name < '!')
+ continue;
+ if (fncnv > 0) {
+ if (*name == SP) {
+ *p++ = '_';
+ n++;
+ continue;
+ }
+ if (isupper(*name)) /* Check for mixed case */
+ acase |= 1;
+ else if (islower(*name))
+ acase |= 2;
+ }
+ *p++ = *name;
+ n++;
+ }
+ *p-- = '\0'; /* Terminate */
+ while (*p < '!' && p > name2) /* Strip trailing blanks & controls */
+ *p-- = '\0';
+
+ if (*name2 == '\0') { /* Nothing left? */
+ ckstrncpy(name2,"NONAME",max); /* do this... */
+ } else if (acase == 1) { /* All uppercase? */
+ p = name2; /* So convert all letters to lower */
+ while (*p) {
+ if (isupper(*p))
+ *p = tolower(*p);
+ p++;
+ }
+ }
+ debug(F110,"nzrtol new name",name2,0);
+}
+
+
+/* Z S T R I P -- Strip device & directory name from file specification */
+
+/* Strip pathname from filename "name", return pointer to result in name2 */
+
+static char work[CKMAXPATH+1];
+
+VOID
+zstrip(name,name2) char *name, **name2; {
+ char *cp, *pp;
+ int n = 0;
+
+ debug(F110,"zstrip before",name,0);
+ if (!name) { *name2 = ""; return; }
+ pp = work;
+#ifdef DTILDE
+ /* Strip leading tilde */
+ if (*name == '~') name++;
+ debug(F110,"zstrip after tilde-stripping",name,0);
+#endif /* DTILDE */
+ for (cp = name; *cp; cp++) {
+ if (ISDIRSEP(*cp)) {
+ pp = work;
+ n = 0;
+ } else {
+ *pp++ = *cp;
+ if (n++ >= CKMAXPATH)
+ break;
+ }
+ }
+ *pp = '\0'; /* Terminate the string */
+ *name2 = work;
+ debug(F110,"zstrip after",*name2,0);
+}
+
+/* Z L T O R -- Local TO Remote */
+
+VOID
+zltor(name,name2) char *name, *name2; {
+ nzltor(name,name2,1,0,CKMAXPATH);
+}
+
+/* N Z L T O R -- New Local TO Remote */
+
+/*
+ fncnv = 0 for no conversion, > 0 for regular conversion, < 0 for minimal.
+*/
+VOID
+nzltor(name,name2,fncnv,fnspath,max)
+ char *name, *name2; int fncnv, fnspath, max;
+{ /* nzltor */
+ char *cp, *pp;
+#ifdef COMMENT
+ int dc = 0;
+#endif /* COMMENT */
+ int n = 0;
+ char *dotp = NULL;
+ char *dirp = NULL;
+ char fullname[CKMAXPATH+1];
+ char *p;
+ CHAR c;
+
+#ifndef NOCSETS
+ extern int fcharset, /* tcharset, */ language;
+ int langsv;
+ _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
+#ifdef CK_ANSIC
+ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
+#else
+ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
+#endif /* CK_ANSIC */
+ langsv = language;
+ language = L_USASCII;
+#ifdef COMMENT
+ /* Proper translation of filenames must be done elsewhere */
+ n = tcharset ? tcharset : TC_USASCII;
+ sxo = xls[n][fcharset];
+#else
+ sxo = xls[TC_USASCII][fcharset];
+#endif /* COMMENT */
+#endif /* NOCSETS */
+
+ debug(F110,"nzltor name",name,0);
+
+ /* Handle pathname */
+
+ fullname[0] = NUL;
+ if (fnspath == PATH_OFF) { /* PATHNAMES OFF */
+ zstrip(name,&p);
+ ckstrncpy(fullname,p,CKMAXPATH);
+ } else { /* PATHNAMES RELATIVE or ABSOLUTE */
+ char * p = name;
+ while (1) {
+ if (!strncmp(p,"../",3))
+ p += 3;
+ else if (!strncmp(p,"./",2))
+ p += 2;
+ else
+ break;
+ }
+ if (fnspath == PATH_ABS) { /* ABSOLUTE */
+ zfnqfp(p,CKMAXPATH,fullname);
+ } else { /* RELATIVE */
+ ckstrncpy(fullname,p,CKMAXPATH);
+ }
+ }
+ debug(F110,"nzltor fullname",fullname,0);
+
+ if (!fncnv) { /* Not converting */
+ ckstrncpy(name2,fullname,max); /* We're done. */
+#ifndef NOCSETS
+ langsv = language;
+#endif /* NOCSETS */
+ return;
+ }
+ name = fullname; /* Converting */
+
+#ifdef aegis
+ char *namechars;
+ int tilde = 0, bslash = 0;
+
+ if ((namechars = getenv("NAMECHARS")) != NULL) {
+ if (ckstrchr(namechars, '~' ) != NULL) tilde = '~';
+ if (ckstrchr(namechars, '\\') != NULL) bslash = '\\';
+ } else {
+ tilde = '~';
+ bslash = '\\';
+ }
+#endif /* aegis */
+
+ pp = work; /* Output buffer */
+ for (cp = name, n = 0; *cp && n < max; cp++,n++) { /* Convert name chars */
+ c = *cp;
+#ifndef NOCSETS
+ if (sxo) c = (*sxo)(c); /* Convert to ASCII */
+#endif /* NOCSETS */
+ if (fncnv > 0 && islower(c)) /* Uppercase letters */
+ *pp++ = toupper(c); /* Change tilde to hyphen */
+ else if (c == '~')
+ *pp++ = '-';
+ else if (fncnv > 0 && c == '#') /* Change number sign to 'X' */
+ *pp++ = 'X';
+ else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */
+ *pp++ = 'X';
+ else if (c == ' ') /* Change space to underscore */
+ *pp++ = '_';
+ else if (c < ' ') /* Change controls to 'X' */
+ *pp++ = 'X';
+ else if (fncnv > 0 && c == '.') { /* Change dot to underscore */
+ dotp = pp; /* Remember where we last did this */
+ *pp++ = '_';
+ } else {
+ if (c == '/')
+ dirp = pp;
+ *pp++ = c;
+ }
+ }
+ *pp = NUL; /* Tie it off. */
+#ifdef COMMENT
+ if (dotp) *dotp = '.'; /* Restore last dot (if any) */
+#else
+ if (dotp > dirp) *dotp = '.'; /* Restore last dot in file name */
+#endif /* COMMENT */
+ cp = name2; /* If nothing before dot, */
+ if (*work == '.') *cp++ = 'X'; /* insert 'X' */
+ ckstrncpy(cp,work,max);
+#ifndef NOCSETS
+ language = langsv;
+#endif /* NOCSETS */
+ debug(F110,"nzltor name2",name2,0);
+}
+
+
+/* Z C H D I R -- Change directory */
+/*
+ Call with:
+ dirnam = pointer to name of directory to change to,
+ which may be "" or NULL to indicate user's home directory.
+ Returns:
+ 0 on failure
+ 1 on success
+*/
+int
+zchdir(dirnam) char *dirnam; {
+ char *hd, *sp;
+#ifdef IKSDB
+ _PROTOTYP (int slotdir,(char *,char *));
+#endif /* IKSDB */
+#ifndef NOSPL
+ extern struct mtab *mactab; /* Main macro table */
+ extern int nmac; /* Number of macros */
+#endif /* NOSPL */
+
+ debug(F110,"zchdir",dirnam,0);
+ if (!dirnam) dirnam = "";
+ if (!*dirnam) /* If argument is null or empty, */
+ dirnam = zhome(); /* use user's home directory. */
+ sp = dirnam;
+ debug(F110,"zchdir 2",dirnam,0);
+
+#ifdef DTILDE
+ hd = tilde_expand(dirnam); /* Attempt to expand tilde */
+ if (!hd) hd = "";
+ if (*hd == '\0') hd = dirnam; /* in directory name. */
+#else
+ hd = dirnam;
+#endif /* DTILDE */
+ debug(F110,"zchdir 3",hd,0);
+
+#ifdef CKROOT
+ debug(F111,"zchdir setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(hd)) {
+ debug(F110,"zchdir setroot violation",hd,0);
+ return(0);
+ }
+#endif /* CKROOT */
+
+#ifdef pdp11
+ /* Just to save some space */
+ return((chdir(hd) == 0) ? 1 : 0);
+#else
+ if (chdir(hd) == 0) { /* Try to cd */
+#ifdef IKSDB
+#ifdef CK_LOGIN
+ if (inserver && ikdbopen)
+ slotdir(isguest ? anonroot : "", zgtdir());
+#endif /* CK_LOGIN */
+#endif /* IKSDB */
+
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ static int on_cd = 0;
+ if (!on_cd) {
+ on_cd = 1;
+ k = mlook(mactab,"on_cd",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,zgtdir(),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ on_cd = 0;
+ }
+ }
+#endif /* NOSPL */
+ return(1);
+ }
+ return(0);
+#endif /* pdp11 */
+}
+
+int
+#ifdef CK_ANSIC
+zchkpid(unsigned long xpid)
+#else
+zchkpid(xpid) unsigned long xpid;
+#endif /* CK_ANSIC */
+{
+ return((kill((PID_T)xpid,0) < 0) ? 0 : 1);
+}
+
+
+/* Z H O M E -- Return pointer to user's home directory */
+
+static char * zhomdir = NULL;
+
+char *
+zhome() {
+ char * home;
+
+#ifdef CKROOT
+ if (ckrootset)
+ return((char *)ckroot);
+#endif /* CKROOT */
+
+#ifdef Plan9
+ home = getenv("home");
+#else
+ home = getenv("HOME");
+#endif /* Plan9 */
+ makestr(&zhomdir,home);
+ return(home ? zhomdir : ".");
+}
+
+/* Z G T D I R -- Returns a pointer to the current directory */
+
+/*
+ The "preferred" interface for getting the current directory in modern UNIX
+ is getcwd() [POSIX 1003.1 5.2.2]. However, on certain platforms (such as
+ SunOS), it is implemented by forking a shell, feeding it the pwd command,
+ and returning the result, which is not only inefficient but also can result
+ in stray messages to the terminal. In such cases -- as well as when
+ getcwd() is not available at all -- getwd() can be used instead by defining
+ USE_GETWD. However, note that getwd() provides no buffer-length argument
+ and therefore no safeguard against memory leaks.
+*/
+#ifndef USE_GETWD
+#ifdef BSD42
+#define USE_GETWD
+#else
+#ifdef SUNOS4
+#define USE_GETWD
+#endif /* SUNOS4 */
+#endif /* BSD42 */
+#endif /* USE_GETWD */
+
+#ifdef pdp11
+#define CWDBL 80 /* Save every byte we can... */
+#else
+#define CWDBL CKMAXPATH
+#endif /* pdp11 */
+static char cwdbuf[CWDBL+2];
+/*
+ NOTE: The getcwd() prototypes are commented out on purpose. If you get
+ compile-time warnings, search through your system's header files to see
+ which one has the needed prototype, and #include it. Usually it is
+ <unistd.h>. See the section for including <unistd.h> in ckcdeb.h and
+ make any needed adjustments there (and report them).
+*/
+char *
+zgtdir() {
+ char * buf = cwdbuf;
+ char * s;
+
+#ifdef USE_GETWD
+ extern char *getwd();
+ s = getwd(buf);
+ debug(F110,"zgtdir BSD4 getwd()",s,0);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef BSD44
+#ifdef DCLGETCWD
+_PROTOTYP( char * getcwd, (char *, SIZE_T) );
+#endif /* DCLGETCWD */
+ debug(F101,"zgtdir BSD44 CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef MINIX2
+#ifdef DCLGETCWD
+ _PROTOTYP( char * getcwd, (char *, SIZE_T) );
+#endif /* DCLGETCWD */
+ debug(F101,"zgtdir MINIX2 CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef SVORPOSIX
+#ifdef COMMENT
+/* This non-ANSI prototype can be fatal at runtime! (e.g. in SCO3.2v5.0.5). */
+/* Anyway it's already prototyped in some header file that we have included. */
+ extern char *getcwd();
+#else
+#ifdef DCLGETCWD
+ _PROTOTYP( char * getcwd, (char *, SIZE_T) );
+#endif /* DCLGETCWD */
+#endif /* COMMENT */
+ debug(F101,"zgtdir SVORPOSIX CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+#ifdef COHERENT
+#ifdef _I386
+#ifdef DCLGETCWD
+ extern char *getcwd();
+#endif /* DCLGETCWD */
+ debug(F101,"zgtdir COHERENT _I386 CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+ extern char *getwd();
+ debug(F101,"zgtdir COHERENT CWDBL","",CWDBL);
+ s = getwd(buf);
+ if (!s) s = "./";
+ return(s);
+#endif /* _I386 */
+#else
+#ifdef SUNOS4
+ debug(F101,"zgtdir SUNOS CWDBL","",CWDBL);
+ s = getcwd(buf,CWDBL);
+ if (!s) s = "./";
+ return(s);
+#else
+ return("./");
+#endif /* SUNOS4 */
+#endif /* COHERENT */
+#endif /* SYSVORPOSIX */
+#endif /* MINIX2 */
+#endif /* BSD44 */
+#endif /* USE_GETWD */
+}
+
+/* Z X C M D -- Run a system command so its output can be read like a file */
+
+#ifndef NOPUSH
+int
+zxcmd(filnum,comand) int filnum; char *comand; {
+ int out;
+ int pipes[2];
+ extern int kactive; /* From ckcpro.w and ckcmai.c */
+
+ if (nopush) {
+ debug(F100,"zxcmd fails: nopush","",0);
+ return(-1);
+ }
+ debug(F111,"zxcmd",comand,filnum);
+ if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
+ if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
+ return(0);
+
+ out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
+ debug(F101,"zxcmd out",comand,out);
+
+/* Output to a command */
+
+ if (out) { /* Need popen() to do this. */
+ ckstrncpy(fullname,"(pipe)",CKMAXPATH);
+#ifdef NOPOPEN
+ return(0); /* no popen(), fail. */
+#else
+/* Use popen() to run the command. */
+
+#ifdef _POSIX_SOURCE
+/* Strictly speaking, popen() is not available in POSIX.1 */
+#define DCLPOPEN
+#endif /* _POSIX_SOURCE */
+
+ debug(F110,"zxcmd out",comand,0);
+
+ if (priv_chk()) {
+ debug(F100,"zxcmd priv_chk failed","",0);
+ return(0);
+ }
+ errno = 0;
+ fp[filnum] = popen(comand,"w");
+ debug(F111,"zxcmd popen",fp[filnum] ? "OK" : "Failed", errno);
+ if (fp[filnum] == NULL)
+ return(0);
+#ifdef COMMENT
+/* I wonder what this is all about... */
+ close(pipes[0]); /* Don't need the input side */
+ fp[filnum] = fdopen(pipes[1],"w"); /* Open output stream. */
+ fp[ZSYSFN] = fp[filnum]; /* Remember. */
+#endif /* COMMENT */
+ ispipe[filnum] = 1;
+ zoutcnt = 0; /* (PWP) reset input buffer */
+ zoutptr = zoutbuffer;
+ return(1);
+#endif /* NOPOPEN */
+ }
+
+/* Input from a command */
+
+#ifdef SNI541
+ /* SINIX-L 5.41 does not like fdopen() */
+ return(0);
+#else
+ if (pipe(pipes) != 0) {
+ debug(F100,"zxcmd pipe failure","",0);
+ return(0); /* can't make pipe, fail */
+ }
+
+/* Create a fork in which to run the named process */
+
+ if ((
+#ifdef aegis
+ pid = vfork() /* child */
+#else
+ pid = fork() /* child */
+#endif /* aegis */
+ ) == 0) {
+
+/* We're in the fork. */
+
+ char *shpath, *shname, *shptr; /* Find user's preferred shell */
+#ifndef aegis
+ struct passwd *p;
+ char *defshell;
+#ifdef HPUX10 /* Default shell */
+ defshell = "/usr/bin/sh";
+#else
+#ifdef Plan9
+ defshell = "/bin/rc";
+#else
+ defshell = "/bin/sh";
+#endif /* Plan9 */
+#endif /* HPUX10 */
+#endif /* aegis */
+ if (priv_can()) exit(1); /* Turn off any privileges! */
+ debug(F101,"zxcmd pid","",pid);
+ close(pipes[0]); /* close input side of pipe */
+ close(0); /* close stdin */
+ if (open("/dev/null",0) < 0) return(0); /* replace input by null */
+#ifndef OXOS
+#ifndef SVORPOSIX
+ dup2(pipes[1],1); /* BSD: replace stdout & stderr */
+ dup2(pipes[1],2); /* by the pipe */
+#else
+ close(1); /* AT&T: close stdout */
+ if (dup(pipes[1]) != 1) /* Send stdout to the pipe */
+ return(0);
+ close(2); /* Send stderr to the pipe */
+ if (dup(pipes[1]) != 2)
+ return(0);
+#endif /* SVORPOSIX */
+#else /* OXOS */
+ dup2(pipes[1],1);
+ dup2(pipes[1],2);
+#endif /* OXOS */
+ close(pipes[1]); /* Don't need this any more. */
+
+#ifdef aegis
+ if ((shpath = getenv("SERVERSHELL")) == NULL)
+ shpath = "/bin/sh";
+#else
+ shpath = getenv("SHELL"); /* What shell? */
+ if (shpath == NULL) {
+ p = getpwuid( real_uid() ); /* Get login data */
+ debug(F111,"zxcmd shpath","getpwuid()",p);
+ if (p == (struct passwd *)NULL || !*(p->pw_shell))
+ shpath = defshell;
+ else shpath = p->pw_shell;
+ }
+#endif /* aegis */
+ shptr = shname = shpath;
+ while (*shptr != '\0')
+ if (*shptr++ == '/')
+ shname = shptr;
+ debug(F110,shpath,shname,0);
+ restorsigs(); /* Restore ignored signals */
+ execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
+ exit(0); /* just punt if it failed. */
+ } else if (pid == (PID_T) -1) {
+ debug(F100,"zxcmd fork failure","",0);
+ return(0);
+ }
+ debug(F101,"zxcmd pid","",pid);
+ close(pipes[1]); /* Don't need the output side */
+ ispipe[filnum] = 1; /* Remember it's a pipe */
+ fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
+
+#ifdef DONDELAY
+#ifdef SELECT
+ if (filnum == ZIFILE && kactive) { /* Make pipe reads nonblocking */
+ int flags, x;
+ if ((flags = fcntl(fileno(fp[filnum]),F_GETFL,0)) > -1) {
+ debug(F101,"zxcmd fcntl 1 pipe flags","",flags);
+ x = fcntl(fileno(fp[filnum]),F_SETFL, flags |
+#ifdef QNX
+ O_NONBLOCK
+#else
+ O_NDELAY
+#endif /* QNX */
+ );
+ debug(F101,"zxcmd fcntl 2 result","",x);
+ }
+ }
+#endif /* SELECT */
+#endif /* DONDELAY */
+#endif /* SNI541 */
+ fp[ZSYSFN] = fp[filnum]; /* Remember. */
+ zincnt = 0; /* (PWP) reset input buffer */
+ zinptr = zinbuffer;
+ fullname[0] = '\0';
+ return(1);
+} /* zxcmd */
+
+/* Z C L O S F - wait for the child fork to terminate and close the pipe. */
+
+/* Used internally by zclose - returns -1 on failure, 1 on success. */
+
+int
+zclosf(filnum) int filnum; {
+ int wstat, out;
+ int statusp;
+
+ debug(F101,"zclosf filnum","",filnum);
+ out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
+ debug(F101,"zclosf out","",out);
+
+#ifndef NOPOPEN
+ if (ispipe[filnum]
+ /* In UNIX we use popen() only for output files */
+ && out
+ ) {
+ int x;
+ x = pclose(fp[filnum]);
+ pexitstat = x >> 8;
+ debug(F101,"zclosf pclose","",x);
+ debug(F101,"zclosf pexitstat","",pexitstat);
+ fp[filnum] = fp[ZSYSFN] = NULL;
+ ispipe[filnum] = 0;
+ return((x != 0) ? -1 : 1);
+ }
+#endif /* NOPOPEN */
+ debug(F101,"zclosf fp[filnum]","", fp[filnum]);
+ debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
+
+ if (pid != (PID_T) 0) {
+ debug(F101,"zclosf killing pid","",pid);
+#ifdef Plan9
+ kill(pid, SIGKILL);
+#else
+ kill(pid,9);
+#endif /* Plan9 */
+
+#ifndef CK_CHILD
+/*
+ This is the original code (before 20 April 1997) and has proven totally
+ portable. But it does not give us the process's return code.
+*/
+ while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
+#else
+/* Here we try to get the return code. Let's hope this is portable too. */
+ while ((wstat = wait(&statusp)) != pid && wstat != -1) ;
+ pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
+ debug(F101,"zclosf wait statusp","",statusp);
+ debug(F101,"zclosf wait pexitstat","",pexitstat);
+#endif /* CK_CHILD */
+ pid = 0;
+ }
+ fclose(fp[filnum]);
+ fp[filnum] = fp[ZSYSFN] = NULL;
+
+ ispipe[filnum] = 0;
+ debug(F101,"zclosf fp[filnum]","",fp[filnum]);
+#ifdef CK_CHILD
+ return(pexitstat == 0 ? 1 : -1);
+#else
+ return(1);
+#endif /* CK_CHILD */
+}
+
+#else /* NOPUSH */
+
+int
+zxcmd(filnum,comand) int filnum; char *comand; {
+ return(0);
+}
+int
+zclosf(filnum) int filnum; {
+ return(EOF);
+}
+#endif /* NOPUSH */
+
+
+/* Z X P A N D -- Expand a wildcard string into an array of strings */
+/*
+ As of C-Kermit 7.0, this API is obsolete, replaced by nzxpand(), and this
+ function is only used internally. See nzxpand() below.
+
+ Returns the number of files that match fnarg, with data structures set up
+ so that first file (if any) will be returned by the next znext() call.
+
+ Depends on external variable wildxpand: 0 means we expand wildcards
+ internally, nonzero means we call the shell to do it.
+*/
+static int xdironly = 0;
+static int xfilonly = 0;
+static int xmatchdot = 0;
+static int xrecursive = 0;
+static int xnobackup = 0;
+static int xnolinks = 0;
+
+static char *freeptr = NULL, **resptr = NULL; /* Copies of caller's args */
+static int remlen; /* Remaining space in caller's array */
+static int numfnd = 0; /* Number of matches found */
+
+#define MINSPACE 1024
+
+static int
+initspace(resarry,len) char * resarry[]; int len; {
+#ifdef DYNAMIC
+ if (len < MINSPACE) len = MINSPACE;
+ if (!sspace) { /* Need to allocate string space? */
+ while (len >= MINSPACE) {
+ if ((sspace = malloc(len+2))) { /* Got it. */
+ debug(F101,"fgen string space","",len);
+ break;
+ }
+ len = (len / 2) + (len / 4); /* Didn't, reduce by 3/4 */
+ }
+ if (len <= MINSPACE) { /* Did we get it? */
+ fprintf(stderr,"fgen can't malloc string space\n");
+ return(-1);
+ }
+ ssplen = len;
+ }
+#endif /* DYNAMIC */
+
+ freeptr = sspace; /* This is where matches are copied. */
+ resptr = resarry; /* Static copies of these so */
+ remlen = len; /* recursive calls can alter them. */
+ debug(F101,"initspace ssplen","",ssplen);
+ return(0);
+}
+
+/*
+ Z S E T F I L -- Query or change the size of file list buffers.
+
+ fc = 1: Change current string space to n, return new size.
+ fc = 2: Return current string space size.
+ fc = 3: Change current maxnames to n, return new maxnames.
+ fc = 4: Return current maxnames.
+ Returns < 0 on error.
+*/
+int
+zsetfil(n, fc) int n, fc; {
+#ifdef DYNAMIC
+ switch (fc) {
+ case 1: /* Stringspace */
+ if (sspace) {
+ free(sspace);
+ sspace = NULL;
+ }
+ if (initspace(mtchs,n) < 0)
+ return(-1);
+ case 2: /* Fall thru deliberately */
+ return(ssplen);
+ case 3: /* Listsize */
+ if (mtchs) {
+ free((char *)mtchs);
+ mtchs = NULL;
+ }
+ mtchs = (char **)malloc(n * sizeof(char *));
+ if (!mtchs)
+ return(-1);
+ maxnames = n;
+ case 4: /* Fall thru deliberately */
+ return(maxnames);
+ }
+#endif /* DYNAMIC */
+ return(-1);
+}
+
+
+
+#ifndef NONZXPAND
+#ifndef pdp11
+static
+#endif /* pdp11 */
+#endif /* NONZXPAND */
+int
+zxpand(fnarg) char *fnarg; {
+ extern int diractive;
+ char fnbuf[CKMAXPATH+8], * fn, * p;
+
+#ifdef DTILDE /* Built with tilde-expansion? */
+ char *tnam;
+#endif /* DTILDE */
+ int x;
+ int haveonedir = 0;
+
+ if (!fnarg) { /* If no argument provided */
+ nxpand = fcount = 0;
+ return(0); /* Return zero files found */
+ }
+ debug(F110,"zxpand entry",fnarg,0);
+ debug(F101,"zxpand xdironly","",xdironly);
+ debug(F101,"zxpand xfilonly","",xfilonly);
+
+ if (!*fnarg) { /* If no argument provided */
+ nxpand = fcount = 0;
+ return(0); /* Return zero files found */
+ }
+
+#ifdef CKROOT
+ debug(F111,"zxpand setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(fnarg)) {
+ debug(F110,"zxpand setroot violation",fnarg,0);
+ nxpand = fcount = 0;
+ return(0);
+ }
+#endif /* CKROOT */
+
+#ifdef COMMENT
+/*
+ This would have been perfect, except it makes us return fully qualified
+ pathnames for all files.
+*/
+ zfnqfp(fnarg,CKMAXPATH,fnbuf);
+ debug(F110,"zxpand zfnqfp",fnbuf,0);
+ s = zgtdir();
+ debug(F110,"zxpand zgtdir",s,0);
+ p = fnbuf;
+ while (*p && *s) /* Make it relative */
+ if (*s++ != *p++)
+ break;
+ fn = (*s) ? fnbuf : p;
+ debug(F110,"zxpand fn 0",fn,0);
+ if (!*fn) {
+ fn = fnbuf;
+ fnbuf[0] = '*';
+ fnbuf[1] = '\0';
+ }
+ debug(F110,"zxpand fn 0.5",fn,0);
+#else
+#ifdef DTILDE /* Built with tilde-expansion? */
+ if (*fnarg == '~') { /* Starts with tilde? */
+ tnam = tilde_expand(fnarg); /* Try to expand it. */
+ ckstrncpy(fnbuf,tnam,CKMAXPATH);
+ } else
+#endif /* DTILDE */
+ ckstrncpy(fnbuf,fnarg,CKMAXPATH);
+ fn = fnbuf; /* Point to what we'll work with */
+#endif /* COMMENT */
+ debug(F110,"zxpand fn 1",fn,0);
+
+ if (!*fn) /* But make sure something is there */
+ return(0);
+
+ p = fn + (int)strlen(fn) - 1;
+ if (*p == '/') { /* If last char = / it must be a dir */
+ if (!xfilonly && !iswild(p)) haveonedir++;
+ ckstrncat(fn, "*", CKMAXPATH+8); /* so append '*' */
+ } else if (p > fn) { /* If ends in "/." */
+ if (*(p-1) == '/' && *p == '.') /* change '.' to '*' */
+ *p = '*';
+ } else if (p == fn) { /* If it's '.' alone */
+ if (*p == '.') /* change '.' to '*' */
+ *p = '*';
+ }
+ debug(F110,"zxpand fn 2",fn,0);
+ x = isdir(fn); /* Is it a directory? */
+ debug(F111,"zxpand isdir 1",fn,x);
+ if (x) { /* If so, make it into a wildcard */
+ if (!xfilonly && !iswild(p))
+ haveonedir++;
+ if ((x = strlen(fn)) > 0) {
+ if (!ISDIRSEP(fn[x-1]))
+ fn[x++] = DIRSEP;
+ fn[x++] = '*';
+ fn[x] = '\0';
+ }
+ }
+ debug(F111,"zxpand fn 3",fn,haveonedir);
+/*
+ The following allows us to parse a single directory name without opening
+ the directory and looking at its contents. The diractive flag is a horrible
+ hack (especially since DIR /NORECURSIVE turns it off), but otherwise we'd
+ have to change the API.
+*/
+ if (!diractive && haveonedir) {
+#ifdef COMMENT
+ fcount = (mtchs == NULL &&
+ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
+ ? 0 : 1;
+#else
+ fcount = 0;
+ if (!mtchs) {
+ mtchs = (char **)malloc(maxnames * sizeof(*mtchs));
+ if (mtchs)
+ fcount = 1;
+ if (!fcount)
+ return(nxpand = fcount);
+ }
+#endif /* COMMENT */
+ debug(F110,"zxpand haveonedir A1",fnarg,0);
+ initspace(mtchs,ssplen);
+ addresult(fnarg,1);
+ if (numfnd < 0) return(-1);
+ mtchptr = mtchs; /* Save pointer for next. */
+ debug(F110,"zxpand haveonedir A2",*mtchptr,0);
+ return(nxpand = fcount);
+ }
+
+#ifndef NOPUSH
+ if (!nopush && wildxpand) /* Who is expanding wildcards? */
+ fcount = (mtchs == NULL && /* Shell */
+ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
+ ? 0
+ : shxpand(fn,mtchs,maxnames);
+ else
+#endif /* NOPUSH */
+ fcount = (mtchs == NULL && /* Kermit */
+ (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
+ ? 0
+ : fgen(fn,mtchs,maxnames); /* Look up the file. */
+
+ if (fcount == 0 && haveonedir) {
+ fcount = 1;
+ debug(F110,"zxpand haveonedir B",fnarg,0);
+ addresult(fnarg,1);
+ if (numfnd < 0) return(-1);
+ }
+ mtchptr = mtchs; /* Save pointer for next. */
+ nxpand = fcount;
+
+#ifdef DEBUG
+ if (deblog) {
+ if (fcount > 1)
+ debug(F111,"zxpand ok",mtchs[0],fcount);
+ else
+ debug(F101,"zxpand fcount","",fcount);
+ }
+#endif /* DEBUG */
+ return(fcount);
+}
+
+#ifndef NONZXPAND
+/* N Z X P A N D -- Expand a file list, with options. */
+/*
+ Call with:
+ s = pointer to filename or pattern.
+ flags = option bits:
+
+ flags & ZX_FILONLY Match regular files
+ flags & ZX_DIRONLY Match directories
+ flags & ZX_RECURSE Descend through directory tree
+ flags & ZX_MATCHDOT Match "dot files"
+ flags & ZX_NOBACKUP Don't match "backup files"
+ flags & ZX_NOLINKS Don't follow symlinks.
+
+ Returns the number of files that match s, with data structures set up
+ so that first file (if any) will be returned by the next znext() call.
+*/
+int
+nzxpand(s,flags) char * s; int flags; {
+ char * p;
+ int x;
+
+ debug(F111,"nzxpand",s,flags);
+ x = flags & (ZX_DIRONLY|ZX_FILONLY);
+ xdironly = (x == ZX_DIRONLY);
+ xfilonly = (x == ZX_FILONLY);
+ if (xdironly && xfilonly) {
+ xdironly = 0;
+ xfilonly = 0;
+ }
+ xmatchdot = (flags & ZX_MATCHDOT);
+ debug(F111,"nzxpand xmatchdot 1",s,xmatchdot);
+ /* If xmatchdot not set by caller but pattern implies it, set it anyway */
+ if (!xmatchdot && ((p = ckstrchr(s,'.')))) {
+ if (p == s && p[1] != '/') {
+ xmatchdot = 1;
+ debug(F111,"nzxpand xmatchdot 2",s,xmatchdot);
+ } else if (p > s) {
+ xmatchdot = (*(p-1) == ',') || (*(p-1) == '{') || (*(p-1) == '/');
+ debug(F111,"nzxpand xmatchdot 3",s,xmatchdot);
+ }
+ }
+ xrecursive = (flags & ZX_RECURSE);
+ xnobackup = (flags & ZX_NOBACKUP);
+ xnolinks = (flags & ZX_NOLINKS);
+
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"nzxpand xdironly","",xdironly);
+ debug(F101,"nzxpand xfilonly","",xfilonly);
+ debug(F101,"nzxpand xmatchdot","",xmatchdot);
+ debug(F101,"nzxpand xrecursive","",xrecursive);
+ debug(F101,"nzxpand xnobackup","",xnobackup);
+ debug(F101,"nzxpand xnolinks","",xnolinks);
+ }
+#endif /* DEBUG */
+
+ x = zxpand(s);
+ if (x > 1)
+ sh_sort(mtchs,NULL,x,0,0,1); /* Alphabetize the list */
+ xdironly = 0;
+ xfilonly = 0;
+ xmatchdot = 0;
+ xrecursive = 0;
+ xnobackup = 0;
+ xnolinks = 0;
+ return(x);
+}
+#endif /* NONZXPAND */
+
+#ifndef NOZXREWIND
+/* Z X R E W I N D -- Rewinds the zxpand() list */
+
+int
+zxrewind() {
+ /* if (!mtchs) return(-1); */
+ fcount = nxpand;
+ mtchptr = mtchs;
+ return(nxpand);
+}
+#endif /* NOZXREWIND */
+
+/* Z N E X T -- Get name of next file from list created by zxpand(). */
+/*
+ Returns >0 if there's another file, with its name copied into the arg string,
+ or 0 if no more files in list.
+*/
+int
+znext(fn) char *fn; {
+ if (fcount-- > 0) {
+ ckstrncpy(fn,*mtchptr++,CKMAXPATH);
+ } else {
+ fn[0] = '\0';
+ }
+#ifndef COMMENT
+ debug(F111,"znext",fn,fcount+1);
+ return(fcount+1);
+#else
+ debug(F111,"znext",fn,fcount); /* Return 0 if no filename to return */
+ return(fcount);
+#endif /* COMMENT */
+}
+
+/* Z C H K S P A -- Check if there is enough space to store the file */
+
+/*
+ Call with file specification f, size n in bytes.
+ Returns -1 on error, 0 if not enough space, 1 if enough space.
+*/
+/*ARGSUSED*/
+int
+#ifdef CK_ANSIC
+zchkspa(char *f, long n)
+#else
+zchkspa(f,n) char *f; long n;
+#endif /* CK_ANSIC */
+/* zchkspa() */ {
+ /* In UNIX there is no good (and portable) way. */
+ return(1); /* Always say OK. */
+}
+
+#ifdef COMMENT /* (not used) */
+
+/* I S B A C K U P -- Tells if given file has a backup suffix */
+/*
+ Returns:
+ -1: Invalid argument
+ 0: File does not have a backup suffix
+ >0: Backup suffix number
+*/
+int
+isbackup(fn) char * fn; { /* Get backup suffix number */
+ int i, j, k, x, state, flag;
+
+ if (!fn) /* Watch out for null pointers. */
+ return(-1);
+ if (!*fn) /* And empty names. */
+ return(-1);
+
+ flag = state = 0;
+ for (i = (int)strlen(fn) - 1; (!flag && (i > 0)); i--) {
+ switch (state) {
+ case 0: /* State 0 - final char */
+ if (fn[i] == '~') /* Is tilde */
+ state = 1; /* Switch to next state */
+ else /* Otherwise */
+ flag = 1; /* Quit - no backup suffix. */
+ break;
+ case 1: /* State 1 - digits */
+ if (fn[i] == '~' && fn[i-1] == '.') { /* Have suffix */
+ return(atoi(&fn[i+1]));
+ } else if (fn[i] >= '0' && fn[i] <= '9') { /* In number part */
+ continue; /* Keep going */
+ } else { /* Something else */
+ flag = 1; /* Not a backup suffix - quit. */
+ }
+ break;
+ }
+ }
+ return(0);
+}
+#endif /* COMMENT */
+
+
+/* Z N E W N -- Make a new name for the given file */
+
+/*
+ Given the name, fn, of a file that already exists, this function builds a
+ new name of the form "<oldname>.~<n>~", where <oldname> is argument name
+ (fn), and <n> is a version number, one higher than any existing version
+ number for that file, up to 99999. This format is consistent with that used
+ by GNU EMACS. If the constructed name is too long for the system's maximum,
+ enough characters are truncated from the end of <fn> to allow the version
+ number to fit. If no free version numbers exist between 1 and 99999, a
+ version number of "xxxx" is used. Returns a pointer to the new name in
+ argument s.
+*/
+#ifdef pdp11
+#define ZNEWNBL 63 /* Name buffer length */
+#define ZNEWNMD 3 /* Max digits for version number */
+#else
+#define ZNEWNBL CKMAXPATH
+#define ZNEWNMD 4
+#endif /* pdp11 */
+
+#define MAXBUDIGITS 5
+
+static char znewbuf[ZNEWNBL+12];
+
+VOID
+znewn(fn,s) char *fn, **s; {
+ char * buf; /* Pointer to buffer for new name */
+ char * xp, * namepart = NULL; /* Pointer to filename part */
+ struct zfnfp * fnfp; /* znfqfp() result struct pointer */
+ int d = 0, t, fnlen, buflen;
+ int n, i, k, flag, state;
+ int max = MAXNAMLEN; /* Maximum name length */
+ char * dname = NULL;
+
+ buf = znewbuf;
+ *s = NULL; /* Initialize return value */
+ if (!fn) fn = ""; /* Check filename argument */
+ i = strlen(fn);
+
+/* If incoming file already has a backup suffix, remove it. */
+/* Then we'll tack a new on later, which will be the highest for this file. */
+
+ if (i <= max && i > 0 && fn[i-1] == '~') {
+ char * p;
+ i--;
+ debug(F111,"znewn suffix removal",fn,i);
+ if ((dname = (char *)malloc(i+1))) {
+ ckstrncpy(dname,fn,i+1);
+ p = dname;
+ for (flag = state = 0; (!flag && (i > 0)); i--) {
+ switch (state) {
+ case 0: /* State 0 - final char */
+ if (p[i] == '~') /* Is tilde */
+ state = 1; /* Switch to next state */
+ else /* Otherwise */
+ flag = 1; /* Quit - no backup suffix. */
+ break;
+ case 1: /* State 1 - digits */
+ if (p[i] == '~' && p[i-1] == '.') { /* Have suffix */
+ p[i-1] = NUL; /* Trim it */
+ fn = dname;
+ debug(F111,"znewn suffix removal 2",fn,i);
+ flag = 1; /* done */
+ } else if (p[i] >= '0' && p[i] <= '9') { /* Number part */
+ continue; /* Keep going */
+ } else { /* Something else */
+ flag = 1; /* Not a backup suffix - quit. */
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ((fnlen = strlen(fn)) < 1) { /* Get length */
+ if (dname) free(dname);
+ return;
+ }
+ debug(F111,"znewn",fn,fnlen);
+
+ debug(F101,"znewn max 1","",max);
+ if (max < 14) max = 14; /* Make max reasonable for any UNIX */
+ if (max > ZNEWNBL) max = ZNEWNBL;
+ debug(F101,"znewn max 2","",max);
+
+ if ((fnfp = zfnqfp(fn, ZNEWNBL, buf))) { /* Get fully qualified name */
+ namepart = fnfp->fname; /* Isolate the filename */
+ k = strlen(fn); /* Length of name part */
+ debug(F111,"znewn namepart",namepart,k);
+ } else {
+ if (dname) free(dname);
+ return;
+ }
+ buflen = fnfp->len; /* Length of fully qualified name */
+ debug(F111,"znewn len",buf,buflen);
+
+ if (k + MAXBUDIGITS + 3 < max) { /* Backup name fits - no overflow */
+ /* Make pattern for backup names */
+ ckstrncpy(buf+buflen,".~*~",ZNEWNBL+12-buflen);
+ n = nzxpand(buf,ZX_FILONLY); /* Expand the pattern */
+ debug(F111,"znewn A matches",buf,n);
+ while (n-- > 0) { /* Find any existing name.~n~ files */
+ xp = *mtchptr++; /* Point at matching name */
+ t = atoi(xp+buflen+2); /* Get number */
+ if (t > d) d = t; /* Save d = highest version number */
+ }
+ sprintf(buf+buflen,".~%d~",d+1); /* Yes, make "name.~<d+1>~" */
+ debug(F110,"znewn A newname",buf,0);
+ } else { /* Backup name would be too long */
+ int xlen; /* So we have to eat back into it */
+ int delta;
+ char buf2[ZNEWNBL+12];
+
+ delta = max - k;
+ debug(F101,"znewn B delta","",delta);
+
+ for (i = MAXBUDIGITS; i > 0; i--) { /* In this case the format of */
+ ckstrncpy(buf2,buf,ZNEWNBL+12); /* the backup name depends on */
+ xlen = buflen - i - 3 + delta; /* how many digits are in the */
+ ckstrncpy(buf2+xlen,".~*~",ZNEWNBL+12-xlen); /* backup number */
+ n = nzxpand(buf2,ZX_FILONLY);
+ debug(F111,"znewn B matches",buf2,n);
+ if (n > 0)
+ break;
+ }
+ while (n-- > 0) { /* Find any existing name.~n~ files */
+ xp = *mtchptr++; /* Point at matching name */
+ t = atoi(xp+xlen+2); /* Get number */
+ if (t > d) d = t; /* Save d = highest version number */
+ }
+ if (d > 0) /* If the odometer turned over... */
+ if ((d % 10) == 9) /* back up one space. */
+ xlen--;
+ sprintf(buf2+xlen,".~%d~",d+1); /* This just fits */
+ ckstrncpy(buf,buf2,ZNEWNBL+12); /* (we could be more clever here...) */
+ debug(F110,"znewn B new name",buf,0);
+ }
+ *s = buf; /* Point to new name */
+ ck_znewn = d+1; /* Also make it available globally */
+ if (dname) free(dname);
+ return;
+}
+
+/* Z R E N A M E -- Rename a file */
+/*
+ Call with old and new names.
+ If new name is the name of a directory, the 'old' file is moved to
+ that directory.
+ Returns 0 on success, -1 on failure.
+*/
+int
+zrename(old,new) char *old, *new; {
+ char *p, *s;
+ int x;
+
+ if (!old) old = "";
+ if (!new) new = "";
+ debug(F110,"zrename old",old,0);
+ debug(F110,"zrename new",new,0);
+ if (!*old) return(-1);
+ if (!*new) return(-1);
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return(-1);
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+#ifdef CKROOT
+ debug(F111,"zrename setroot",ckroot,ckrootset);
+ if (ckrootset) {
+ if (!zinroot(old)) {
+ debug(F110,"zrename old: setroot violation",old,0);
+ return(-1);
+ }
+ if (!zinroot(new)) {
+ debug(F110,"zrename new: setroot violation",new,0);
+ return(-1);
+ }
+ }
+#endif /* CKROOT */
+
+ p = NULL;
+ s = new;
+
+ if (isdir(new)) {
+ char *q = NULL;
+ x = strlen(new);
+ if (!(p = malloc(strlen(new) + strlen(old) + 2)))
+ return(-1);
+ strcpy(p,new); /* (safe) Directory part */
+ if (!ISDIRSEP(*(new+x-1))) /* Separator, if needed */
+ strcat(p,"/"); /* (safe) */
+ zstrip(old,&q); /* Strip path part from old name */
+ strcat(p,q); /* cat to new directory (safe) */
+ s = p;
+ debug(F110,"zrename dir",s,0);
+ }
+#ifdef DEBUG
+ else debug(F110,"zrename no dir",s,0);
+#endif /* DEBUG */
+
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_del))) {
+ if (zchki(s) > -1) /* Destination file exists? */
+ return(-1);
+ }
+#endif /* IKSD */
+
+ x = -1; /* Return code. */
+#ifdef RENAME
+/* Atomic, preferred, uses a single system call, rename(), if available. */
+ x = rename(old,s);
+ debug(F111,"zrename rename()",old,x);
+ if (x) x = -1;
+#endif /* RENAME */
+
+ /* If rename() failed or not available try link()/unlink() */
+
+ if (x < 0) {
+ if (zchko(old) > -1) { /* Requires write access to orignal */
+ x = link(old,s);
+ debug(F111,"zrename link()",old,x);
+ if (x > -1) { /* Make a link with the new name. */
+ x = unlink(old);
+ debug(F111,"zrename unlink()",old,x);
+ }
+ /* If link/unlink failed copy and delete */
+ if (x < 0) {
+ x = zcopy(old,s);
+ debug(F111,"zrename zcopy()",old,x);
+ if (x > -1) {
+ x = zdelet(old);
+ debug(F111,"zrename zdelet()",old,x);
+ }
+ }
+ }
+ }
+ fullname[0] = '\0'; /* Clear this out for next time. */
+
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_FC && ckxlogging) {
+ zfnqfp(old,CKMAXPATH,fullname);
+ tmp2[0] = '\0';
+ zfnqfp(s,CKMAXPATH,tmp2);
+ if (x > -1)
+ syslog(LOG_INFO,"file[] %s: renamed to %s ok", fullname, tmp2);
+ else
+ syslog(LOG_INFO,"file[] %s: rename to %s failed (%m)",fullname,tmp2);
+ }
+#endif /* CKSYSLOG */
+
+ if (p) free(p);
+ return(x);
+}
+
+/* Z C O P Y -- Copy a single file. */
+/*
+ Call with source and destination names.
+ If destination is a directory, the source file is
+ copied to that directory with its original name.
+ Returns:
+ 0 on success.
+ <0 on failure:
+ -2 = source file is not a regular file.
+ -3 = source file not found.
+ -4 = permission denied.
+ -5 = source and destination are the same file.
+ -6 = i/o error.
+ -1 = other error.
+*/
+int
+zcopy(source,destination) char *source, *destination; {
+ char *src, *dst; /* Local pointers to filenames */
+ int x, y, rc; /* Workers */
+ int in = -1, out = -1; /* i/o file descriptors */
+ struct stat srcbuf; /* Source file info buffer */
+ int perms; /* Output file permissions */
+ char buf[1024]; /* File copying buffer */
+
+ if (!source) source = "";
+ if (!destination) destination = "";
+
+ debug(F110,"zcopy src arg",source,0);
+ debug(F110,"zcopy dst arg",destination,0);
+
+ if (!*source) return(-1);
+ if (!*destination) return(-1);
+
+#ifdef IKSD
+#ifdef CK_LOGIN
+ if (inserver && isguest)
+ return(-4);
+#endif /* CK_LOGIN */
+#endif /* IKSD */
+
+#ifdef CKROOT
+ debug(F111,"zcopy setroot",ckroot,ckrootset);
+ if (ckrootset) {
+ if (!zinroot(source)) {
+ debug(F110,"zcopy source: setroot violation",source,0);
+ return(-1);
+ }
+ if (!zinroot(destination)) {
+ debug(F110,"zcopy destination: setroot violation",destination,0);
+ return(-1);
+ }
+ }
+#endif /* CKROOT */
+
+ src = source;
+ dst = destination;
+
+ if (stat(src,&srcbuf) == 0) { /* Get source file info */
+ struct stat dstbuf; /* Destination file info buffer */
+ debug(F101,"STAT","",6);
+ if (stat(dst,&dstbuf) == 0) {
+ debug(F101,"STAT","",7);
+ if (srcbuf.st_dev == dstbuf.st_dev)
+ if (srcbuf.st_ino == dstbuf.st_ino) {
+ debug(F100,"zcopy files identical: stat()","",0);
+ return(-5);
+ }
+ }
+ } else { /* stat() failed... */
+ debug(F101,"STAT","",8);
+ debug(F111,"source file not found",src,errno);
+ return(-3);
+ }
+ fullname[0] = '\0'; /* Get full pathnames */
+ if (zfnqfp(source,CKMAXPATH,fullname))
+ src = fullname;
+ debug(F110,"zcopy src",src,0);
+ tmp2[0] = '\0';
+ if (zfnqfp(destination,CKMAXPATH,tmp2))
+ dst = tmp2;
+ debug(F110,"zcopy dst 1",dst,0);
+ if (!strcmp(src,dst)) { /* Src and dst are same file? */
+ debug(F100,"zcopy files identical: strcmp()","",0); /* This... */
+ return(-5); /* should not happen. */
+ }
+ if (isdir(src)) { /* Source file is a directory? */
+ debug(F110,"zcopy source is directory",src,0);
+ return(-2); /* Fail */
+ }
+ if (isdir(dst)) { /* Destination is a directory? */
+ char *q = NULL; /* Yes, add filename to it. */
+ x = strlen(dst);
+ if (x < 1) return(-1);
+ if (!ISDIRSEP(*(dst+x-1))) { /* Add separator if needed */
+ tmp2[x++] = '/';
+ tmp2[x] = '\0';
+ }
+ debug(F111,"zcopy dst 2",dst,x);
+ zstrip(src,&q); /* Strip path part from old name */
+ ckstrncpy(tmp2+x,q,CKMAXPATH-x); /* Concatenate it to new name */
+ }
+ debug(F110,"zcopy dst 3",dst,0);
+
+#ifdef IKSD
+ if (inserver && (!ENABLED(en_del))) {
+ if (zchki(dst) > -1) /* Destination file exists? */
+ return(-4);
+ }
+#endif /* IKSD */
+
+ perms = umask(0); /* Get user's umask */
+ umask(perms); /* Put it back! */
+ perms ^= 0777; /* Flip the bits */
+ perms &= 0666; /* Zero execute bits from umask */
+ perms |= (srcbuf.st_mode & 0111); /* OR in source file's execute bits */
+ rc = -1; /* Default return code */
+ errno = 0; /* Reset errno */
+ in = open(src, O_RDONLY, 0); /* Open source file */
+ debug(F111,"zcopy open source",src,in);
+ if (in > -1) { /* If open... */
+ /* Open destination file */
+#ifdef O_TRUNC
+ out = open(dst, O_WRONLY|O_CREAT|O_TRUNC, perms);
+#else
+ out = open(dst, O_WRONLY|O_CREAT, perms);
+#endif /* O_TRUNC */
+ debug(F111,"zcopy open dest",dst,out);
+ if (out > -1) { /* If open... */
+ while ((x = read(in,buf,1024)) > 0) { /* Copy in 1K blocks */
+ y = write(out,buf,x);
+ if (y < 0) { /* On write failure */
+ x = -1;
+ rc = -6; /* Indicate i/o error */
+ break;
+ }
+ }
+ debug(F101,"zcopy final read","",x);
+ debug(F101,"zcopy errno","",errno);
+ rc = (x == 0) ? 0 : -6; /* In case of read failure */
+ }
+ }
+ if (in > -1) close(in); /* Close files */
+ if (out > -1) close(out);
+ if (rc == -1) { /* Set return code */
+ switch (errno) {
+ case ENOENT: rc = -3; break;
+ case EACCES: rc = -4; break;
+ case EIO: rc = -6;
+ }
+ }
+
+#ifdef CKSYSLOG
+ if (rc > -1 && ckxsyslog >= SYSLG_FC && ckxlogging) {
+ if (rc)
+ syslog(LOG_INFO,"file[] %s: copy to %s failed (%m)", fullname, tmp2);
+ else
+ syslog(LOG_INFO,"file[] %s: copy to %s ok", fullname, tmp2);
+ }
+#endif /* CKSYSLOG */
+
+ return(rc);
+}
+
+/* Z S A T T R */
+/*
+ Fills in a Kermit file attribute structure for the file which is to be sent.
+ Returns 0 on success with the structure filled in, or -1 on failure.
+ If any string member is null, then it should be ignored.
+ If any numeric member is -1, then it should be ignored.
+*/
+#ifdef CK_PERMS
+
+#ifdef CK_GPERMS
+#undef CK_GPERMS
+#endif /* CK_GPERMS */
+
+#ifdef UNIX
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif /* S_IRUSR */
+#ifndef S_IWUSR
+#define S_IXUSR 0200
+#endif /* S_IWUSR */
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif /* S_IXUSR */
+#endif /* UNIX */
+
+#ifdef S_IRUSR
+#ifdef S_IWUSR
+#ifdef S_IXUSR
+#define CK_GPERMS
+#endif /* S_IXUSR */
+#endif /* S_IWUSR */
+#endif /* S_IRUSR */
+
+static char gperms[2];
+
+#endif /* CK_GPERMS */
+
+static char lperms[24];
+
+#ifdef CK_PERMS
+static char xlperms[24];
+
+/* Z S E T P E R M -- Set permissions of a file */
+
+int
+zsetperm(f,code) char * f; int code; {
+ int x;
+#ifdef CK_SCO32V4
+ mode_t mask;
+#else
+ int mask;
+#endif /* CK_SCO32V4 */
+ mask = code;
+ if (inserver && guest) {
+ debug(F110,"zsetperm guest",f,0);
+ return(0);
+ }
+ x = chmod(f,mask);
+ if (x < 0) {
+ debug(F111,"zsetperm error",f,errno);
+ return(0);
+ }
+ debug(F111,"zsetperm ok",f,mask);
+ return(1);
+}
+
+/* Z G P E R M -- Get permissions of a file as an octal string */
+
+char *
+zgperm(f) char *f; {
+ extern int diractive;
+ int x; char *s = (char *)xlperms;
+ struct stat buf;
+ debug(F110,"zgperm",f,0);
+ if (!f) return("----------");
+ if (!*f) return("----------");
+
+#ifdef CKROOT
+ debug(F111,"zgperm setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zgperm setroot violation",f,0);
+ return("----------");
+ }
+#endif /* CKROOT */
+
+#ifdef USE_LSTAT
+ if (diractive)
+ x = lstat(f,&buf);
+ else
+#endif /* USE_LSTAT */
+ x = stat(f,&buf);
+ debug(F101,"STAT","",9);
+ if (x < 0)
+ return("----------");
+ sprintf(s,"%o",buf.st_mode);
+ debug(F110,"zgperm",s,0);
+ return(s);
+}
+
+/* Like zgperm() but returns permissions in "ls -l" string format */
+
+static char xsperms[24];
+
+char *
+ziperm(f) char * f; {
+ extern int diractive;
+ int x; char *s = (char *)xsperms;
+ struct stat buf;
+ unsigned int perms = 0;
+
+ debug(F110,"ziperm",f,0);
+
+ if (!f) return(NULL);
+ if (!*f) return(NULL);
+
+ if (diractive && zgfs_mode != 0) {
+ perms = zgfs_mode; /* zgetfs() already got them */
+ } else {
+#ifdef USE_LSTAT
+ if (diractive)
+ x = lstat(f,&buf);
+ else
+#endif /* USE_LSTAT */
+ x = stat(f,&buf);
+ debug(F101,"STAT","",10);
+ if (x < 0)
+ return("----------");
+ perms = buf.st_mode;
+ }
+ switch (perms & S_IFMT) {
+ case S_IFDIR:
+ *s++ = 'd';
+ break;
+ case S_IFCHR: /* Character special */
+ *s++ = 'c';
+ break;
+ case S_IFBLK: /* Block special */
+ *s++ = 'b';
+ break;
+ case S_IFREG: /* Regular */
+ *s++ = '-';
+ break;
+#ifdef S_IFLNK
+ case S_IFLNK: /* Symbolic link */
+ *s++ = 'l';
+ break;
+#endif /* S_IFLNK */
+#ifdef S_IFSOCK
+ case S_IFSOCK: /* Socket */
+ *s++ = 's';
+ break;
+#endif /* S_IFSOCK */
+#ifdef S_IFIFO
+#ifndef Plan9
+#ifndef COHERENT
+ case S_IFIFO: /* FIFO */
+ *s++ = 'p';
+ break;
+#endif /* COHERENT */
+#endif /* Plan9 */
+#endif /* S_IFIFO */
+#ifdef S_IFWHT
+ case S_IFWHT: /* Whiteout */
+ *s++ = 'w';
+ break;
+#endif /* S_IFWHT */
+ default: /* Unknown */
+ *s++ = '?';
+ break;
+ }
+ if (perms & S_IRUSR) /* Owner's permissions */
+ *s++ = 'r';
+ else
+ *s++ = '-';
+ if (perms & S_IWUSR)
+ *s++ = 'w';
+ else
+ *s++ = '-';
+ switch (perms & (S_IXUSR | S_ISUID)) {
+ case 0:
+ *s++ = '-';
+ break;
+ case S_IXUSR:
+ *s++ = 'x';
+ break;
+ case S_ISUID:
+ *s++ = 'S';
+ break;
+ case S_IXUSR | S_ISUID:
+ *s++ = 's';
+ break;
+ }
+ if (perms & S_IRGRP) /* Group permissions */
+ *s++ = 'r';
+ else
+ *s++ = '-';
+ if (perms & S_IWGRP)
+ *s++ = 'w';
+ else
+ *s++ = '-';
+ switch (perms & (S_IXGRP | S_ISGID)) {
+ case 0:
+ *s++ = '-';
+ break;
+ case S_IXGRP:
+ *s++ = 'x';
+ break;
+ case S_ISGID:
+ *s++ = 'S';
+ break;
+ case S_IXGRP | S_ISGID:
+ *s++ = 's';
+ break;
+ }
+ if (perms & S_IROTH) /* World permissions */
+ *s++ = 'r';
+ else
+ *s++ = '-';
+ if (perms & S_IWOTH)
+ *s++ = 'w';
+ else
+ *s++ = '-';
+ switch (
+#ifdef Plan9
+ perms & (S_IXOTH)
+#else
+ perms & (S_IXOTH | S_ISVTX)
+#endif
+ ) {
+ case 0:
+ *s++ = '-';
+ break;
+ case S_IXOTH:
+ *s++ = 'x';
+ break;
+#ifndef Plan9
+ case S_ISVTX:
+ *s++ = 'T';
+ break;
+ case S_IXOTH | S_ISVTX:
+ *s++ = 't';
+ break;
+#endif /* Plan9 */
+ }
+ *s = '\0';
+ debug(F110,"ziperm",xsperms,0);
+ return((char *)xsperms);
+}
+
+#else
+
+char *
+zgperm(f) char *f; {
+ return("----------");
+}
+char *
+ziperms(f) char *f; {
+ return("----------");
+}
+#endif /* CK_PERMS */
+
+int
+zsattr(xx) struct zattr *xx; {
+ long k; int x;
+ struct stat buf;
+
+ k = iflen % 1024L; /* File length in K */
+ if (k != 0L) k = 1L;
+ xx->lengthk = (iflen / 1024L) + k;
+ xx->type.len = 0; /* File type can't be filled in here */
+ xx->type.val = "";
+ if (*nambuf) {
+ xx->date.val = zfcdat(nambuf); /* File creation date */
+ xx->date.len = (int)strlen(xx->date.val);
+ } else {
+ xx->date.len = 0;
+ xx->date.val = "";
+ }
+ xx->creator.len = 0; /* File creator */
+ xx->creator.val = "";
+ xx->account.len = 0; /* File account */
+ xx->account.val = "";
+ xx->area.len = 0; /* File area */
+ xx->area.val = "";
+ xx->password.len = 0; /* Area password */
+ xx->password.val = "";
+ xx->blksize = -1L; /* File blocksize */
+ xx->xaccess.len = 0; /* File access */
+ xx->xaccess.val = "";
+ xx->encoding.len = 0; /* Transfer syntax */
+ xx->encoding.val = 0;
+ xx->disp.len = 0; /* Disposition upon arrival */
+ xx->disp.val = "";
+ xx->lprotect.len = 0; /* Local protection */
+ xx->lprotect.val = "";
+ xx->gprotect.len = 0; /* Generic protection */
+ xx->gprotect.val = "";
+ x = -1;
+ if (*nambuf) x = stat(nambuf,&buf);
+ debug(F101,"STAT","",11);
+ if (x >= 0) {
+ debug(F111,"zsattr buf.st_mode & 0777",nambuf,buf.st_mode & 0777);
+ /* UNIX filemode as an octal string without filetype bits */
+ sprintf(lperms,"%o",buf.st_mode & 0777);
+ xx->lprotect.len = (int)strlen(lperms);
+ xx->lprotect.val = (char *)lperms;
+ x = 0;
+#ifdef CK_GPERMS
+ /* Generic permissions only if we have stat.h symbols defined */
+ if (buf.st_mode & S_IRUSR) x |= 1; /* Read */
+ if (buf.st_mode & S_IWUSR) x |= (2+16); /* Write and Delete */
+ if (buf.st_mode & S_IXUSR) x |= 4; /* Execute */
+ gperms[0] = tochar(x);
+ gperms[1] = NUL;
+ xx->gprotect.len = 1;
+ xx->gprotect.val = (char *)gperms;
+#endif /* CK_GPERMS */
+ }
+ debug(F111,"zsattr lperms",xx->lprotect.val,xx->lprotect.len);
+ debug(F111,"zsattr gperms",xx->gprotect.val,xx->gprotect.len);
+ xx->systemid.val = "U1"; /* U1 = UNIX */
+ xx->systemid.len = 2; /* System ID */
+ xx->recfm.len = 0; /* Record format */
+ xx->recfm.val = "";
+ xx->sysparam.len = 0; /* System-dependent parameters */
+ xx->sysparam.val = "";
+ xx->length = iflen; /* Length */
+ return(0);
+}
+
+/* Z F C D A T -- Get file creation date */
+/*
+ Call with pointer to filename.
+ On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
+ On failure, returns pointer to null string.
+*/
+static char datbuf[40];
+
+char *
+#ifdef CK_ANSIC
+zdtstr(time_t timearg)
+#else
+zdtstr(timearg) time_t timearg;
+#endif /* CK_ANSIC */
+/* zdtstr */ {
+#ifndef TIMESTAMP
+ return("");
+#else
+ struct tm * time_stamp;
+ struct tm * localtime();
+ int yy, ss;
+
+ debug(F101,"zdtstr timearg","",timearg);
+ if (timearg < 0)
+ return("");
+ time_stamp = localtime(&(timearg));
+ if (!time_stamp) {
+ debug(F100,"localtime returns null","",0);
+ return("");
+ }
+/*
+ We assume that tm_year is ALWAYS years since 1900.
+ Any platform where this is not the case will have problems
+ starting in 2000.
+*/
+ yy = time_stamp->tm_year; /* Year - 1900 */
+ debug(F101,"zdtstr tm_year","",time_stamp->tm_year);
+ if (yy > 1000) {
+ debug(F101,"zstrdt YEAR-2000 ALERT 1: localtime year","",yy);
+ }
+ yy += 1900;
+ debug(F101,"zdatstr year","",yy);
+
+ if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
+ return("");
+ if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
+ return("");
+ if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
+ return("");
+ if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59)
+ return("");
+ ss = time_stamp->tm_sec; /* Seconds */
+ if (ss < 0 || ss > 59) /* Some systems give a BIG number */
+ ss = 0;
+ sprintf(datbuf,
+#ifdef pdp11
+/* For some reason, 2.1x BSD sprintf gets the last field wrong. */
+ "%04d%02d%02d %02d:%02d:00",
+#else
+ "%04d%02d%02d %02d:%02d:%02d",
+#endif /* pdp11 */
+ yy,
+ time_stamp->tm_mon + 1,
+ time_stamp->tm_mday,
+ time_stamp->tm_hour,
+ time_stamp->tm_min
+#ifndef pdp11
+ , ss
+#endif /* pdp11 */
+ );
+ yy = (int)strlen(datbuf);
+ debug(F111,"zdatstr",datbuf,yy);
+ if (yy > 17) datbuf[17] = '\0';
+ return(datbuf);
+#endif /* TIMESTAMP */
+}
+
+char *
+zfcdat(name) char *name; {
+#ifdef TIMESTAMP
+ struct stat buffer;
+ extern int diractive;
+ unsigned int mtime;
+ int x;
+ char * s;
+
+ if (!name)
+ return("");
+ s = name;
+ if (!*s)
+ return("");
+
+#ifdef CKROOT
+ debug(F111,"zfcdat setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(name)) {
+ debug(F110,"zfcdat setroot violation",name,0);
+ return("");
+ }
+#endif /* CKROOT */
+
+#ifdef DTILDE
+ if (*s == '~') {
+ s = tilde_expand(s);
+ if (!s) s = "";
+ if (!*s) s = name;
+ }
+#endif /* DTILDE */
+
+ datbuf[0] = '\0';
+ x = 0;
+ debug(F111,"zfcdat",s,diractive);
+
+ if (diractive && zgfs_mtime) {
+ mtime = zgfs_mtime;
+ } else {
+#ifdef USE_LSTAT
+ if (diractive) {
+ x = lstat(s,&buffer);
+ debug(F101,"STAT","",12);
+ debug(F101,"zfcdat lstat","",x);
+ } else {
+#endif /* USE_LSTAT */
+ x = stat(s,&buffer);
+ debug(F101,"STAT","",13);
+ debug(F101,"zfcdat stat","",x);
+#ifdef USE_LSTAT
+ }
+#endif /* USE_LSTAT */
+ if (x != 0) {
+#ifdef USE_LSTAT
+ debug(F111,"zfcdat stat failed",s,errno);
+#else
+ debug(F111,"zfcdat lstat failed",s,errno);
+#endif /* USE_LSTAT */
+ return("");
+ }
+ debug(F101,"zfcdat buffer.st_mtime","",buffer.st_mtime);
+ mtime = buffer.st_mtime;
+ }
+ return(zdtstr(mtime));
+#else
+ return("");
+#endif /* TIMESTAMP */
+}
+
+#ifndef NOTIMESTAMP
+
+/* Z S T R D T -- Converts local date string to internal representation */
+/*
+ In our case (UNIX) this is seconds since midnite 1 Jan 1970 UTC,
+ suitable for comparison with UNIX file dates. As far as I know, there is
+ no library or system call -- at least nothing reasonably portable -- to
+ convert local time to UTC.
+*/
+time_t
+zstrdt(date,len) char * date; int len; {
+#ifdef M_UNIX
+/*
+ SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
+ ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
+ dependence on the XPG4 supplement presence. So always use
+ what the system header file supplies in ODT 3.0...
+*/
+#ifndef ODT30
+#ifndef _SCO_DS
+ extern void ftime(); /* extern void ftime(struct timeb *) */
+#endif /* _SCO_DS */
+#endif /* ODT30 */
+#else
+#ifndef M_XENIX
+ extern int ftime();
+#endif /* M_XENIX */
+#endif /* M_UNIX */
+ extern struct tm * localtime();
+
+ /* And this should have been declared always through a header file */
+#ifdef HPUX10
+ time_t tmx;
+ long days;
+#else
+#ifdef BSD44
+ time_t tmx;
+ long days;
+#else
+ long tmx, days;
+#endif /* BSD44 */
+#endif /* HPUX10 */
+ int i, n, isleapyear;
+ /* J F M A M J J A S O N D */
+ /* 31 28 31 30 31 30 31 31 30 31 30 31 */
+ static
+ int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
+ char s[5];
+ struct tm *time_stamp;
+
+#ifdef BSD44
+ struct timeval tp[2];
+ long xtimezone = 0L;
+#else
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2]; /* New access and modificaton time */
+ } tp;
+ char *tz;
+ long timezone; /* In case timezone not defined in .h file */
+#else
+#ifdef SYSUTIMEH
+ struct utimbuf tp;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+#ifdef ANYBSD
+ long timezone = 0L;
+ static struct timeb tbp;
+#endif /* ANYBSD */
+
+#ifdef BEBOX
+ long timezone = 0L;
+#endif /* BEBOX */
+
+ debug(F111,"zstrdt",date,len);
+
+ if ((len == 0)
+ || (len != 17)
+ || (date[8] != ' ')
+ || (date[11] != ':')
+ || (date[14] != ':') ) {
+ debug(F111,"Bad creation date ",date,len);
+ return(-1);
+ }
+ debug(F111,"zstrdt date check 1",date,len);
+ for(i = 0; i < 8; i++) {
+ if (!isdigit(date[i])) {
+ debug(F111,"Bad creation date ",date,len);
+ return(-1);
+ }
+ }
+ debug(F111,"zstrdt date check 2",date,len);
+ i++;
+
+ for (; i < 16; i += 3) {
+ if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
+ debug(F111,"Bad creation date ",date,len);
+ return(-1);
+ }
+ }
+ debug(F111,"zstrdt date check 3",date,len);
+
+
+#ifdef COMMENT /* was BSD44 */
+/*
+ man gettimeofday on BSDI 3.1 says:
+ "The timezone field is no longer used; timezone information is stored out-
+ side the kernel. See ctime(3) for more information." So this chunk of
+ code is effectively a no-op, at least in BSDI 3.x.
+*/
+ {
+ int x;
+ struct timezone tzp;
+ x = gettimeofday(NULL, &tzp);
+ debug(F101,"zstrdt BSD44 gettimeofday","",x);
+ if (x > -1)
+ xtimezone = tzp.tz_minuteswest * 60L;
+ else
+ xtimezone = 0L;
+ debug(F101,"zstrdt BSD44 timezone","",xtimezone);
+ }
+#else
+#ifdef ANYBSD
+ debug(F100,"zstrdt BSD calling ftime","",0);
+ ftime(&tbp);
+ debug(F100,"zstrdt BSD back from ftime","",0);
+ timezone = tbp.timezone * 60L;
+ debug(F101,"zstrdt BSD timezone","",timezone);
+#else
+#ifdef SVORPOSIX
+ tzset(); /* Set timezone */
+#else
+#ifdef V7
+ if ((tz = getenv("TZ")) == NULL)
+ timezone = 0; /* UTC/GMT */
+ else
+ timezone = atoi(&tz[3]); /* Set 'timezone'. */
+ timezone *= 60L;
+#endif /* V7 */
+#endif /* SVORPOSIX */
+#endif /* ANYBSD */
+#endif /* COMMENT (was BSD44) */
+
+ debug(F100,"zstrdt so far so good","",0);
+
+ s[4] = '\0';
+ for (i = 0; i < 4; i++) /* Fix the year */
+ s[i] = date[i];
+
+ n = atoi(s);
+ debug(F111,"zstrdt year",s,n);
+ if (n < 1970) {
+ debug(F100,"zstrdt fails - year","",n);
+ return(-1);
+ }
+
+/* Previous year's leap days. This won't work after year 2100. */
+
+ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
+ days = (long) (n - 1970) * 365;
+ days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
+
+ s[2] = '\0';
+
+ for (i = 4; i < 16; i += 2) {
+ s[0] = date[i];
+ s[1] = date[i + 1];
+ n = atoi(s);
+ switch (i) {
+ case 4: /* MM: month */
+ if ((n < 1 ) || ( n > 12)) {
+ debug(F111,"zstrdt 4 bad date ",date,len);
+ return(-1);
+ }
+ days += monthdays [n];
+ if (isleapyear && n > 2)
+ ++days;
+ continue;
+
+ case 6: /* DD: day */
+ if ((n < 1 ) || ( n > 31)) {
+ debug(F111,"zstrdt 6 bad date ",date,len);
+ return(-1);
+ }
+ tmx = (days + n - 1) * 24L * 60L * 60L;
+ i++; /* Skip the space */
+ continue;
+
+ case 9: /* hh: hour */
+ if ((n < 0 ) || ( n > 23)) {
+ debug(F111,"zstrdt 9 bad date ",date,len);
+ return(-1);
+ }
+ tmx += n * 60L * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 12: /* mm: minute */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zstrdt 12 bad date ",date,len);
+ return(-1);
+ }
+#ifdef COMMENT /* (was BSD44) */ /* Correct for time zone */
+ tmx += xtimezone;
+ debug(F101,"zstrdt BSD44 tmx","",tmx);
+#else
+#ifdef ANYBSD
+ tmx += timezone;
+#else
+#ifndef CONVEX9 /* Don't yet know how to do this here */
+#ifdef ultrix
+ tmx += (long) timezone;
+#else
+#ifdef Plan9
+ {
+ extern time_t tzoffset;
+ tmx += tzoffset;
+ }
+#else
+#ifndef BSD44
+ tmx += timezone;
+#endif /* BSD44 */
+#endif /* Plan9 */
+#endif /* ultrix */
+#endif /* CONVEX9 */
+#endif /* ANYBSD */
+#endif /* COMMENT (was BSD44) */
+ tmx += n * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 15: /* ss: second */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zstrdt 15 bad date ",date,len);
+ return(-1);
+ }
+ tmx += n;
+ }
+ time_stamp = localtime(&tmx);
+ debug(F101,"zstrdt tmx 1","",tmx);
+ if (!time_stamp)
+ return(-1);
+#ifdef COMMENT
+ /* Why was this here? */
+ time_stamp = localtime(&tmx);
+ debug(F101,"zstrdt tmx 2","",tmx);
+#endif /* COMMENT */
+#ifdef BSD44
+ { /* New to 7.0 - Works in at at least BSDI 3.1 and FreeBSD 2.2.7 */
+ long zz;
+ zz = time_stamp->tm_gmtoff; /* Seconds away from Zero Meridian */
+ debug(F101,"zstrdt BSD44 tm_gmtoff","",zz);
+ tmx -= zz;
+ debug(F101,"zstrdt BSD44 tmx 3 (GMT)","",tmx);
+ }
+#else
+ /*
+ Daylight Savings Time adjustment.
+ Do this everywhere BUT in BSD44 because in BSD44,
+ tm_gmtoff also includes the DST adjustment.
+ */
+ if (time_stamp->tm_isdst) {
+ tmx -= 60L * 60L;
+ debug(F101,"zstrdt tmx 3 (DST)","",tmx);
+ }
+#endif /* BSD44 */
+ n = time_stamp->tm_year;
+ if (n < 300) {
+ n += 1900;
+ }
+ }
+ return(tmx);
+}
+
+
+#ifdef ZLOCALTIME
+/* Z L O C A L T I M E -- GMT/UTC time string to local time string */
+
+/*
+ Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time.
+ Returns: "yyyymmdd hh:mm:ss" local date-time on success, NULL on failure.
+*/
+static char zltimbuf[64];
+
+char *
+zlocaltime(gmtstring) char * gmtstring; {
+#ifdef M_UNIX
+/*
+ SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
+ ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
+ dependence on the XPG4 supplement presence. So always use
+ what the system header file supplies in ODT 3.0...
+*/
+#ifndef ODT30
+#ifndef _SCO_DS
+ extern void ftime(); /* extern void ftime(struct timeb *) */
+#endif /* _SCO_DS */
+#endif /* ODT30 */
+#else
+#ifndef M_XENIX
+ extern int ftime();
+#endif /* M_XENIX */
+#endif /* M_UNIX */
+ extern struct tm * localtime();
+
+ /* And this should have been declared always through a header file */
+#ifdef HPUX10
+ time_t tmx;
+ long days;
+#else
+#ifdef BSD44
+ time_t tmx;
+ long days;
+#else
+ long tmx, days;
+#endif /* BSD44 */
+#endif /* HPUX10 */
+ int i, n, x, isleapyear;
+ /* J F M A M J J A S O N D */
+ /* 31 28 31 30 31 30 31 31 30 31 30 31 */
+ static
+ int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
+ char s[5];
+ struct tm *time_stamp;
+
+#ifdef BSD44
+ struct timeval tp[2];
+#else
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2]; /* New access and modificaton time */
+ } tp;
+#else
+#ifdef SYSUTIMEH
+ struct utimbuf tp;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+#ifdef ANYBSD
+ static struct timeb tbp;
+#endif /* ANYBSD */
+
+ char * date = gmtstring;
+ int len;
+
+ len = strlen(date);
+ debug(F111,"zlocaltime",date,len);
+
+ if ((len == 0)
+ || (len != 17)
+ || (date[8] != ' ')
+ || (date[11] != ':')
+ || (date[14] != ':') ) {
+ debug(F111,"Bad creation date ",date,len);
+ return(NULL);
+ }
+ debug(F111,"zlocaltime date check 1",date,len);
+ for(i = 0; i < 8; i++) {
+ if (!isdigit(date[i])) {
+ debug(F111,"Bad creation date ",date,len);
+ return(NULL);
+ }
+ }
+ debug(F111,"zlocaltime date check 2",date,len);
+ i++;
+
+ for (; i < 16; i += 3) {
+ if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
+ debug(F111,"Bad creation date ",date,len);
+ return(NULL);
+ }
+ }
+ debug(F111,"zlocaltime date check 3",date,len);
+
+ debug(F100,"zlocaltime so far so good","",0);
+
+ s[4] = '\0';
+ for (i = 0; i < 4; i++) /* Fix the year */
+ s[i] = date[i];
+
+ n = atoi(s);
+ debug(F111,"zlocaltime year",s,n);
+ if (n < 1970) {
+ debug(F100,"zlocaltime fails - year","",n);
+ return(NULL);
+ }
+
+/* Previous year's leap days. This won't work after year 2100. */
+
+ isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
+ days = (long) (n - 1970) * 365;
+ days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
+
+ s[2] = '\0';
+
+ for (i = 4; i < 16; i += 2) {
+ s[0] = date[i];
+ s[1] = date[i + 1];
+ n = atoi(s);
+ switch (i) {
+ case 4: /* MM: month */
+ if ((n < 1 ) || ( n > 12)) {
+ debug(F111,"zlocaltime 4 bad date ",date,len);
+ return(NULL);
+ }
+ days += monthdays [n];
+ if (isleapyear && n > 2)
+ ++days;
+ continue;
+
+ case 6: /* DD: day */
+ if ((n < 1 ) || ( n > 31)) {
+ debug(F111,"zlocaltime 6 bad date ",date,len);
+ return(NULL);
+ }
+ tmx = (days + n - 1) * 24L * 60L * 60L;
+ i++; /* Skip the space */
+ continue;
+
+ case 9: /* hh: hour */
+ if ((n < 0 ) || ( n > 23)) {
+ debug(F111,"zlocaltime 9 bad date ",date,len);
+ return(NULL);
+ }
+ tmx += n * 60L * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 12: /* mm: minute */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zlocaltime 12 bad date ",date,len);
+ return(NULL);
+ }
+ tmx += n * 60L;
+ i++; /* Skip the colon */
+ continue;
+
+ case 15: /* ss: second */
+ if ((n < 0 ) || ( n > 59)) {
+ debug(F111,"zlocaltime 15 bad date ",date,len);
+ return(NULL);
+ }
+ tmx += n;
+ }
+
+/*
+ At this point tmx is the time_t representation of the argument date-time
+ string without any timezone or DST adjustments. Therefore it should be
+ the same as the time_t representation of the GMT/UTC time. Now we should
+ be able to feed it to localtime() and have it converted to a struct tm
+ representing the local time equivalent of the given UTC time.
+*/
+ time_stamp = localtime(&tmx);
+ if (!time_stamp)
+ return(NULL);
+ }
+
+/* Now we simply reformat the struct tm to a string */
+
+ x = time_stamp->tm_year;
+ if (time_stamp->tm_year < 70 || time_stamp->tm_year > 8099)
+ return(NULL);
+ if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
+ return(NULL);
+ if (time_stamp->tm_mday < 1 || time_stamp->tm_mday > 31)
+ return(NULL);
+ if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 24)
+ return(NULL);
+ if (time_stamp->tm_min < 0 || time_stamp->tm_min > 60)
+ return(NULL);
+ if (time_stamp->tm_sec < 0 || time_stamp->tm_sec > 60)
+ return(NULL);
+ sprintf(zltimbuf,"%04d%02d%02d %02d:%02d:%02d",
+ time_stamp->tm_year + 1900,
+ time_stamp->tm_mon + 1,
+ time_stamp->tm_mday,
+ time_stamp->tm_hour,
+ time_stamp->tm_min,
+ time_stamp->tm_sec
+ );
+ return((char *)zltimbuf);
+}
+#endif /* ZLOCALTIME */
+#endif /* NOTIMESTAMP */
+
+/* Z S T I M E -- Set modification date/time+permissions for incoming file */
+/*
+ Call with:
+ f = pointer to name of existing file.
+ yy = pointer to a Kermit file attribute structure in which yy->date.val
+ is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
+ yy->lprotect.val & yy->gprotect.val are permission/protection values.
+ x = is a function code: 0 means to set the file's attributes as given.
+ 1 means compare the date in struct yy with the file creation date.
+ Returns:
+ -1 on any kind of error.
+ 0 if x is 0 and the attributes were set successfully.
+ 0 if x is 1 and date from attribute structure <= file creation date.
+ 1 if x is 1 and date from attribute structure > file creation date.
+*/
+int
+zstime(f,yy,x)
+ char *f; struct zattr *yy; int x;
+/* zstime */ {
+ int r = -1; /* Return code */
+#ifdef CK_PERMS
+ int setperms = 0;
+#endif /* CK_PERMS */
+ int setdate = 0;
+
+/* It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se. */
+
+#ifdef TIMESTAMP
+#ifdef BSD44
+ extern int utimes();
+#else
+ extern int utime();
+#endif /* BSD44 */
+
+ struct stat sb;
+
+/* At least, the declarations for int functions are not needed anyway */
+
+#ifdef BSD44
+ struct timeval tp[2];
+ long xtimezone;
+#else
+#ifdef V7
+ struct utimbuf {
+ time_t timep[2]; /* New access and modificaton time */
+ } tp;
+ char *tz;
+ long timezone; /* In case not defined in .h file */
+#else
+#ifdef SYSUTIMEH
+ struct utimbuf tp;
+#else
+ struct utimbuf {
+ time_t atime;
+ time_t mtime;
+ } tp;
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+ long tm = 0L;
+
+ if (!f) f = "";
+ if (!*f) return(-1);
+ if (!yy) return(-1);
+
+ debug(F110,"zstime",f,0);
+ debug(F111,"zstime date",yy->date.val,yy->date.len);
+
+#ifdef CKROOT
+ debug(F111,"zstime setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zstime setroot violation",f,0);
+ return(0);
+ }
+#endif /* CKROOT */
+
+ if (yy->date.len == 0) { /* No date in struct */
+ if (yy->lprotect.len != 0) { /* So go do permissions */
+ goto zsperms;
+ } else {
+ debug(F100,"zstime: nothing to do","",0);
+ return(0);
+ }
+ }
+ if ((tm = zstrdt(yy->date.val,yy->date.len)) < 0) {
+ debug(F101,"zstime: zstrdt fails","",0);
+ return(-1);
+ }
+ debug(F101,"zstime: tm","",tm);
+ debug(F111,"zstime: A-pkt date ok ",yy->date.val,yy->date.len);
+
+ if (stat(f,&sb)) { /* Get the time for the file */
+ debug(F101,"STAT","",14);
+ debug(F111,"zstime: Can't stat file:",f,errno);
+ return(-1);
+ }
+ debug(F101,"STAT","",15);
+ setdate = 1;
+
+ zsperms:
+#ifdef CK_PERMS
+ {
+ int i, x = 0, xx, flag = 0;
+ char * s;
+#ifdef DEBUG
+ char obuf[24];
+ if (deblog) {
+ debug(F111,"zstime lperms",yy->lprotect.val,yy->lprotect.len);
+ debug(F111,"zstime gperms",yy->gprotect.val,yy->gprotect.len);
+ debug(F110,"zstime system id",yy->systemid.val,0);
+ sprintf(obuf,"%o",sb.st_mode);
+ debug(F110,"zstime file perms before",obuf,0);
+ }
+#endif /* DEBUG */
+
+#ifdef CK_LOGIN
+ debug(F101,"zstime isguest","",isguest);
+ debug(F101,"zstime ckxperms","",ckxperms);
+ if (isguest) {
+#ifdef COMMENT
+ /* Clear owner permissions */
+ sb.st_mode &= (unsigned) 0177077; /* (16 bits) */
+#else
+ /* Set permissions from ckxperms variable */
+ sb.st_mode = ckxperms;
+#endif /* COMMENT */
+ debug(F101,"zstime isguest sb.st_mode","",sb.st_mode);
+#ifdef COMMENT
+ /* We already set them in zopeno() */
+ setperms = 1;
+#endif /* COMMENT */
+ flag = 0;
+ } else
+#endif /* CK_LOGIN */
+ if ((yy->lprotect.len > 0 && /* Have local-format permissions */
+ yy->systemid.len > 0 && /* from A-packet... */
+#ifdef UNIX
+ !strcmp(yy->systemid.val,"U1") /* AND you are same as me */
+#else
+ 0
+#endif /* UNIX */
+ ) || (yy->lprotect.len < 0) /* OR by inheritance from old file */
+ ) {
+ flag = 1;
+ s = yy->lprotect.val; /* UNIX filemode */
+ xx = yy->lprotect.len;
+ if (xx < 0) /* len < 0 means inheritance */
+ xx = 0 - xx;
+ for (i = 0; i < xx; i++) { /* Decode octal string */
+ if (*s <= '7' && *s >= '0') {
+ x = 8 * x + (int)(*s) - '0';
+ } else {
+ flag = 0;
+ break;
+ }
+ s++;
+ }
+#ifdef DEBUG
+ sprintf(obuf,"%o",x);
+ debug(F110,"zstime octal lperm",obuf,0);
+#endif /* DEBUG */
+ } else if (!flag && yy->gprotect.len > 0) {
+ int g;
+#ifdef CK_SCO32V4
+ mode_t mask;
+#else
+ int mask;
+#endif /* CK_SCO32V4 */
+ mask = umask(0); /* Get umask */
+ debug(F101,"zstime mask 1","",mask);
+ umask(mask); /* Put it back */
+ mask ^= 0777; /* Flip the bits */
+ debug(F101,"zstime mask 2","",mask);
+ g = xunchar(*(yy->gprotect.val)); /* Decode generic protection */
+ debug(F101,"zstime gprotect","",g);
+#ifdef S_IRUSR
+ debug(F100,"zstime S_IRUSR","",0);
+ if (g & 1) x |= S_IRUSR; /* Read permission */
+ flag = 1;
+#endif /* S_IRUSR */
+#ifdef S_IWUSR
+ debug(F100,"zstime S_IWUSR","",0);
+ if (g & 2) x |= S_IWUSR; /* Write permission */
+ if (g & 16) x |= S_IWUSR; /* Delete permission */
+ flag = 1;
+#endif /* S_IWUSR */
+#ifdef S_IXUSR
+ debug(F100,"zstime S_IXUSR","",0);
+ if (g & 4) /* Has execute permission bit */
+ x |= S_IXUSR;
+ else /* Doesn't have it */
+ mask &= 0666; /* so also clear it out of mask */
+ flag = 1;
+#endif /* S_IXUSR */
+ debug(F101,"zstime mask x","",x);
+ x |= mask;
+ debug(F101,"zstime mask x|mask","",x);
+ }
+ debug(F101,"zstime flag","",flag);
+ if (flag) {
+#ifdef S_IFMT
+ debug(F101,"zstime S_IFMT x","",x);
+ sb.st_mode = (sb.st_mode & S_IFMT) | x;
+ setperms = 1;
+#else
+#ifdef _IFMT
+ debug(F101,"zstime _IFMT x","",x);
+ sb.st_mode = (sb.st_mode & _IFMT) | x;
+ setperms = 1;
+#endif /* _IFMT */
+#endif /* S_IFMT */
+ }
+#ifdef DEBUG
+ sprintf(obuf,"%04o",sb.st_mode);
+ debug(F111,"zstime file perms after",obuf,setperms);
+#endif /* DEBUG */
+ }
+#endif /* CK_PERMS */
+
+ debug(F101,"zstime: sb.st_atime","",sb.st_atime);
+
+#ifdef BSD44
+ tp[0].tv_sec = sb.st_atime; /* Access time first */
+ tp[1].tv_sec = tm; /* Update time second */
+ debug(F100,"zstime: BSD44 modtime","",0);
+#else
+#ifdef V7
+ tp.timep[0] = tm; /* Set modif. time to creation date */
+ tp.timep[1] = sb.st_atime; /* Don't change the access time */
+ debug(F100,"zstime: V7 modtime","",0);
+#else
+#ifdef SYSUTIMEH
+ tp.modtime = tm; /* Set modif. time to creation date */
+ tp.actime = sb.st_atime; /* Don't change the access time */
+ debug(F100,"zstime: SYSUTIMEH modtime","",0);
+#else
+ tp.mtime = tm; /* Set modif. time to creation date */
+ tp.atime = sb.st_atime; /* Don't change the access time */
+ debug(F100,"zstime: default modtime","",0);
+#endif /* SYSUTIMEH */
+#endif /* V7 */
+#endif /* BSD44 */
+
+ switch (x) { /* Execute desired function */
+ case 0: /* Set the creation date of the file */
+#ifdef CK_PERMS /* And permissions */
+/*
+ NOTE: If we are inheriting permissions from a previous file, and the
+ previous file was a directory, this would turn the new file into a directory
+ too, but it's not, so we try to unset the right bit. Luckily, this code
+ will probably never be executed since the upper level modules do not allow
+ reception of a file that has the same name as a directory.
+
+ NOTE 2: We change the permissions *before* we change the modification time,
+ otherwise changing the permissions would set the mod time to the present
+ time.
+*/
+ {
+ int x;
+ debug(F101,"zstime setperms","",setperms);
+ if (S_ISDIR(sb.st_mode)) {
+ debug(F101,"zstime DIRECTORY bit on","",sb.st_mode);
+ sb.st_mode ^= 0040000;
+ debug(F101,"zstime DIRECTORY bit off","",sb.st_mode);
+ }
+ if (setperms) {
+ x = chmod(f,sb.st_mode);
+ debug(F101,"zstime chmod","",x);
+ }
+ }
+ if (x < 0) return(-1);
+#endif /* CK_PERMS */
+
+ if (!setdate) /* We don't have a date */
+ return(0); /* so skip the following... */
+
+ if (
+#ifdef BSD44
+ utimes(f,tp)
+#else
+ utime(f,&tp)
+#endif /* BSD44 */
+ ) { /* Fix modification time */
+ debug(F111,"zstime 0: can't set modtime for file",f,errno);
+ r = -1;
+ } else {
+ /* Including the modtime here is not portable */
+ debug(F110,"zstime 0: modtime set for file",f,0);
+ r = 0;
+ }
+ break;
+
+ case 1: /* Compare the dates */
+/*
+ This was st_atime, which was wrong. We want the file-data modification
+ time, st_mtime.
+*/
+ debug(F111,"zstime 1: compare",f,sb.st_mtime);
+ debug(F111,"zstime 1: compare","packet",tm);
+
+ r = (sb.st_mtime < tm) ? 0 : 1;
+ break;
+
+ default: /* Error */
+ r = -1;
+ }
+#endif /* TIMESTAMP */
+ return(r);
+}
+
+/* Find initialization file. */
+
+#ifdef NOTUSED
+int
+zkermini() {
+/* nothing here for Unix. This function added for benefit of VMS Kermit. */
+ return(0);
+}
+#endif /* NOTUSED */
+
+#ifndef UNIX
+/* Historical -- not used in Unix any more (2001-11-03) */
+#ifndef NOFRILLS
+int
+zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */
+/*
+ Returns 0 on success
+ 2 if mail delivered but temp file can't be deleted
+ -2 if mail can't be delivered
+ -1 on file access error
+ The UNIX version always returns 0 because it can't get a good return
+ code from zsyscmd.
+*/
+ int n;
+
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-2);
+#endif /* CK_LOGIN */
+
+ if (!f) f = "";
+ if (!*f) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zmail setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zmail setroot violation",f,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+#ifdef BSD4
+/* The idea is to use /usr/ucb/mail, rather than regular mail, so that */
+/* a subject line can be included with -s. Since we can't depend on the */
+/* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
+/* and even if Mail has been moved to somewhere else, this should still */
+/* find it... The search could be made more reliable by actually using */
+/* access() to see if /usr/ucb/Mail exists. */
+
+ n = strlen(f);
+ n = n + n + 15 + (int)strlen(p);
+
+ if (n > ZMBUFLEN)
+ return(-2);
+
+#ifdef DGUX540
+ sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
+#else
+ sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
+#endif /* DGUX540 */
+ zsyscmd(zmbuf);
+#else
+#ifdef SVORPOSIX
+#ifndef OXOS
+ sprintf(zmbuf,"mail %s < %s", p, f);
+#else /* OXOS */
+ sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
+#endif /* OXOS */
+ zsyscmd(zmbuf);
+#else
+ *zmbuf = '\0';
+#endif
+#endif
+ return(0);
+}
+#endif /* NOFRILLS */
+#endif /* UNIX */
+
+#ifndef NOFRILLS
+int
+zprint(p,f) char *p; char *f; { /* Print file f with options p */
+ extern char * printername; /* From ckuus3.c */
+ extern int printpipe;
+ int n;
+
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-2);
+#endif /* CK_LOGIN */
+
+ if (!f) f = "";
+ if (!*f) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zprint setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(f)) {
+ debug(F110,"zprint setroot violation",f,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ debug(F110,"zprint file",f,0);
+ debug(F110,"zprint flags",p,0);
+ debug(F110,"zprint printername",printername,0);
+ debug(F101,"zprint printpipe","",printpipe);
+
+#ifdef UNIX
+/*
+ Note use of standard input redirection. In some systems, lp[r] runs
+ setuid to lp (or ...?), so if user has sent a file into a directory
+ that lp does not have read access to, it can't be printed unless it is
+ fed to lp[r] as standard input.
+*/
+ if (printpipe && printername) {
+ n = 8 + (int)strlen(f) + (int)strlen(printername);
+ if (n > ZMBUFLEN)
+ return(-2);
+ sprintf(zmbuf,"cat %s | %s", f, printername);
+ } else if (printername) {
+ n = 8 + (int)strlen(f) + (int)strlen(printername);
+ if (n > ZMBUFLEN)
+ return(-2);
+ sprintf(zmbuf,"cat %s >> %s", f, printername);
+ } else {
+ n = 4 + (int)strlen(PRINTCMD) + (int)strlen(p) + (int)strlen(f);
+ if (n > ZMBUFLEN)
+ return(-2);
+ sprintf(zmbuf,"%s %s < %s", PRINTCMD, p, f);
+ }
+ debug(F110,"zprint command",zmbuf,0);
+ zsyscmd(zmbuf);
+#else /* Not UNIX */
+ *zmbuf = '\0';
+#endif /* UNIX */
+ return(0);
+}
+#endif /* NOFRILLS */
+
+/* Wildcard expansion functions... */
+
+static char scratch[MAXPATH+4]; /* Used by both methods */
+
+static int oldmtchs = 0; /* Let shell (ls) expand them. */
+#ifdef COMMENT
+static char *lscmd = "/bin/ls -d"; /* Command to use. */
+#else
+static char *lscmd = "echo"; /* Command to use. */
+#endif /* COMMENT */
+
+#ifndef NOPUSH
+int
+shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
+ char *fgbuf = NULL; /* Buffer for forming ls command */
+ char *p, *q; /* Workers */
+
+ int i, x, retcode, itsadir;
+ char c;
+
+ x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
+ for (i = 0; i < oldmtchs; i++) { /* Free previous file list */
+ if (namlst[i] ) { /* If memory is allocated */
+ free(namlst[i]); /* Free the memory */
+ namlst[i] = NULL ; /* Remember no memory is allocated */
+ }
+ }
+ oldmtchs = 0 ; /* Remember there are no matches */
+ fgbuf = malloc(x); /* Get buffer for command */
+ if (!fgbuf) return(-1); /* Fail if cannot */
+ ckmakmsg(fgbuf,x,lscmd," ",pat,NULL); /* Form the command */
+ zxcmd(ZIFILE,fgbuf); /* Start the command */
+ i = 0; /* File counter */
+ p = scratch; /* Point to scratch area */
+ retcode = -1; /* Assume failure */
+ while ((x = zminchar()) != -1) { /* Read characters from command */
+ c = (char) x;
+ if (c == ' ' || c == '\n') { /* Got newline or space? */
+ *p = '\0'; /* Yes, terminate string */
+ p = scratch; /* Point back to beginning */
+ if (zchki(p) == -1) /* Does file exist? */
+ continue; /* No, continue */
+ itsadir = isdir(p); /* Yes, is it a directory? */
+ if (xdironly && !itsadir) /* Want only dirs but this isn't */
+ continue; /* so skip. */
+ if (xfilonly && itsadir) /* It's a dir but want only files */
+ continue; /* so skip. */
+ x = (int)strlen(p); /* Keep - get length of name */
+ q = malloc(x+1); /* Allocate space for it */
+ if (!q) goto shxfin; /* Fail if space can't be obtained */
+ strcpy(q,scratch); /* (safe) Copy name to space */
+ namlst[i++] = q; /* Copy pointer to name into array */
+ if (i >= len) goto shxfin; /* Fail if too many */
+ } else { /* Regular character */
+ *p++ = c; /* Copy it into scratch area */
+ }
+ }
+ retcode = i; /* Return number of matching files */
+shxfin: /* Common exit point */
+ free(fgbuf); /* Free command buffer */
+ fgbuf = NULL;
+ zclosf(ZIFILE); /* Delete the command fork. */
+ oldmtchs = i; /* Remember how many files */
+ return(retcode);
+}
+#endif /* NOPUSH */
+
+/*
+ Directory-reading functions for UNIX originally written for C-Kermit 4.0
+ by Jeff Damens, CUCCA, 1984.
+*/
+static char * xpat = NULL; /* Global copy of fgen() pattern */
+static char * xpatlast = NULL; /* Rightmost segment of pattern*/
+static int xpatslash = 0; /* Slash count in pattern */
+static int xpatwild = 0; /* Original pattern is wild */
+static int xleafwild = 0; /* Last segment of pattern is wild */
+static int xpatabsolute = 0;
+
+#ifdef aegis
+static char bslash;
+#endif /* aegis */
+
+
+/* S P L I T P A T H */
+
+/*
+ Splits the slash-separated portions of the argument string into
+ a list of path structures. Returns the head of the list. The
+ structures are allocated by malloc, so they must be freed.
+ Splitpath is used internally by the filename generator.
+
+ Input:
+ A path string.
+
+ Returns:
+ A linked list of the slash-separated segments of the input.
+*/
+static struct path *
+splitpath(p) char *p; {
+ struct path *head,*cur,*prv;
+ int i;
+
+ debug(F111,"splitpath",p,xrecursive);
+ head = prv = NULL;
+
+ if (!p) return(NULL);
+ if (!*p) return(NULL);
+
+ if (!strcmp(p,"**")) { /* Fix this */
+ p = "*";
+ }
+ if (ISDIRSEP(*p)) p++; /* Skip leading slash if any */
+
+ /* Make linked list of path segments from pattern */
+
+ while (*p) {
+ cur = (struct path *) malloc(sizeof (struct path));
+ debug(F101,"splitpath malloc","",cur);
+ if (cur == NULL) {
+ debug(F100,"splitpath malloc failure","",0);
+ prv -> fwd = NULL;
+ return((struct path *)NULL);
+ }
+ cur -> fwd = NULL;
+ if (head == NULL) /* First, make list head */
+ head = cur;
+ else /* Not first, link into chain */
+ prv -> fwd = cur;
+ prv = cur; /* Link from previous to this one */
+
+#ifdef aegis
+ /* treat backslash as "../" */
+ if (bslash && *p == bslash) {
+ strcpy(cur->npart, ".."); /* safe */
+ ++p;
+ } else {
+ for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
+ cur -> npart[i] = *p++;
+ cur -> npart[i] = '\0'; /* end this segment */
+ if (i >= MAXNAMLEN)
+ while (*p && *p != '/' && *p != bslash)
+ p++;
+ }
+ if (*p == '/') p++;
+#else
+ /* General case (UNIX) */
+ for (i = 0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
+ cur -> npart[i] = *p++;
+ }
+
+ cur -> npart[i] = '\0'; /* End this path segment */
+ if (i >= MAXNAMLEN)
+ while (!ISDIRSEP(*p) && *p != '\0') p++;
+ if (ISDIRSEP(*p))
+ p++;
+
+#endif /* aegis */
+ }
+ if (prv) {
+ makestr(&xpatlast,prv -> npart);
+ debug(F110,"splitpath xpatlast",xpatlast,0);
+ }
+#ifdef DEBUG
+ /* Show original path list */
+ if (deblog) {
+ for (i = 0, cur = head; cur; i++) {
+ debug(F111,"SPLITPATH",cur -> npart, i);
+ cur = cur -> fwd;
+ }
+ }
+#endif /* DEBUG */
+ return(head);
+}
+
+/* F G E N -- Generate File List */
+
+/*
+ File name generator. It is passed a string, possibly containing wildcards,
+ and an array of character pointers. It finds all the matching filenames and
+ stores pointers to them in the array. The returned strings are allocated
+ from a static buffer local to this module (so the caller doesn't have to
+ worry about deallocating them); this means that successive calls to fgen
+ will wipe out the results of previous calls.
+
+ Input:
+ A wildcard string, an array to write names to, the length of the array.
+
+ Returns:
+ The number of matches.
+ The array is filled with filenames that matched the pattern.
+ If there wasn't enough room in the array, -1 is returned.
+
+ Originally by: Jeff Damens, CUCCA, 1984. Many changes since then.
+*/
+static int
+fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
+ struct path *head;
+ char *sptr, *s;
+ int n;
+
+#ifdef aegis
+ char *namechars;
+ int tilde = 0, bquote = 0;
+
+ if ((namechars = getenv("NAMECHARS")) != NULL) {
+ if (ckstrchr(namechars, '~' ) != NULL) tilde = '~';
+ if (ckstrchr(namechars, '\\') != NULL) bslash = '\\';
+ if (ckstrchr(namechars, '`' ) != NULL) bquote = '`';
+ } else {
+ tilde = '~'; bslash = '\\'; bquote = '`';
+ }
+ sptr = scratch;
+
+ /* copy "`node_data", etc. anchors */
+ if (bquote && *pat == bquote)
+ while (*pat && *pat != '/' && *pat != bslash)
+ *sptr++ = *pat++;
+ else if (tilde && *pat == tilde)
+ *sptr++ = *pat++;
+ while (*pat == '/')
+ *sptr++ = *pat++;
+ if (sptr == scratch) {
+ strcpy(scratch,"./"); /* safe */
+ sptr = scratch+2;
+ }
+ if (!(head = splitpath(pat))) return(-1);
+
+#else /* not aegis */
+
+ debug(F111,"fgen pat",pat,len);
+ debug(F110,"fgen current directory",zgtdir(),0);
+ debug(F101,"fgen stathack","",stathack);
+
+ scratch[0] = '\0';
+ xpatwild = 0;
+ xleafwild = 0;
+ xpatabsolute = 0;
+
+ if (!(head = splitpath(pat))) /* Make the path segment list */
+ return(-1);
+
+ sptr = scratch;
+
+#ifdef COMMENT
+ if (strncmp(pat,"./",2) && strncmp(pat,"../",3)) {
+#endif /* COMMENT */
+ if (!ISDIRSEP(*pat)) /* If name is not absolute */
+ *sptr++ = '.'; /* put "./" in front. */
+ *sptr++ = DIRSEP;
+#ifdef COMMENT
+ }
+#endif /* COMMENT */
+ *sptr = '\0';
+#endif /* aegis */
+
+ makestr(&xpat,pat); /* Save copy of original pattern */
+ debug(F110,"fgen scratch",scratch,0);
+
+ for (n = 0, s = xpat; *s; s++) /* How many slashes in the pattern */
+ if (*s == DIRSEP) /* since these are fences for */
+ n++; /* pattern matching */
+ xpatslash = n;
+ debug(F101,"fgen xpatslash","",xpatslash);
+
+ numfnd = 0; /* None found yet */
+
+ if (initspace(resarry,ssplen) < 0)
+ return(-1);
+
+ xpatwild = iswild(xpat); /* Original pattern is wild? */
+ xpatabsolute = isabsolute(xpat);
+ xleafwild = iswild(xpatlast);
+
+ debug(F111,"fgen xpat",xpat,xpatwild);
+ debug(F111,"fgen xpatlast",xpatlast,xleafwild);
+ debug(F101,"fgen xpatabsolute","",xpatabsolute);
+
+ traverse(head,scratch,sptr); /* Go walk the directory tree. */
+ while (head != NULL) { /* Done - free path segment list. */
+ struct path *next = head -> fwd;
+ free((char *)head);
+ head = next;
+ }
+ debug(F101,"fgen","",numfnd);
+ return(numfnd); /* Return the number of matches */
+}
+
+/* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
+/* LONGFN can also be defined on the cc command line. */
+
+#ifdef BSD29
+#ifndef LONGFN
+#define LONGFN
+#endif
+#endif
+
+#ifdef BSD42
+#ifndef LONGFN
+#define LONGFN
+#endif
+#endif
+
+/*
+ T R A V E R S E -- Traverse a directory tree.
+
+ Walks the directory tree looking for matches to its arguments.
+ The algorithm is, briefly:
+
+ If the current pattern segment contains no wildcards, that
+ segment is added to what we already have. If the name so far
+ exists, we call ourselves recursively with the next segment
+ in the pattern string; otherwise, we just return.
+
+ If the current pattern segment contains wildcards, we open the name
+ we've accumulated so far (assuming it is really a directory), then read
+ each filename in it, and, if it matches the wildcard pattern segment, add
+ that filename to what we have so far and call ourselves recursively on
+ the next segment.
+
+ Finally, when no more pattern segments remain, we add what's accumulated
+ so far to the result array and increment the number of matches.
+
+ Inputs:
+ A pattern path list (as generated by splitpath), a string pointer that
+ points to what we've traversed so far (this can be initialized to "/"
+ to start the search at the root directory, or to "./" to start the
+ search at the current directory), and a string pointer to the end of
+ the string in the previous argument, plus the global "recursive",
+ "xmatchdot", and "xdironly" flags.
+
+ Returns: void, with:
+ mtchs[] containing the array of filename string pointers, and:
+ numfnd containing the number of filenames.
+
+ Although it might be poor practice, the mtchs[] array is revealed to the
+ outside in case it needs it; for example, to be sorted prior to use.
+ (It is poor practice because not all platforms implement file lists the
+ same way; some don't use an array at all.)
+
+ Note that addresult() acts as a second-level filter; due to selection
+ criteria outside of the pattern, it might decline to add files that
+ this routine asks it to, e.g. because we are collecting only directory
+ names but not the names of regular files.
+
+ WARNING: In the course of C-Kermit 7.0 development, this routine became
+ ridiculously complex, in order to meet approximately sixty specific
+ requirements. DON'T EVEN THINK ABOUT MODIFYING THIS ROUTINE! Trust me;
+ it is not possible to fix anything in it without breaking something else.
+ This routine badly needs a total redesign and rewrite. Note: There may
+ be some good applications for realpath() and/or scandir() and/or fts_blah()
+ here, on platforms where they are available.
+*/
+static VOID
+traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
+
+/* Appropriate declarations for directory routines and structures */
+/* #define OPENDIR means to use opendir(), readdir(), closedir() */
+/* If OPENDIR not defined, we use open(), read(), close() */
+
+#ifdef DIRENT /* New way, <dirent.h> */
+#define OPENDIR
+ DIR *fd, *opendir();
+ struct dirent *dirbuf;
+ struct dirent *readdir();
+#else /* !DIRENT */
+#ifdef LONGFN /* Old way, <dir.h> with opendir() */
+#define OPENDIR
+ DIR *fd, *opendir();
+ struct direct *dirbuf;
+#else /* !LONGFN */
+ int fd; /* Old way, <dir.h> with open() */
+ struct direct dir_entry;
+ struct direct *dirbuf = &dir_entry;
+#endif /* LONGFN */
+#endif /* DIRENT */
+ int mopts = 0; /* ckmatch() opts */
+ int depth = 0; /* Directory tree depth */
+
+ char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */
+ int itsadir = 0, segisdir = 0, itswild = 0, mresult, n, x /* , y */ ;
+ struct stat statbuf; /* For file info. */
+
+ debug(F101,"STAT","",16);
+ if (pl == NULL) { /* End of path-segment list */
+ *--endcur = '\0'; /* Terminate string, overwrite trailing slash */
+ debug(F110,"traverse add: end of path segment",sofar,0);
+ addresult(sofar,-1);
+ return;
+ }
+ if (stathack) {
+ /* This speeds up the search a lot and we still get good results */
+ /* but it breaks the tagging of directory names done in addresult */
+ if (xrecursive || xfilonly || xdironly || xpatslash) {
+ itsadir = xisdir(sofar);
+ debug(F101,"STAT","",17);
+ } else
+ itsadir = (strncmp(sofar,"./",2) == 0);
+ } else {
+ itsadir = xisdir(sofar);
+ debug(F101,"STAT","",18);
+ }
+ debug(F111,"traverse entry sofar",sofar,itsadir);
+
+#ifdef CKSYMLINK /* We're doing symlinks? */
+#ifdef USE_LSTAT /* OK to use lstat()? */
+ if (itsadir && xnolinks) { /* If not following symlinks */
+ int x;
+ struct stat buf;
+ x = lstat(sofar,&buf);
+ debug(F111,"traverse lstat 1",sofar,x);
+ if (x > -1 &&
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ )
+ itsadir = 0;
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+
+ if (!xmatchdot && xpatlast[0] == '.')
+ xmatchdot = 1;
+ if (!xmatchdot && xpat[0] == '.' && xpat[1] != '/' && xpat[1] != '.')
+ xmatchdot = 1;
+
+ /* ckmatch() options */
+
+ if (xmatchdot) mopts |= 1; /* Match dot */
+ if (!xrecursive) mopts |= 2; /* Dirsep is fence */
+
+ debug(F111,"traverse entry xpat",xpat,xpatslash);
+ debug(F111,"traverse entry xpatlast",xpatlast,xmatchdot);
+ debug(F110,"traverse entry pl -> npart",pl -> npart,0);
+
+#ifdef RECURSIVE
+ if (xrecursive > 0 && !itsadir) {
+ char * s; /* Recursive descent and this is a regular file */
+ *--endcur = '\0'; /* Terminate string, overwrite trailing slash */
+
+ /* Find the nth slash from the right and match from there... */
+ /* (n == the number of slashes in the original pattern - see fgen) */
+ if (*sofar == '/') {
+ debug(F110,"traverse xpatslash absolute",sofar,0);
+ s = sofar;
+ } else {
+ debug(F111,"traverse xpatslash relative",sofar,xpatslash);
+ for (s = endcur - 1, n = 0; s >= sofar; s--) {
+ if (*s == '/') {
+ if (++n >= xpatslash) {
+ s++;
+ break;
+ }
+ }
+ }
+ }
+#ifndef NOSKIPMATCH
+ /* This speeds things up a bit. */
+ /* If it causes trouble define NOSKIPMATCH and rebuild. */
+ if (xpat[0] == '*' && !xpat[1])
+ x = xmatchdot ? 1 : (s[0] != '.');
+ else
+#endif /* NOSKIPMATCH */
+ x = ckmatch(xpat, s, 1, mopts); /* Match with original pattern */
+ debug(F111,"traverse xpatslash ckmatch",s,x);
+ if (x > 0) {
+ debug(F110,"traverse add: recursive, match, && !isdir",sofar,0);
+ addresult(sofar,itsadir);
+ }
+ return;
+ }
+#endif /* RECURSIVE */
+
+ debug(F111,"traverse sofar 2",sofar,0);
+
+ segisdir = ((pl -> fwd) == NULL) ? 0 : 1;
+ itswild = iswild(pl -> npart);
+
+ debug(F111,"traverse segisdir",sofar,segisdir);
+ debug(F111,"traverse itswild ",pl -> npart,itswild);
+
+#ifdef RECURSIVE
+ if (xrecursive > 0) { /* If recursing and... */
+ if (segisdir && itswild) /* this is a dir and npart is wild */
+ goto blah; /* or... */
+ else if (!xpatabsolute && !xpatwild) /* search object is nonwild */
+ goto blah; /* then go recurse */
+ }
+#endif /* RECURSIVE */
+
+ if (!itswild) { /* This path segment not wild? */
+#ifdef COMMENT
+ strcpy(endcur,pl -> npart); /* (safe) Append next part. */
+ endcur += (int)strlen(pl -> npart); /* Advance end pointer */
+#else
+/*
+ strcpy() does not account for quoted metacharacters.
+ We must remove the quotes before doing the stat().
+*/
+ {
+ int quote = 0;
+ char c, * s;
+ s = pl -> npart;
+ while ((c = *s++)) {
+ if (!quote) {
+ if (c == CMDQ) {
+ quote = 1;
+ continue;
+ }
+ }
+ *endcur++ = c;
+ quote = 0;
+ }
+ }
+#endif /* COMMENT */
+ *endcur = '\0'; /* End new current string. */
+
+ if (stat(sofar,&statbuf) == 0) { /* If this piece exists... */
+ debug(F110,"traverse exists",sofar,0);
+ *endcur++ = DIRSEP; /* add slash to end */
+ *endcur = '\0'; /* and end the string again. */
+ traverse(pl -> fwd, sofar, endcur);
+ }
+#ifdef DEBUG
+ else debug(F110,"traverse not found", sofar, 0);
+#endif /* DEBUG */
+ return;
+ }
+
+ *endcur = '\0'; /* End current string */
+ debug(F111,"traverse sofar 3",sofar,0);
+
+ if (!itsadir)
+ return;
+
+ /* Search is recursive or ... */
+ /* path segment contains wildcards, have to open and search directory. */
+
+ blah:
+
+ debug(F110,"traverse opening directory", sofar, 0);
+
+#ifdef OPENDIR
+ debug(F110,"traverse opendir()",sofar,0);
+ if ((fd = opendir(sofar)) == NULL) { /* Can't open, fail. */
+ debug(F101,"traverse opendir() failed","",errno);
+ return;
+ }
+ while ((dirbuf = readdir(fd)))
+#else /* !OPENDIR */
+ debug(F110,"traverse directory open()",sofar,0);
+ if ((fd = open(sofar,O_RDONLY)) < 0) {
+ debug(F101,"traverse directory open() failed","",errno);
+ return;
+ }
+ while (read(fd, (char *)dirbuf, sizeof dir_entry))
+#endif /* OPENDIR */
+ { /* Read each entry in this directory */
+ int exists;
+ char *eos, *s;
+ exists = 0;
+
+ /* On some platforms, the read[dir]() can return deleted files, */
+ /* e.g. HP-UX 5.00. There is no point in grinding through this */
+ /* routine when the file doesn't exist... */
+
+ if ( /* There actually is an inode... */
+#ifdef BSD42
+ dirbuf->d_ino != -1
+#else
+#ifdef unos
+ dirbuf->d_ino != -1
+#else
+#ifdef QNX
+ dirbuf->d_stat.st_ino != 0
+#else
+#ifdef SOLARIS
+ dirbuf->d_ino != 0
+#else
+#ifdef sun
+ dirbuf->d_fileno != 0
+#else
+#ifdef bsdi
+ dirbuf->d_fileno != 0
+#else
+#ifdef __386BSD__
+ dirbuf->d_fileno != 0
+#else
+#ifdef __FreeBSD__
+ dirbuf->d_fileno != 0
+#else
+#ifdef ultrix
+ dirbuf->gd_ino != 0
+#else
+#ifdef Plan9
+ 1
+#else
+ dirbuf->d_ino != 0
+#endif /* Plan9 */
+#endif /* ultrix */
+#endif /* __FreeBSD__ */
+#endif /* __386BSD__ */
+#endif /* bsdi */
+#endif /* sun */
+#endif /* SOLARIS */
+#endif /* QNX */
+#endif /* unos */
+#endif /* BSD42 */
+ )
+ exists = 1;
+ if (!exists)
+ continue;
+
+ ckstrncpy(nambuf, /* Copy the name */
+ dirbuf->d_name,
+ MAXNAMLEN
+ );
+ if (nambuf[0] == '.') {
+ if (!nambuf[1] || (nambuf[1] == '.' && !nambuf[2])) {
+ debug(F110,"traverse skipping",nambuf,0);
+ continue; /* skip "." and ".." */
+ }
+ }
+ s = nambuf; /* Copy name to end of sofar */
+ eos = endcur;
+ while ((*eos = *s)) {
+ s++;
+ eos++;
+ }
+/*
+ Now we check the file for (a) whether it is a directory, and (b) whether
+ its name matches our pattern. If it is a directory, and if we have been
+ told to build a recursive list, then we must descend regardless of whether
+ it matches the pattern. If it is not a directory and it does not match
+ our pattern, we skip it. Note: sofar is the full pathname, nambuf is
+ the name only.
+*/
+ /* Do this first to save pointless function calls */
+ if (nambuf[0] == '.' && !xmatchdot) /* Dir name starts with '.' */
+ continue;
+ if (stathack) {
+ if (xrecursive || xfilonly || xdironly || xpatslash) {
+ itsadir = xisdir(sofar); /* See if it's a directory */
+ debug(F101,"STAT","",19);
+ } else {
+ itsadir = 0;
+ }
+ } else {
+ itsadir = xisdir(sofar);
+ debug(F101,"STAT","",20);
+ }
+
+#ifdef CKSYMLINK
+#ifdef USE_LSTAT
+ if (itsadir && xnolinks) { /* If not following symlinks */
+ int x;
+ struct stat buf;
+ x = lstat(sofar,&buf);
+ debug(F111,"traverse lstat 2",sofar,x);
+ if (x > -1 &&
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ )
+ itsadir = 0;
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+
+#ifdef RECURSIVE
+ if (xrecursive > 0 && itsadir &&
+ (xpatlast[0] == '*') && !xpatlast[1]
+ ) {
+ debug(F110,
+ "traverse add: recursive && isdir && segisdir or match",
+ sofar,
+ segisdir
+ );
+ addresult(sofar,itsadir);
+ if (numfnd < 0) return;
+ }
+#endif /* RECURSIVE */
+
+ debug(F111,"traverse mresult xpat",xpat,xrecursive);
+ debug(F111,"traverse mresult pl -> npart",
+ pl -> npart,
+ ((pl -> fwd) ? 9999 : 0)
+ );
+ debug(F111,"traverse mresult sofar segisdir",sofar,segisdir);
+ debug(F111,"traverse mresult sofar itsadir",sofar,itsadir);
+ debug(F101,"traverse mresult xmatchdot","",xmatchdot);
+/*
+ Match the path so far with the pattern after stripping any leading "./"
+ from either or both. The pattern chosen is the full original pattern if
+ the match candidate (sofar) is not a directory, or else just the name part
+ (pl->npart) if it is.
+*/
+ {
+ char * s1; /* The pattern */
+ char * s2 = sofar; /* The path so far */
+ char * s3; /* Worker */
+ int opts; /* Match options */
+
+ s1 = itsadir ? pl->npart : xpat;
+
+#ifndef COMMENT
+ /* I can't explain this but it unbreaks "cd blah/sub<Esc>" */
+ if (itsadir && !xrecursive && xpatslash > 0 &&
+ segisdir == 0 && itswild) {
+ s1 = xpat;
+ debug(F110,"traverse mresult s1 kludge",s1,0);
+ }
+#endif /* COMMENT */
+
+ if (xrecursive && xpatslash == 0)
+ s2 = nambuf;
+ while ((s1[0] == '.') && (s1[1] == '/')) /* Strip "./" */
+ s1 += 2;
+ while ((s2[0] == '.') && (s2[1] == '/')) /* Ditto */
+ s2 += 2;
+ opts = mopts; /* Match options */
+ if (itsadir) /* Current segment is a directory */
+ opts = mopts & 1; /* No fences */
+ s3 = s2; /* Get segment depth */
+ depth = 0;
+ while (*s3) { if (*s3++ == '/') depth++; }
+#ifndef NOSKIPMATCH
+ /* This speeds things up a bit. */
+ /* If it causes trouble define NOSKIPMATCH and rebuild. */
+ if (depth == 0 && (s1[0] == '*') && !s1[1])
+ mresult = xmatchdot ? 1 : (s2[0] != '.');
+ else
+#endif /* NOSKIPMATCH */
+ mresult = ckmatch(s1,s2,1,opts); /* Match */
+ }
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"traverse mresult depth",sofar,depth);
+ debug(F101,"traverse mresult xpatslash","",xpatslash);
+ debug(F111,"traverse mresult nambuf",nambuf,mresult);
+ debug(F111,"traverse mresult itswild",pl -> npart,itswild);
+ debug(F111,"traverse mresult segisdir",pl -> npart,segisdir);
+ }
+#endif /* DEBUG */
+ if (mresult || /* If match succeeded */
+ xrecursive || /* Or search is recursive */
+ depth < xpatslash /* Or not deep enough to match... */
+ ) {
+ if ( /* If it's not a directory... */
+/*
+ The problem here is that segisdir is apparently not set appropriately.
+ If I leave in the !segisdir test, then "dir /recursive blah" (where blah is
+ a directory name) misses some regular files because sometimes segisdir
+ is set and sometimes it's not. But if I comment it out, then
+ "dir <star>/<star>.txt lists every file in * and does not even open up the
+ subdirectories. However, "dir /rec <star>/<star>.txt" works right.
+*/
+#ifdef COMMENT
+ mresult && (!itsadir && !segisdir)
+#else
+ mresult && /* Matched */
+ !itsadir && /* sofar is not a directory */
+ ((!xrecursive && !segisdir) || xrecursive)
+#endif /* COMMENT */
+ ) {
+ debug(F110,
+ "traverse add: match && !itsadir",sofar,0);
+ addresult(sofar,itsadir);
+ if (numfnd < 0) return;
+ } else if (itsadir && (xrecursive || mresult)) {
+ struct path * xx = NULL;
+ *eos++ = DIRSEP; /* Add directory separator */
+ *eos = '\0'; /* to end of segment */
+#ifdef RECURSIVE
+ /* Copy previous pattern segment to this new directory */
+
+ if (xrecursive > 0 && !(pl -> fwd)) {
+ xx = (struct path *) malloc(sizeof (struct path));
+ pl -> fwd = xx;
+ if (xx) {
+ xx -> fwd = NULL;
+ strcpy(xx -> npart, pl -> npart); /* safe */
+ }
+ }
+#endif /* RECURSIVE */
+ traverse(pl -> fwd, sofar, eos); /* Traverse new directory */
+ }
+ }
+ }
+#ifdef OPENDIR
+ closedir(fd);
+#else /* !OPENDIR */
+ close(fd);
+#endif /* OPENDIR */
+}
+
+/*
+ * addresult:
+ * Adds a result string to the result array. Increments the number
+ * of matches found, copies the found string into our string
+ * buffer, and puts a pointer to the buffer into the caller's result
+ * array. Our free buffer pointer is updated. If there is no
+ * more room in the caller's array, the number of matches is set to -1.
+ * Input: a result string.
+ * Returns: nothing.
+ */
+static VOID
+addresult(str,itsadir) char *str; int itsadir; {
+ int len;
+
+ if (!freeptr) {
+ debug(F100,"addresult string space not init'd","",0);
+ initspace(mtchs,ssplen);
+ }
+ if (!str) str = "";
+ debug(F111,"addresult",str,itsadir);
+ if (!*str)
+ return;
+
+ if (itsadir < 0) {
+ itsadir = xisdir(str);
+ }
+ if ((xdironly && !itsadir) || (xfilonly && itsadir)) {
+ debug(F111,"addresult skip",str,itsadir);
+ return;
+ }
+ while (str[0] == '.' && ISDIRSEP(str[1])) /* Strip all "./" from front */
+ str += 2;
+ if (--remlen < 0) { /* Elements left in array of names */
+ debug(F111,"addresult ARRAY FULL",str,numfnd);
+ numfnd = -1;
+ return;
+ }
+ len = (int)strlen(str); /* Space this will use */
+ debug(F111,"addresult len",str,len);
+
+ if (len < 1)
+ return;
+
+ if ((freeptr + len + itsadir + 1) > (sspace + ssplen)) {
+ debug(F111,"addresult OUT OF SPACE",str,numfnd);
+#ifdef DYNAMIC
+ printf(
+"?String space %d exhausted - use SET FILE STRINGSPACE to increase\n",ssplen);
+#else
+ printf("?String space %d exhausted\n",ssplen);
+#endif /* DYNAMIC */
+ numfnd = -1; /* Do not record if not enough space */
+ return;
+ }
+ strcpy(freeptr,str); /* safe */
+
+ /* Tag directory names by putting '/' at the end */
+
+ if (itsadir && (freeptr[len-1] == '/')) {
+ freeptr[len++] = DIRSEP;
+ freeptr[len] = '\0';
+ }
+ if (numfnd >= maxnames) {
+#ifdef DYNAMIC
+ printf(
+"?Too many files (%d max) - use SET FILE LISTSIZE to increase\n",maxnames);
+#else
+ printf("?Too many files - %d max\n",maxnames);
+#endif /* DYNAMIC */
+ numfnd = -1;
+ return;
+ }
+ str = freeptr;
+ *resptr++ = freeptr;
+ freeptr += (len + 1);
+ numfnd++;
+ debug(F111,"addresult ADD",str,numfnd);
+}
+
+#ifdef COMMENT
+/*
+ * match(pattern,string):
+ * pattern matcher. Takes a string and a pattern possibly containing
+ * the wildcard characters '*' and '?'. Returns true if the pattern
+ * matches the string, false otherwise.
+ * Orignally by: Jeff Damens, CUCCA, 1984
+ * No longer used as of C-Kermit 7.0, now we use ckmatch() instead (ckclib.c).
+ *
+ * Input: a string and a wildcard pattern.
+ * Returns: 1 if match, 0 if no match.
+ */
+static int
+match(pattern, string) char *pattern, *string; {
+ char *psave = NULL, *ssave = NULL; /* Backup pointers for failure */
+ int q = 0; /* Quote flag */
+
+ if (*string == '.' && *pattern != '.' && !xmatchdot) {
+ debug(F110,"match skip",string,0);
+ return(0);
+ }
+ while (1) {
+ for (; *pattern == *string; pattern++,string++) /* Skip first */
+ if (*string == '\0') return(1); /* End of strings, succeed */
+
+ if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
+ q = 1; /* metacharacters */
+ pattern++; /* advance past quote */
+ if (*pattern != *string) return(0);
+ continue;
+ } else q = 0;
+
+ if (q) {
+ return(0);
+ } else {
+ if (*string != '\0' && *pattern == '?') {
+ pattern++; /* '?', let it match */
+ string++;
+ } else if (*pattern == '*') { /* '*' ... */
+ psave = ++pattern; /* remember where we saw it */
+ ssave = string; /* let it match 0 chars */
+ } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
+ /* ...have seen a star */
+ string = ++ssave; /* skip 1 char from string */
+ pattern = psave; /* and back up pattern */
+ } else return(0); /* otherwise just fail */
+ }
+ }
+}
+#endif /* COMMENT */
+
+/*
+ The following two functions are for expanding tilde in filenames
+ Contributed by Howie Kaye, CUCCA, developed for CCMD package.
+*/
+
+/* W H O A M I -- Get user's username. */
+
+/*
+ 1) Get real uid
+ 2) See if the $USER environment variable is set ($LOGNAME on AT&T)
+ 3) If $USER's uid is the same as ruid, realname is $USER
+ 4) Otherwise get logged in user's name
+ 5) If that name has the same uid as the real uid realname is loginname
+ 6) Otherwise, get a name for ruid from /etc/passwd
+*/
+char *
+whoami() {
+#ifdef DTILDE
+#ifdef pdp11
+#define WHOLEN 100
+#else
+#define WHOLEN 257
+#endif /* pdp11 */
+ static char realname[UIDBUFLEN+1]; /* user's name */
+ static int ruid = -1; /* user's real uid */
+ char loginname[UIDBUFLEN+1], envname[256]; /* temp storage */
+ char *c;
+ struct passwd *p;
+ _PROTOTYP(extern char * getlogin, (void) );
+
+ if (ruid != -1)
+ return(realname);
+
+ ruid = real_uid(); /* get our uid */
+
+ /* how about $USER or $LOGNAME? */
+ if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
+ ckstrncpy(envname, c, 255);
+ if ((p = getpwnam(envname)) != NULL) {
+ if (p->pw_uid == ruid) { /* get passwd entry for envname */
+ ckstrncpy(realname, envname, UIDBUFLEN); /* uid's are same */
+ return(realname);
+ }
+ }
+ }
+
+ /* can we use loginname() ? */
+
+ if ((c = getlogin()) != NULL) { /* name from utmp file */
+ ckstrncpy (loginname, c, UIDBUFLEN);
+ if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
+ if (p->pw_uid == ruid) /* for loginname */
+ ckstrncpy(realname, envname, UIDBUFLEN); /* if uid's are same */
+ }
+
+ /* Use first name we get for ruid */
+
+ if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
+ realname[0] = '\0'; /* no user name */
+ ruid = -1;
+ return(NULL);
+ }
+ ckstrncpy(realname, p->pw_name, UIDBUFLEN);
+ return(realname);
+#else
+ return(NULL);
+#endif /* DTILDE */
+}
+
+/* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */
+
+char *
+tilde_expand(dirname) char *dirname; {
+#ifdef DTILDE
+#ifdef pdp11
+#define BUFLEN 100
+#else
+#define BUFLEN 257
+#endif /* pdp11 */
+ struct passwd *user;
+ static char olddir[BUFLEN+1];
+ static char oldrealdir[BUFLEN+1];
+ static char temp[BUFLEN+1];
+ int i, j;
+
+ debug(F111,"tilde_expand",dirname,dirname[0]);
+
+ if (dirname[0] != '~') /* Not a tilde...return param */
+ return(dirname);
+ if (!strcmp(olddir,dirname)) { /* Same as last time */
+ return(oldrealdir); /* so return old answer. */
+ } else {
+ j = (int)strlen(dirname);
+ for (i = 0; i < j; i++) /* find username part of string */
+ if (!ISDIRSEP(dirname[i]))
+ temp[i] = dirname[i];
+ else break;
+ temp[i] = '\0'; /* tie off with a NULL */
+ if (i == 1) { /* if just a "~" */
+#ifdef IKSD
+ if (inserver)
+ user = getpwnam(uidbuf); /* Get info on current user */
+ else
+#endif /* IKSD */
+ {
+ char * p = whoami();
+ if (p)
+ user = getpwnam(p);
+ else
+ user = NULL;
+ }
+ } else {
+ user = getpwnam(&temp[1]); /* otherwise on the specified user */
+ }
+ }
+ if (user != NULL) { /* valid user? */
+ ckstrncpy(olddir, dirname, BUFLEN); /* remember the directory */
+ ckstrncpy(oldrealdir,user->pw_dir, BUFLEN); /* and home directory */
+ ckstrncat(oldrealdir,&dirname[i], BUFLEN);
+ oldrealdir[BUFLEN] = '\0';
+ return(oldrealdir);
+ } else { /* invalid? */
+ ckstrncpy(olddir, dirname, BUFLEN); /* remember for next time */
+ ckstrncpy(oldrealdir, dirname, BUFLEN);
+ return(oldrealdir);
+ }
+#else
+ return(NULL);
+#endif /* DTILDE */
+}
+
+/*
+ Functions for executing system commands.
+ zsyscmd() executes the system command in the normal, default way for
+ the system. In UNIX, it does what system() does. Thus, its results
+ are always predictable.
+ zshcmd() executes the command using the user's preferred shell.
+*/
+int
+zsyscmd(s) char *s; {
+#ifdef aegis
+ if (nopush) return(-1);
+ if (!priv_chk()) return(system(s));
+#else
+ PID_T shpid;
+#ifdef COMMENT
+/* This doesn't work... */
+ WAIT_T status;
+#else
+ int status;
+#endif /* COMMENT */
+
+ if (nopush) return(-1);
+ if ((shpid = fork())) {
+ if (shpid < (PID_T)0) return(-1); /* Parent */
+ while (shpid != (PID_T) wait(&status))
+ ;
+ return(status);
+ }
+ if (priv_can()) { /* Child: cancel any priv's */
+ printf("?Privilege cancellation failure\n");
+ _exit(255);
+ }
+ restorsigs(); /* Restore ignored signals */
+#ifdef HPUX10
+ execl("/usr/bin/sh","sh","-c",s,NULL);
+ perror("/usr/bin/sh");
+#else
+#ifdef Plan9
+ execl("/bin/rc", "rc", "-c", s, NULL);
+ perror("/bin/rc");
+#else
+ execl("/bin/sh","sh","-c",s,NULL);
+ perror("/bin/sh");
+#endif /* Plan9 */
+#endif /* HPUX10 */
+ _exit(255);
+ return(0); /* Shut up ANSI compilers. */
+#endif /* aegis */
+}
+
+
+/* Z _ E X E C -- Overlay ourselves with another program */
+
+#ifndef NOZEXEC
+#ifdef HPUX5
+#define NOZEXEC
+#else
+#ifdef ATT7300
+#define NOZEXEC
+#endif /* ATT7300 */
+#endif /* HPUX5 */
+#endif /* NOZEXEC */
+
+VOID
+z_exec(p,s,t) char * p, ** s; int t; { /* Overlay ourselves with "p s..." */
+#ifdef NOZEXEC
+ printf("EXEC /REDIRECT NOT IMPLEMENTED IN THIS VERSION OF C-KERMIT\n");
+ debug(F110,"z_exec NOT IMPLEMENTED",p,0);
+#else
+ int x;
+ extern int ttyfd;
+ debug(F110,"z_exec command",p,0);
+ debug(F110,"z_exec arg 0",s[0],0);
+ debug(F110,"z_exec arg 1",s[1],0);
+ debug(F101,"z_exec t","",t);
+ errno = 0;
+ if (t) {
+ if (ttyfd > 2) {
+ dup2(ttyfd, 0);
+ dup2(ttyfd, 1);
+ /* dup2(ttyfd, 2); */
+ close(ttyfd);
+ }
+ }
+ restorsigs(); /* Restore ignored signals */
+ x = execvp(p,s);
+ if (x < 0) debug(F101,"z_exec errno","",errno);
+#endif /* NOZEXEC */
+}
+
+/*
+ Z S H C M D -- Execute a shell command (or program thru the shell).
+
+ Original UNIX code by H. Fischer; copyright rights assigned to Columbia U.
+ Adapted to use getpwuid to find login shell because many systems do not
+ have SHELL in environment, and to use direct calling of shell rather
+ than intermediate system() call. -- H. Fischer (1985); many changes since
+ then. Call with s pointing to command to execute. Returns:
+ -1 on failure to start the command (can't find, can't fork, can't run).
+ 1 if command ran and gave an exit status of 0.
+ 0 if command ran and gave a nonzero exit status.
+ with pexitstatus containing the command's exit status.
+*/
+int
+zshcmd(s) char *s; {
+ PID_T pid;
+
+#ifdef NOPUSH
+ return(0);
+#else
+ if (nopush) return(-1);
+ debug(F110,"zshcmd command",s,0);
+
+#ifdef aegis
+ if ((pid = vfork()) == 0) { /* Make child quickly */
+ char *shpath, *shname, *shptr; /* For finding desired shell */
+
+ if (priv_can()) exit(1); /* Turn off privs. */
+ if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
+
+#else /* All Unix systems */
+ if ((pid = fork()) == 0) { /* Make child */
+ char *shpath, *shname, *shptr; /* For finding desired shell */
+ struct passwd *p;
+#ifdef HPUX10 /* Default */
+ char *defshell = "/usr/bin/sh";
+#else
+#ifdef Plan9
+ char *defshell = "/bin/rc";
+#else
+ char *defshell = "/bin/sh";
+#endif /* Plan9 */
+#endif /* HPUX10 */
+ if (priv_can()) exit(1); /* Turn off privs. */
+#ifdef COMMENT
+/* Old way always used /etc/passwd shell */
+ p = getpwuid(real_uid()); /* Get login data */
+ if (p == (struct passwd *) NULL || !*(p->pw_shell))
+ shpath = defshell;
+ else
+ shpath = p->pw_shell;
+#else
+/* New way lets user override with SHELL variable, but does not rely on it. */
+/* This allows user to specify a different shell. */
+ shpath = getenv("SHELL"); /* What shell? */
+ debug(F110,"zshcmd SHELL",shpath,0);
+ if (shpath == NULL) {
+ p = getpwuid( real_uid() ); /* Get login data */
+ if (p == (struct passwd *)NULL || !*(p->pw_shell))
+ shpath = defshell;
+ else shpath = p->pw_shell;
+ debug(F110,"zshcmd shpath",shpath,0);
+ }
+#endif /* COMMENT */
+#endif /* aegis */
+ shptr = shname = shpath;
+ while (*shptr != '\0')
+ if (*shptr++ == DIRSEP)
+ shname = shptr;
+ restorsigs(); /* Restore ignored signals */
+ debug(F110,"zshcmd shname",shname,0);
+ if (s == NULL || *s == '\0') { /* Interactive shell requested? */
+ execl(shpath,shname,"-i",NULL); /* Yes, do that */
+ } else { /* Otherwise, */
+ execl(shpath,shname,"-c",s,NULL); /* exec the given command */
+ } /* If execl() failed, */
+ exit(BAD_EXIT); /* return bad return code. */
+
+ } else { /* Parent */
+
+ int wstat; /* ... must wait for child */
+#ifdef CK_CHILD
+ int child; /* Child's exit status */
+#endif /* CK_CHILD */
+ SIGTYP (*istat)(), (*qstat)();
+
+ if (pid == (PID_T) -1) return(-1); /* fork() failed? */
+
+ istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
+ qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
+
+#ifdef CK_CHILD
+ while (((wstat = wait(&child)) != pid) && (wstat != -1))
+#else
+ while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
+#endif /* CK_CHILD */
+ ; /* Wait for fork */
+ signal(SIGINT,istat); /* Restore interrupts */
+ signal(SIGQUIT,qstat);
+#ifdef CK_CHILD
+ pexitstat = (child & 0xff) ? child : child >> 8;
+ debug(F101,"zshcmd exit status","",pexitstat);
+ return(child == 0 ? 1 : 0); /* Return child's status */
+#endif /* CK_CHILD */
+ }
+ return(1);
+#endif /* NOPUSH */
+}
+
+/* I S W I L D -- Check if filespec is "wild" */
+
+/*
+ Returns:
+ 0 if argument is empty or is the name of a single file;
+ 1 if it contains wildcard characters.
+ Note: must match the algorithm used by match(), hence no [a-z], etc.
+*/
+int
+iswild(filespec) char *filespec; {
+ char c, *p, *f; int x;
+ int quo = 0;
+ if (!filespec)
+ return(0);
+ f = filespec;
+ if (wildxpand) { /* Shell handles wildcarding */
+ if ((x = nzxpand(filespec,0)) > 1)
+ return(1);
+ if (x == 0) return(0); /* File does not exist */
+ p = malloc(MAXNAMLEN + 20);
+ znext(p);
+ x = (strcmp(filespec,p) != 0);
+ free(p);
+ p = NULL;
+ return(x);
+ } else { /* We do it ourselves */
+ while ((c = *filespec++) != '\0') {
+ if (c == '\\' && quo == 0) {
+ quo = 1;
+ continue;
+ }
+ if (!quo && (c == '*' || c == '?'
+#ifdef CKREGEX
+#ifndef VMS
+ || c == '['
+#endif /* VMS */
+ || c == '{'
+#endif /* CKREGEX */
+ )) {
+ debug(F111,"iswild",f,1);
+ return(1);
+ }
+ quo = 0;
+ }
+ debug(F111,"iswild",f,0);
+ return(0);
+ }
+}
+
+/*
+ I S D I R -- Is a Directory.
+
+ Tell if string pointer s is the name of an existing directory. Returns 1 if
+ directory, 0 if not a directory.
+
+ The following no longer applies:
+
+ If the file is a symlink, we return 1 if
+ it is a directory OR if it is a link to a directory and the "xrecursive" flag
+ is NOT set. This is to allow parsing a link to a directory as if it were a
+ directory (e.g. in the CD or IF DIRECTORY command) but still prevent
+ recursive traversal from visiting the same directory twice.
+*/
+
+#ifdef ISDIRCACHE
+/* This turns out to be unsafe and gives little benefit anyway. */
+/* See notes 28 Sep 2003. Thus ISDIRCACHE is not defined. */
+
+static char prevpath[CKMAXPATH+4] = { '\0', '\0' };
+static int prevstat = -1;
+int
+clrdircache() {
+ debug(F100,"CLEAR ISDIR CACHE","",0);
+ prevstat = -1;
+ prevpath[0] = NUL;
+}
+#endif /* ISDIRCACHE */
+
+int
+isdir(s) char *s; {
+ int x, needrlink = 0, islink = 0;
+ struct stat statbuf;
+ char fnam[CKMAXPATH+4];
+
+ if (!s) return(0);
+ if (!*s) return(0);
+
+#ifdef ISDIRCACHE
+ if (prevstat > -1) {
+ if (s[0] == prevpath[0]) {
+ if (!strcmp(s,prevpath)) {
+ debug(F111,"isdir cache hit",s,prevstat);
+ return(prevstat);
+ }
+ }
+ }
+#endif /* ISDIRCACHE */
+
+#ifdef CKSYMLINK
+#ifdef COMMENT
+/*
+ The following over-clever bit has been commented out because it presumes
+ to know when a symlink might be redundant, which it can't possibly know.
+ Using plain old stat() gives Kermit the same results as ls and ls -R, which
+ is just fine: no surprises.
+*/
+#ifdef USE_LSTAT
+ if (xrecursive) {
+ x = lstat(s,&statbuf);
+ debug(F111,"isdir lstat",s,x);
+ } else {
+#endif /* USE_LSTAT */
+ x = stat(s,&statbuf);
+ debug(F111,"isdir stat",s,x);
+#ifdef USE_LSTAT
+ }
+#endif /* USE_LSTAT */
+#else
+ x = stat(s,&statbuf);
+ debug(F111,"isdir stat",s,x);
+#endif /* COMMENT */
+ if (x == -1) {
+ debug(F101,"isdir errno","",errno);
+ return(0);
+ }
+ islink = 0;
+ if (xrecursive) {
+#ifdef NOLINKBITS
+ needrlink = 1;
+#else
+#ifdef S_ISLNK
+ islink = S_ISLNK(statbuf.st_mode);
+ debug(F101,"isdir S_ISLNK islink","",islink);
+#else
+#ifdef _IFLNK
+ islink = (_IFMT & statbuf.st_mode) == _IFLNK;
+ debug(F101,"isdir _IFLNK islink","",islink);
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+#endif /* NOLINKBITS */
+ if (needrlink) {
+ if (readlink(s,fnam,CKMAXPATH) > -1)
+ islink = 1;
+ }
+ }
+#else
+ x = stat(s,&statbuf);
+ if (x == -1) {
+ debug(F101,"isdir errno","",errno);
+ return(0);
+ }
+ debug(F111,"isdir stat",s,x);
+#endif /* CKSYMLINK */
+ debug(F101,"isdir islink","",islink);
+ debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode);
+ x = islink ? 0 : (S_ISDIR (statbuf.st_mode) ? 1 : 0);
+#ifdef ISDIRCACHE
+ prevstat = x;
+ ckstrncpy(prevpath,s,CKMAXPATH+1);
+#endif /* ISDIRCACHE */
+ return(x);
+}
+
+#ifdef CK_MKDIR
+/* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */
+
+/* Z M K D I R -- Create directory(s) if necessary */
+/*
+ Call with:
+ A pointer to a file specification that might contain directory
+ information. The filename is expected to be included.
+ If the file specification does not include any directory separators,
+ then it is assumed to be a plain file.
+ If one or more directories are included in the file specification,
+ this routine tries to create them if they don't already exist.
+ Returns:
+ 0 or greater on success, i.e. the number of directories created.
+ -1 on failure to create the directory
+*/
+int
+zmkdir(path) char *path; {
+ char *xp, *tp, c;
+ int x, count = 0;
+
+ if (!path) path = "";
+ if (!*path) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zmkdir setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(path)) {
+ debug(F110,"zmkdir setroot violation",path,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+ x = strlen(path);
+ debug(F111,"zmkdir",path,x);
+ if (x < 1 || x > MAXPATH) /* Check length */
+ return(-1);
+ if (!(tp = malloc(x+1))) /* Make a temporary copy */
+ return(-1);
+ strcpy(tp,path); /* safe (prechecked) */
+#ifdef DTILDE
+ if (*tp == '~') { /* Starts with tilde? */
+ xp = tilde_expand(tp); /* Attempt to expand tilde */
+ if (!xp) xp = "";
+ if (*xp) {
+ char *zp;
+ debug(F110,"zmkdir tilde_expand",xp,0);
+ if (!(zp = malloc(strlen(xp) + 1))) { /* Make a place for it */
+ free(tp);
+ tp = NULL;
+ return(-1);
+ }
+ free(tp); /* Free previous buffer */
+ tp = zp; /* Point to new one */
+ strcpy(tp,xp); /* Copy expanded name to new buffer */
+ }
+ }
+#endif /* DTILDE */
+ debug(F110,"zmkdir tp after tilde_expansion",tp,0);
+ xp = tp;
+ if (ISDIRSEP(*xp)) /* Don't create root directory! */
+ xp++;
+
+ /* Go thru filespec from left to right... */
+
+ for (; *xp; xp++) { /* Create parts that don't exist */
+ if (!ISDIRSEP(*xp)) /* Find next directory separator */
+ continue;
+ c = *xp; /* Got one. */
+ *xp = NUL; /* Make this the end of the string. */
+ if (!isdir(tp)) { /* This directory exists already? */
+#ifdef CK_LOGIN
+ if (isguest) /* Not allowed for guests */
+ return(-1);
+#ifndef NOXFER
+ /* Nor if MKDIR and/or CD are disabled */
+ else
+#endif /* CK_LOGIN */
+ if ((server
+#ifdef IKSD
+ || inserver
+#endif /* IKSD */
+ ) && (!ENABLED(en_mkd) || !ENABLED(en_cwd)))
+ return(-1);
+#endif /* IKSD */
+
+ debug(F110,"zmkdir making",tp,0);
+ x = /* No, try to create it */
+#ifdef NOMKDIR
+ -1 /* Systems without mkdir() */
+#else
+ mkdir(tp,0777) /* UNIX */
+#endif /* NOMKDIR */
+ ;
+ if (x < 0) {
+ debug(F101,"zmkdir failed, errno","",errno);
+ free(tp); /* Free temporary buffer. */
+ tp = NULL;
+ return(-1); /* Return failure code. */
+ } else
+ count++;
+ }
+ *xp = c; /* Replace the separator. */
+ }
+ free(tp); /* Free temporary buffer. */
+ return(count); /* Return success code. */
+}
+#endif /* CK_MKDIR */
+
+int
+zrmdir(path) char *path; {
+#ifdef CK_LOGIN
+ if (isguest)
+ return(-1);
+#endif /* CK_LOGIN */
+
+ if (!path) path = "";
+ if (!*path) return(-1);
+
+#ifdef CKROOT
+ debug(F111,"zrmdir setroot",ckroot,ckrootset);
+ if (ckrootset) if (!zinroot(path)) {
+ debug(F110,"zrmdir setroot violation",path,0);
+ return(-1);
+ }
+#endif /* CKROOT */
+
+#ifndef NOMKDIR
+ return(rmdir(path));
+#else
+ return(-1);
+#endif /* NOMKDIR */
+}
+
+/* Z F S E E K -- Position input file pointer */
+/*
+ Call with:
+ Long int, 0-based, indicating desired position.
+ Returns:
+ 0 on success.
+ -1 on failure.
+*/
+#ifndef NORESEND
+int
+#ifdef CK_ANSIC
+zfseek(long pos)
+#else
+zfseek(pos) long pos;
+#endif /* CK_ANSIC */
+/* zfseek */ {
+ zincnt = -1; /* Must empty the input buffer */
+ debug(F101,"zfseek","",pos);
+ return(fseek(fp[ZIFILE], pos, 0)?-1:0);
+}
+#endif /* NORESEND */
+
+/* Z F N Q F P -- Convert filename to fully qualified absolute pathname */
+
+static struct zfnfp fnfp = { 0, NULL, NULL };
+
+struct zfnfp *
+zfnqfp(fname, buflen, buf) char * fname; int buflen; char * buf; {
+ char * s;
+ int len;
+#ifdef MAXPATHLEN
+ char zfntmp[MAXPATHLEN+4];
+#else
+ char zfntmp[CKMAXPATH+4];
+#endif /* MAXPATHLEN */
+
+ char sb[32], * tmp;
+ int i = 0, j = 0, k = 0, x = 0, y = 0;
+ int itsadir = 0;
+
+ s = fname;
+ if (!s)
+ return(NULL);
+ if (!*s)
+ return(NULL);
+ if (!buf)
+ return(NULL);
+
+ /* Initialize the data structure */
+
+ fnfp.len = ckstrncpy(buf,fname,buflen);
+ fnfp.fpath = buf;
+ fnfp.fname = NULL;
+ len = buflen;
+ debug(F111,"zfnqfp fname",fname,len);
+
+#ifdef DTILDE
+ if (*s == '~') { /* Starts with tilde? */
+ char * xp;
+ xp = tilde_expand(s); /* Attempt to expand tilde */
+ debug(F110,"zfnqfp xp",xp,0); /* (realpath() doesn't do this) */
+ if (!xp) xp = "";
+ if (*xp)
+ s = xp;
+ }
+#endif /* DTILDE */
+
+#ifdef CKREALPATH
+
+/* N.B.: The realpath() result buffer MUST be MAXPATHLEN bytes long */
+/* otherwise we write over memory. */
+
+ if (!realpath(s,zfntmp)) {
+ debug(F111,"zfnqfp realpath fails",s,errno);
+#ifdef COMMENT
+ if (errno != ENOENT)
+ return(NULL);
+#else
+ /* If realpath() fails use the do-it-yourself method */
+ /* 16 Jan 2002 */
+ goto norealpath;
+#endif /* COMMENT */
+ }
+ len = strlen(zfntmp);
+ if (len > buflen) {
+ debug(F111,"zfnqfp result too long",ckitoa(buflen),len);
+ return(NULL);
+ } else {
+ ckstrncpy(buf,zfntmp,buflen);
+ }
+ if (buf[len-1] != '/') {
+ if ((itsadir = isdir(buf)) && len < (buflen - 1)) {
+ buf[len++] = '/';
+ buf[len] = NUL;
+ }
+ }
+ fnfp.len = len;
+ fnfp.fpath = buf;
+ debug(F110,"zfnqfp realpath path",fnfp.fpath,0);
+ tmp = buf + fnfp.len - 1;
+ if (!itsadir) {
+ while (tmp >= buf) {
+ if (*tmp == '/') {
+ fnfp.fname = tmp + 1;
+ debug(F110,"zfnqfp realpath name",fnfp.fname,0);
+ break;
+ }
+ tmp--;
+ }
+ }
+ return(&fnfp);
+
+#endif /* CKREALPATH */
+
+ norealpath:
+
+ tmp = zfntmp;
+ while (*s) { /* Remove leading "./" (0 or more) */
+ debug(F110,"zfnqfp while *s",s,0);
+ if (*s == '.' && *(s+1) == '/') {
+ s += 2;
+ while (*s == '/') s++;
+ } else
+ break;
+ }
+ if (!*s) return(NULL);
+ if (*s == '/') { /* Pathname is absolute */
+ ckstrncpy(buf,s,len);
+ x = strlen(buf);
+ y = 0;
+ } else { /* Pathname is relative */
+ char * p;
+ if (p = zgtdir()) { /* So get current directory */
+ debug(F110,"zfnqfp zgtdir",p,0);
+ x = ckstrncpy(buf,p,len);
+ buf[x++] = '/';
+ debug(F110,"zfnqfp buf 1",buf,0);
+ len -= x; /* How much room left in buffer */
+ if ((y = (int)strlen(s)) > len) /* If enough room... */
+ return(NULL);
+ ckstrncpy(buf+x,s,len); /* ... append the filename */
+ debug(F110,"zfnqfp buf 2",buf,0);
+ } else {
+ return(NULL);
+ }
+ }
+
+ /* Buf now holds full path but maybe containing some . or .. tricks */
+
+ j = x + y; /* Length of what's in buf */
+ len = j;
+ debug(F101,"zfnqfp len","",len);
+
+ /* Catch dangling "/." or "/.." */
+ if ((j > 1 && buf[j-1] == '.' && buf[j-2] == '/') ||
+ (j > 2 && buf[j-1] == '.' && buf[j-2] == '.' && buf[j-3] == '/')) {
+ if (j < buflen - 2) {
+ buf[j] = '/';
+ buf[j+1] = NUL;
+ }
+ }
+ j = -1; /* j = position of rightmost "/" */
+ i = 0; /* i = destination index */
+ tmp[i] = NUL; /* destination is temporary buffer */
+
+ for (x = 0; x < len; x++) { /* x = source index */
+ if (buf[x] == '/') {
+ for (k = 0; k < 4; k++) {
+ sb[k] = buf[x+k];
+ sb[k+1] = '\0';
+ if (!sb[k]) break;
+ }
+ if (!strncmp(sb,"/./",3)) { /* Eliminate "./" in "/./" */
+ x += 1;
+ continue;
+ } else if (!strncmp(sb,"//",2)) { /* Change "//" to "/" */
+ continue;
+ } else if (!strncmp(sb,"/../",4)) { /* ".." in path */
+ for (k = i - 1; k >= 0; k--) { /* Back up one level */
+ if (tmp[k] == '/') {
+ i = k;
+ tmp[i] = NUL;
+ break;
+ }
+ }
+ x += 2;
+ continue;
+ }
+ }
+ if (i >= (buflen - 1)) {
+ debug(F111,"zfnqfp overflow",tmp,i);
+ return(NULL);
+ }
+ tmp[i++] = buf[x]; /* Regular character, copy */
+ tmp[i] = NUL;
+ if (buf[x] == '/') /* Remember rightmost "/" */
+ j = i;
+ }
+ ckstrncpy(buf,tmp,buflen-1); /* Copy the result back */
+
+ buf[buflen-1] = NUL;
+ if (!buf[0]) { /* If empty, say root */
+ buf[0] = '/';
+ buf[2] = NUL;
+ j = 0;
+ i = 1;
+ }
+ if ((itsadir = isdir(buf))) {
+ if (buf[i-1] != '/' && i < (buflen - 1)) {
+ buf[i++] = '/';
+ buf[i] = NUL;
+ }
+ }
+ if (!itsadir && (j > -1)) { /* Set pointer to basename */
+ fnfp.fname = (char *)(buf + j);
+ fnfp.fpath = (char *)buf;
+ fnfp.len = i;
+ debug(F111,"zfnqfp path",fnfp.fpath,i);
+ debug(F110,"zfnqfp name",fnfp.fname,0);
+ return(&fnfp);
+ }
+ return(NULL);
+}
+
+/* Z C M P F N -- Compare two filenames */
+
+/* Returns 1 if the two names refer to the same existing file, 0 otherwise. */
+
+int
+zcmpfn(s1,s2) char * s1, * s2; {
+ char buf1[CKMAXPATH+1];
+ char buf2[CKMAXPATH+1];
+
+#ifdef USE_LSTAT
+ char linkname[CKMAXPATH+1];
+ struct stat buf;
+#endif /* USE_LSTAT */
+ int x, rc = 0;
+
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ if (!*s1 || !*s2) return(0);
+
+#ifdef CKSYMLINK /* We're doing symlinks? */
+#ifdef USE_LSTAT /* OK to use lstat()? */
+ x = lstat(s1,&buf);
+ if (x > -1 && /* Now see if it's a symlink */
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ ) {
+ linkname[0] = '\0'; /* Get the name */
+ x = readlink(s1,linkname,CKMAXPATH);
+ if (x > -1 && x < CKMAXPATH) { /* It's a link */
+ linkname[x] = '\0';
+ s1 = linkname;
+ }
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+
+ if (zfnqfp(s1,CKMAXPATH,buf1)) { /* Convert to full pathname */
+
+#ifdef CKSYMLINK /* Same deal for second name... */
+#ifdef USE_LSTAT
+ x = lstat(s2,&buf);
+ if (x > -1 &&
+#ifdef S_ISLNK
+ S_ISLNK(buf.st_mode)
+#else
+#ifdef _IFLNK
+ ((_IFMT & buf.st_mode) == _IFLNK)
+#endif /* _IFLNK */
+#endif /* S_ISLNK */
+ ) {
+ linkname[0] = '\0';
+ x = readlink(s2,linkname,CKMAXPATH);
+ if (x > -1 && x < CKMAXPATH) {
+ linkname[x] = '\0';
+ s2 = linkname;
+ }
+ }
+#endif /* USE_LSTAT */
+#endif /* CKSYMLINK */
+ if (zfnqfp(s2,CKMAXPATH,buf2)) {
+ debug(F110,"zcmpfn s1",buf1,0);
+ debug(F110,"zcmpfn s2",buf2,0);
+ if (!strncmp(buf1,buf2,CKMAXPATH))
+ rc = 1;
+ }
+ }
+ debug(F101,"zcmpfn result","",rc);
+ return(rc);
+}
+
+#ifdef CKROOT
+
+/* User-mode chroot() implementation */
+
+int
+zsetroot(s) char * s; { /* Sets the root */
+ char buf[CKMAXPATH+1];
+ if (!s) return(-1);
+ if (!*s) return(-1);
+ debug(F110,"zsetroot",s,0);
+ if (!isdir(s)) return(-2);
+ if (!zfnqfp(s,CKMAXPATH,buf)) /* Get full, real path */
+ return(-3);
+ if (access(buf,R_OK) < 0) { /* Check access */
+ debug(F110,"zsetroot access denied",buf,0);
+ return(-4);
+ }
+ s = buf;
+ if (ckrootset) { /* If root already set */
+ if (!zinroot(s)) { /* make sure new root is in it */
+ debug(F110,"zsetroot new root not in root",ckroot,0);
+ return(-5);
+ }
+ }
+ if (zchdir(buf) < 1) return(-4); /* Change directory to new root */
+ ckrootset = ckstrncpy(ckroot,buf,CKMAXPATH); /* Now set the new root */
+ if (ckroot[ckrootset-1] != '/') {
+ ckroot[ckrootset++] = '/';
+ ckroot[ckrootset] = '\0';
+ }
+ debug(F111,"zsetroot rootset",ckroot,ckrootset);
+ ckrooterr = 0; /* Reset error flag */
+ return(1);
+}
+
+char *
+zgetroot() { /* Returns the root */
+ if (!ckrootset)
+ return(NULL);
+ return((char *)ckroot);
+}
+
+int
+zinroot(s) char * s; { /* Checks if file s is in the root */
+ int x, n;
+ struct zfnfp * f = NULL;
+ char buf[CKMAXPATH+2];
+
+ debug(F111,"zinroot setroot",ckroot,ckrootset);
+ ckrooterr = 0; /* Reset global error flag */
+ if (!ckrootset) /* Root not set */
+ return(1); /* so it's ok - no need to check */
+ if (!(f = zfnqfp(s,CKMAXPATH,buf))) /* Get full and real pathname */
+ return(0); /* Fail if we can't */
+ n = f->len; /* Length of full pathname */
+ debug(F111,"zinroot n",buf,n);
+ if (n < (ckrootset - 1) || n > CKMAXPATH) { /* Bad length */
+ ckrooterr = 1; /* Fail */
+ return(0);
+ }
+ if (isdir(buf) && buf[n-1] != '/') { /* If it's a directory name */
+ buf[n++] = '/'; /* make sure it ends with '/' */
+ buf[n] = '\0';
+ }
+ x = strncmp(buf,ckroot,ckrootset); /* Compare, case-sensitive */
+ debug(F111,"zinroot checked",buf,x);
+ if (x == 0) /* OK */
+ return(1);
+ ckrooterr = 1; /* Not OK */
+ return(0);
+}
+#endif /* CKROOT */
+
+#ifdef CK_LOGIN
+/*
+ The following code provides support for user login and logout
+ including anonymous accounts. If this feature is to be supported
+ outside of UNIX, it should be spread out among the ck?fio.c modules...
+*/
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL "/usr/bin/bash"
+#endif /* _PATH_BSHELL */
+#ifndef _PATH_FTPUSERS
+#define _PATH_FTPUSERS "/etc/ftpusers"
+#endif /* _PATH_FTPUSERS */
+
+/*
+ * Helper function for sgetpwnam().
+ */
+char *
+sgetsave(s) char *s; {
+ char *new = malloc((unsigned) strlen(s) + 1);
+ if (new == NULL) {
+ printf("?Local resource failure: malloc\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ (void) strcpy(new, s); /* safe */
+ return (new);
+}
+
+/*
+ * Save the result of getpwnam(). Used for USER command, since
+ * the data returned must not be clobbered by any other command
+ * (e.g., globbing).
+ */
+struct passwd *
+sgetpwnam(name) char *name; {
+ static struct passwd save;
+ register struct passwd *p;
+#ifdef CK_SHADOW
+ register struct spwd *sp;
+#endif /* CK_SHADOW */
+ char *sgetsave();
+
+#ifdef HPUX10_TRUSTED
+ struct pr_passwd *pr;
+#endif /* HPUX10_TRUSTED */
+
+#ifdef CK_SHADOW
+ sp = getspnam(name);
+ debug(F111,"sgetpwnam","getspnam()",sp);
+ if (sp == NULL)
+ return (NULL);
+#endif /* CK_SHADOW */
+
+#ifdef HPUX10_TRUSTED
+ if ((pr = getprpwnam(name)) == NULL)
+ return(NULL);
+#endif /* HPUX10_TRUSTED */
+
+ p = getpwnam(name);
+ debug(F111,"sgetpwnam","getpwnam()",p);
+ if (p == NULL)
+ return(NULL);
+ if (save.pw_name) {
+ free(save.pw_name);
+ free(save.pw_passwd);
+ free(save.pw_gecos);
+ free(save.pw_dir);
+ free(save.pw_shell);
+ }
+ save = *p;
+ save.pw_name = sgetsave(p->pw_name);
+#ifdef CK_SHADOW
+ save.pw_passwd = sgetsave(sp->sp_pwdp);
+#else /* CK_SHADOW */
+#ifdef HPUX10_TRUSTED
+ if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
+ save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
+ else
+ save.pw_passwd = sgetsave("");
+#else /* HPUX10_TRUSTED */
+ save.pw_passwd = sgetsave(p->pw_passwd);
+#endif /* HPUX10_TRUSTED */
+#endif /* CK_SHADOW */
+ save.pw_gecos = sgetsave(p->pw_gecos);
+ save.pw_dir = sgetsave(p->pw_dir);
+ save.pw_shell = sgetsave(p->pw_shell);
+ return(&save);
+}
+
+#define CKXLOGBSIZ 256
+
+struct passwd * pw = NULL;
+char * home = NULL; /* Home directory pointer for glob */
+#ifdef CMASK
+#undef CMASK
+#endif /* CMASK */
+
+#define CMASK 027
+
+int defumask = CMASK; /* Default umask value */
+
+/* Z V U S E R -- Verify user, Returns 1 if user OK, 0 otherwise. */
+
+/* Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected. If logged in previously,
+ * need to reset state. If name is "ftp" or "anonymous", the name is not in
+ * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway. Otherwise, check user
+ * requesting login privileges. Disallow anyone who does not have a standard
+ * shell as returned by getusershell(). Disallow anyone mentioned in the file
+ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
+ */
+_PROTOTYP(static int checkuser, (char *) );
+
+char zvuname[64] = { NUL, NUL };
+char zvhome[CKMAXPATH+1] = { NUL, NUL };
+#define ZENVUSER 70
+#define ZENVHOME CKMAXPATH+12
+#define ZENVLOGNAME 74
+static char zenvuser[ZENVUSER];
+static char zenvhome[ZENVHOME];
+static char zenvlogname[ZENVLOGNAME];
+
+#ifdef CK_PAM
+static char pam_data[500];
+struct pam_conv pam_conv = {pam_cb, pam_data}; /* PAM structure */
+struct pam_handle * pamh = NULL; /* PAM reference handle */
+#endif /* CK_PAM */
+
+int
+zvuser(name) char *name; {
+ register char *cp = NULL;
+ int x;
+ char *shell;
+#ifdef GETUSERSHELL
+ char *getusershell();
+#endif /* GETUSERSHELL */
+
+#ifdef CK_PAM
+ int pam_status;
+ const char * reply = NULL;
+#endif /* CK_PAM */
+
+ debug(F111,"user",name,logged_in);
+
+ if (!name) name = "";
+ zvuname[0] = NUL;
+
+ debug(F101,"zvuser ckxsyslog","",ckxsyslog);
+
+#ifdef CKSYSLOG
+ debug(F100,"zvuser CKSYSLOG defined","",0);
+#endif /* CKSYSLOG */
+
+ if (logged_in) /* Should not be called if logged in */
+ return(0);
+
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: user %s",name
+ );
+ }
+#endif /* CKSYSLOG */
+
+ guest = 0; /* Assume not guest */
+ askpasswd = 0;
+
+ if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
+ debug(F101,"zvuser anonymous ckxanon","",ckxanon);
+ if (!ckxanon) { /* Anonymous login not allowed */
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous login not allowed: %s",
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+ if (checkuser("ftp") || checkuser("anonymous")) {
+ debug(F100,"zvuser anon forbidden by ftpusers file","",0);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous login forbidden by ftpusers file: %s",
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ } else if ((pw = sgetpwnam("ftp")) != NULL) {
+ debug(F100,"zvuser anon sgetpwnam(ftp) OK","",0);
+ guest = 1;
+ askpasswd = 1;
+ ckstrncpy(zvuname,"anonymous",64);
+ return(1);
+ } else {
+ debug(F100,"zvuser anon sgetpwnam(ftp) FAILED","",0);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous getpwnam(ftp) failed: %s",
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+ }
+ pw = sgetpwnam(name);
+ if (pw) {
+/*
+ Of course some UNIX platforms (like AIX) don't have getusershell().
+ In that case we can't check if the user's account has been "turned off"
+ or somesuch, e.g. by setting their shell to "/etc/nologin" or somesuch,
+ which runs (usually just printing a message and exiting), but which is
+ not listed in /etc/shells. For that matter, if getusershell() is not
+ available, then probably neither is /etc/shells.
+*/
+ debug(F100,"zvuser sgetpwnam ok","",0);
+ shell = pw->pw_shell;
+ if (!shell) shell = "";
+ if (!*shell)
+ shell = _PATH_BSHELL;
+ debug(F110,"zvuser shell",shell,0);
+#ifdef GETUSERSHELL
+ while ((cp = getusershell()) != NULL) {
+ debug(F110,"zvuser getusershell",cp,0);
+ if (strcmp(cp, shell) == 0)
+ break;
+ }
+ debug(F100,"zvuser endusershell 1","",0);
+ endusershell();
+ debug(F100,"zvuser endusershell 2","",0);
+#else /* GETUSERSHELL */
+ cp = ""; /* Do not refuse if we cannot check */
+#endif /* GETUSERSHELL */
+ x = checkuser(name);
+ debug(F101,"zvuser checkuser","",x);
+ if (cp == NULL) {
+ debug(F100,"zvuser refused 1","",0);
+ pw = (struct passwd *) NULL;
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: invalid shell %s for %s %s",shell, name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ } else if (x) {
+ debug(F100,"zvuser refused 2","",0);
+ pw = (struct passwd *) NULL;
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: %s login forbidden by ftpusers file: %s",
+ name, clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ } else {
+ x = 0;
+#ifdef CK_PAM
+ /* Get PAM authentication details */
+ debug(F110,"zvuser","calling pam_start",0);
+ if ((pam_status =
+ pam_start(PAM_SERVICE_TYPE,name,&pam_conv,&pamh))
+ != PAM_SUCCESS) {
+ reply = pam_strerror(NULL, pam_status);
+ debug(F110,"zvuser PAM failure",reply,0);
+ printf("%s\n",reply);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: %s refused by PAM \"%s\": %s",
+ name,reply,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+#endif /* CK_PAM */
+ askpasswd = 1;
+ ckstrncpy(zvuname,name,64);
+ return(1);
+ }
+ } else {
+ x = 0;
+ debug(F100,"zvuser sgetpwnam NULL","",0);
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: getpwnam(%s) failed: %s",name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+
+#ifdef FTP_KERBEROS
+ if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) {
+#ifdef COMMENT
+ /* Why sprintf and then printf? */
+ /* Also, what is kerb_ok? And is the test on it right? */
+ char buf[CKXLOGBSIZ];
+ sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s%s",
+ kdata.pname, *kdata.pinst ? "." : "",
+ kdata.pinst, kdata.prealm,
+ (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not",
+ name, kerb_ok ? "" : "; Password required.");
+ printf("%s", buf);
+#else
+ printf("Kerberos user %s%s%s@%s is%s authorized as %s%s",
+ kdata.pname, *kdata.pinst ? "." : "",
+ kdata.pinst, kdata.prealm,
+ (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not",
+ name, kerb_ok ? "" : "; Password required.");
+#endif /* COMMENT */
+ if (kerb_ok) return(1);
+ } else
+ return(0);
+#endif /* FTP_KERBEROS */
+}
+
+/* Check if the given user is in the forbidden-user file */
+
+static int
+checkuser(name) char *name; {
+ extern char * userfile;
+ FILE *fd;
+ int i;
+ char line[CKXLOGBSIZ+1];
+
+ if (!name)
+ name = "";
+ i = strlen(name);
+ debug(F111,"checkuser name",name,i);
+ if (!*name)
+ return(1);
+
+ fd = fopen(userfile ? userfile : _PATH_FTPUSERS, "r");
+ debug(F111,"checkuser userfile",userfile,fd);
+ if (fd) {
+ line[0] = '\0';
+ while (fgets(line, sizeof(line), fd)) {
+ debug(F110,"checkuser line",line,0);
+ if (line[0] <= '#')
+ continue;
+ if (strncmp(line, name, i) == 0) {
+ debug(F110,"checkuser REFUSED",name,0);
+ return(1);
+ }
+ line[0] = '\0';
+ }
+ (VOID) fclose(fd);
+ }
+ debug(F110,"checkuser OK",name,0);
+ return(0);
+}
+
+/* Z V L O G O U T -- Log out from Internet Kermit Service */
+
+VOID
+zvlogout() {
+#ifdef COMMENT
+ /* This could be dangerous */
+ if (setuid((UID_T)0) < 0) {
+ debug(F100,"zvlogout setuid FAILED","",0);
+ goto bad;
+ }
+ debug(F100,"zvlogout setuid OK","",0);
+#endif /* COMMENT */
+#ifdef CKSYSLOG
+ if (ckxsyslog >= SYSLG_LI && ckxlogging) {
+ cksyslog(SYSLG_LI, 1, "logout",(char *) uidbuf, clienthost);
+ }
+#endif /* CKSYSLOG */
+#ifdef CKWTMP
+ debug(F110,"WTMP logout",cksysline,logged_in);
+ if (logged_in)
+ logwtmp(cksysline, "", "");
+#endif /* CKWTMP */
+ pw = NULL;
+ logged_in = 0;
+ guest = 0;
+ isguest = 0;
+}
+
+#ifdef FTP_KERBEROS
+kpass(name, p) char *name, *p; {
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ char tkt_file[20];
+ KTEXT_ST ticket;
+ AUTH_DAT authdata;
+ unsigned long faddr;
+ struct hostent *hp;
+
+ if (krb_get_lrealm(realm, 1) != KSUCCESS)
+ return(0);
+
+ ckstrncpy(tkt_file, TKT_ROOT, 20);
+ ckstrncat(tkt_file, "_ftpdXXXXXX", 20);
+ krb_set_tkt_string(mktemp(tkt_file));
+
+ (VOID) ckstrncpy(instance, krb_get_phost(hostname), sizeof(instance));
+
+ if ((hp = gethostbyname(instance)) == NULL)
+ return(0);
+
+#ifdef HADDRLIST
+ hp = ck_copyhostent(hp); /* safe copy that won't change */
+#endif /* HADDRLIST */
+ bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
+
+ if (krb_get_pw_in_tkt(name, "", realm, "krbtgt", realm, 1, p) ||
+ krb_mk_req(&ticket, "rcmd", instance, realm, 33) ||
+ krb_rd_req(&ticket, "rcmd", instance, faddr, &authdata, "") ||
+ kuserok(&authdata, name)) {
+ dest_tkt();
+ return(0);
+ }
+ dest_tkt();
+ return(1);
+}
+#endif /* FTP_KERBEROS */
+
+VOID
+zsyslog() {
+#ifdef CKSYSLOG
+ if (ckxsyslog && !ckxlogging) {
+#ifdef LOG_DAEMON
+ openlog(inserver ? "iksd" : "ckermit", LOG_PID, LOG_DAEMON);
+#else
+ openlog(inserver ? "iksd" : "ckermit", LOG_PID);
+#endif /* LOG_DAEMON */
+ ckxlogging = 1;
+ debug(F100,"zsyslog syslog opened","",0);
+ }
+#endif /* CKSYSLOG */
+}
+
+/* Z V P A S S -- Verify password; returns 1 if OK, 0 otherwise */
+
+#ifndef AUTH_USER
+#define AUTH_USER 3
+#endif /* AUTH_USER */
+#ifndef AUTH_VALID
+#define AUTH_VALID 4
+#endif /* AUTH_VALID */
+
+int
+zvpass(p) char *p; {
+ char *xpasswd, *salt;
+ char * dir = NULL;
+#ifdef CK_PAM
+ int pam_status;
+ const char * reply = NULL;
+#endif /* CK_PAM */
+
+ if (logged_in || askpasswd == 0) {
+ return(0);
+ }
+ debug(F111,"zvpass",p ? (guest ? p : "xxxxxx") : "(null)",guest);
+ if (!p) p = "";
+ askpasswd = 0;
+ if (guest && !*p) { /* Guests must specify a password */
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous guests must specify a password"
+ );
+ }
+#endif /* CKSYSLOG */
+ return(0);
+ }
+ if (!guest
+#ifdef CK_AUTHENTICATION
+ && ck_tn_auth_valid() != AUTH_VALID
+#endif /* CK_AUTHENTICATION */
+ ) { /* "ftp" is only account allowed no password */
+#ifdef CK_PAM
+ debug(F110,"zvpass","calling pam_set_item(AUTHTOK)",0);
+ if ((pam_status = pam_set_item(pamh,PAM_AUTHTOK,p)) != PAM_SUCCESS) {
+ reply = pam_strerror(pamh, pam_status);
+ debug(F110,"zvpass PAM failure",reply,0);
+ /* if no password given treat as non-fatal error */
+ /* pam will prompt for password in pam_authenticate() */
+ if (!p) {
+ printf("%s\n",reply);
+ pam_end(pamh, 0);
+ debug(F100,"zvpass denied","",0);
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+ }
+ debug(F110,"zvpass","calling pam_authenticate",0);
+ if (*p)
+ pam_pw = p;
+ if ((pam_status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
+ reply = pam_strerror(pamh, pam_status);
+ debug(F110,"zvpass PAM failure",reply,0);
+ printf("%s\n",reply);
+ pam_end(pamh, 0);
+ debug(F100,"zvpass denied","",0);
+ pam_pw = NULL;
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+ pam_pw = NULL;
+ debug(F110,"zvpass","calling pam_acct_mgmt",0);
+ if ((pam_status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
+ reply = pam_strerror(pamh, pam_status);
+ debug(F110,"zvpass PAM failure",reply,0);
+ printf("%s\n",reply);
+ pam_end(pamh, 0);
+ debug(F100,"zvpass denied","",0);
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+ debug(F110,"zvpass","PAM validates OK",0);
+ pam_end(pamh,0);
+#else /* CK_PAM */
+ if (pw == NULL)
+ salt = "xx";
+ else
+ salt = pw->pw_passwd;
+
+#ifdef HPUX10_TRUSTED
+ xpasswd = bigcrypt(p, salt);
+#else
+/*
+ On 64-bit platforms this can give "cast to pointer from integer of
+ different size" warning, but I'm not sure what the effect is at runtime,
+ or what to do about it.
+ */
+ xpasswd = (char *)crypt(p, salt);
+#endif /* HPUX10_TRUSTED */
+
+ if (
+#ifdef FTP_KERBEROS
+ /* null pw_passwd ok if Kerberos password ok */
+ pw == NULL ||
+ ((*pw->pw_passwd != '\0' ||
+ strcmp(xpasswd, pw->pw_passwd))
+ && !kpass(pw->pw_name, p))
+#else
+#ifdef CK_SRP
+ /* check with tpasswd first if there */
+ pw == NULL || *pw->pw_passwd == '\0' ||
+ t_verifypw (pw->pw_name, p) == 0 ||
+ (t_verifypw (pw->pw_name, p) < 0 &&
+ strcmp (xpasswd, pw->pw_passwd))
+#else /* CK_SRP */
+ /* The strcmp does not catch null passwords! */
+ (pw == NULL) || (*pw->pw_passwd == '\0') ||
+ strcmp(xpasswd, pw->pw_passwd)
+#endif /* CK_SRP */
+#endif /* FTP_KERBEROS */
+ ) {
+ debug(F100,"zvpass denied","",0);
+ pw = NULL;
+ zvuname[0] = NUL;
+ return(0);
+ }
+#endif /* CK_PAM */
+ }
+
+ (VOID) setgid((GID_T)pw->pw_gid); /* Set group ID */
+
+#ifndef NOINITGROUPS
+ (VOID) initgroups(pw->pw_name, pw->pw_gid);
+#endif /* NOINITGROUPS */
+
+ logged_in = 1;
+ dir = pw->pw_dir;
+
+#ifdef CKWTMP
+ /* Open wtmp before chroot */
+ if (ckxwtmp) {
+ sprintf(cksysline,"iks_%04x", getpid()); /* safe */
+ logwtmp(cksysline, pw->pw_name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+ debug(F110,"WTMP login",cksysline,logged_in);
+ }
+#endif /* CKWTMP */
+/*
+ For anonymous users, we chroot to user ftp's home directory unless
+ started with --anonroot:xxx, in which case we chroot to xxx. We must
+ immediately chdir() to the same directory we chroot() to or else the
+ old current directory remains accessible as "." outside the new root.
+*/
+ if (guest) {
+ if (anonroot) /* Non-default anonymous root */
+ dir = anonroot;
+ else
+ makestr(&anonroot,dir);
+ errno = 0;
+ debug(F110,"zvpass anon chroot",dir,0);
+ if (chroot(dir) < 0) {
+ debug(F111,"zvpass anon chroot FAILED",dir,errno);
+ goto bad;
+ }
+ errno = 0;
+ if (chdir("/") < 0) {
+ debug(F111,"zvpass anon chdir FAILED",dir,errno);
+ goto bad;
+ }
+ debug(F110,"zvpass anon chroot/chdir OK",dir,0);
+ } else if (chdir(dir) < 0) { /* Not guest */
+#ifdef COMMENT
+ if (chdir("/") < 0) {
+ debug(F110,"Non-guest chdir FAILED",dir,0);
+ goto bad;
+ } else
+ printf("?No directory! Logging in with home=/\n");
+#else
+ debug(F110,"zvpass non-guest chdir FAILED",dir,0);
+ goto bad; /* Be conservative at first */
+#endif /* COMMENT */
+ }
+ debug(F110,"zvpass non-guest chdir OK",dir,0);
+ if (setuid((UID_T)pw->pw_uid) < 0) {
+ debug(F101,"zvpass setuid FAILED","",pw->pw_uid);
+ goto bad;
+ }
+ debug(F101,"zvpass setuid OK","",pw->pw_uid);
+
+ guestpass[0] = '\0';
+ if (guest) {
+ extern int fncact;
+ isguest = 1;
+ fncact = XYFX_R; /* FILE COLLISION = RENAME */
+ debug(F110,"GUEST fncact=R",p,0);
+ lset(guestpass,"anonymous:",10,32);
+ ckstrncpy(&guestpass[10],p,GUESTPASS-10);
+ home = "/";
+ printf("Anonymous login.\r\n");
+
+#ifdef SETPROCTITLE
+ /* proctitle declared where? Obviously this code is never compiled. */
+ sprintf(proctitle, "%s: anonymous/%.*s",
+ clienthost ? clienthost : "(unk)",
+ sizeof(proctitle) - sizeof(clienthost) -
+ sizeof(": anonymous/"), p);
+ setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging) {
+ syslog(LOG_INFO,
+ "login: anonymous %s %s",
+ clienthost ? clienthost : "(unknown host)",
+ p
+ );
+ }
+#endif /* CKSYSLOG */
+
+ } else { /* Real user */
+ isguest = 0;
+ home = dir;
+ ckstrncpy(guestpass,zvuname,GUESTPASS);
+
+ printf("User %s logged in.\r\n", pw->pw_name);
+#ifdef SETPROCTITLE
+ /* not used */
+ sprintf(proctitle, "%s: %s",
+ clienthost ? clienthost : "(unk)",
+ pw->pw_name
+ );
+ setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+
+#ifdef CKSYSLOG
+ if (ckxsyslog && ckxlogging)
+ syslog(LOG_INFO, "login: %s %s",
+ pw->pw_name,
+ clienthost ? clienthost : "(unknown host)"
+ );
+#endif /* CKSYSLOG */
+ }
+ ckstrncpy(zvhome,home,CKMAXPATH); /* Set environment variables */
+#ifndef NOPUTENV
+
+ ckmakmsg(zenvuser,ZENVUSER,"USER=",zvuname,NULL,NULL);
+ putenv((char *)zenvuser);
+ ckmakmsg(zenvlogname,ZENVLOGNAME,"LOGNAME=",zvuname,NULL,NULL);
+ putenv((char *)zenvlogname);
+ ckmakmsg(zenvhome,ZENVHOME,"HOME=",zvhome,NULL,NULL);
+ putenv((char *)zenvhome);
+#endif /* NOPUTENV */
+ /* homdir = (char *)zvhome; */
+ ckstrncpy((char *)uidbuf,(char *)zvuname,64);
+ (VOID) umask(defumask);
+#ifdef IKSDB
+ if (ikdbopen) {
+ char * p2;
+ int k;
+ extern char dbrec[];
+ extern unsigned long myflags;
+ extern unsigned int mydbslot;
+ extern struct iksdbfld dbfld[];
+#ifdef CK_AUTHENTICATION
+ extern unsigned long myamode, myatype;
+#endif /* CK_AUTHENTICATION */
+ myflags |= DBF_LOGGED;
+#ifdef DEBUG
+ if (deblog) {
+ debug(F101,"zvpass guest","",guest);
+ debug(F111,"zvpass zvuname",zvuname,0);
+ debug(F110,"zvpass guestpass",guestpass,0);
+ debug(F110,"zvpass dir",dir,0);
+ debug(F110,"zvpass home",home,0);
+ debug(F110,"zvpass anonroot",anonroot,0);
+ }
+#endif /* DEBUG */
+ p2 = guest ? guestpass : zvuname;
+ if (guest) {
+ p2 = (char *)guestpass;
+ myflags &= ~DBF_USER;
+ } else {
+ p2 = (char *)zvuname;
+ myflags |= DBF_USER;
+ }
+ k = strlen(p2);
+ strncpy(&dbrec[DB_ULEN],ulongtohex((unsigned long)k,4),4);
+ lset(&dbrec[dbfld[db_USER].off],p2,1024,32);
+ strncpy(&dbrec[DB_FLAGS],ulongtohex(myflags,4),4);
+#ifdef CK_AUTHENTICATION
+ myamode = ck_tn_auth_valid();
+ strncpy(&dbrec[DB_AMODE],ulongtohex(myamode,4),4);
+ myatype = ck_tn_authenticated();
+ strncpy(&dbrec[DB_ATYPE],ulongtohex(myatype,4),4);
+#endif /* CK_AUTHENTICATION */
+ if (guest) {
+ p2 = dir;
+ } else {
+ p2 = zgtdir();
+ if (!p2) p2 = "";
+ if (!*p2) p2 = home;
+ }
+ strncpy(&dbrec[DB_DLEN],
+ ulongtohex((unsigned long)strlen(p2),4),
+ 4
+ );
+ lset(&dbrec[dbfld[db_DIR].off],p2,1024,32);
+ updslot(mydbslot);
+ }
+#endif /* IKSDB */
+ return(1);
+
+bad: /* Common failure exit */
+ zvuname[0] = NUL;
+ zvlogout();
+ return(0);
+}
+#endif /* CK_LOGIN */
+
+/* Buggy Xenix 2.3.4 cc needs this line after the endif */
--- /dev/null
+#include "ckcsym.h"
+
+/* C K U U S 7 -- "User Interface" for C-Kermit, part 7 */
+
+/*
+ Authors:
+ Frank da Cruz <fdc@columbia.edu>,
+ The Kermit Project, Columbia University, New York City
+ Jeffrey E Altman <jaltman@secure-endpoints.com>
+ Secure Endpoints Inc., New York City
+
+ Copyright (C) 1985, 2004,
+ Trustees of Columbia University in the City of New York.
+ All rights reserved. See the C-Kermit COPYING.TXT file or the
+ copyright text in the ckcmai.c module for disclaimer and permissions.
+*/
+
+/*
+ This file created from parts of ckuus3.c, which became too big for
+ Mark Williams Coherent compiler to handle.
+*/
+
+/*
+ Definitions here supersede those from system include files.
+*/
+#include "ckcdeb.h" /* Debugging & compiler things */
+#include "ckcasc.h" /* ASCII character symbols */
+#include "ckcker.h" /* Kermit application definitions */
+#include "ckcxla.h" /* Character set translation */
+#include "ckcnet.h" /* Network symbols */
+#include "ckuusr.h" /* User interface symbols */
+#include "ckucmd.h"
+#include "ckclib.h"
+
+#ifdef VMS
+#ifndef TCPSOCKET
+#include <errno.h>
+#endif /* TCPSOCKET */
+#endif /* VMS */
+
+#ifdef OS2
+#ifndef NT
+#define INCL_NOPM
+#define INCL_VIO /* Needed for ckocon.h */
+#define INCL_DOSMODULEMGR
+#include <os2.h>
+#undef COMMENT
+#else /* NT */
+#define APIRET ULONG
+#include <windows.h>
+#include <tapi.h>
+#include "cknwin.h"
+#include "ckntap.h"
+#endif /* NT */
+#include "ckowin.h"
+#include "ckocon.h"
+#include "ckodir.h"
+#ifdef OS2MOUSE
+#include "ckokey.h"
+#endif /* OS2MOUSE */
+#ifdef KUI
+#include "ikui.h"
+#endif /* KUI */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+extern int mskkeys;
+#endif /* OS2 */
+
+#ifdef CK_AUTHENTICATION
+#include "ckuath.h"
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_SSL
+#include "ck_ssl.h"
+#endif /* CK_SSL */
+#ifdef SSHBUILTIN
+#include "ckossh.h"
+#endif /* SSHBUILTIN */
+#ifdef STRATUS /* Stratus Computer, Inc. VOS */
+#ifdef putchar
+#undef putchar
+#endif /* putchar */
+#define putchar(x) conoc(x)
+#ifdef getchar
+#undef getchar
+#endif /* getchar */
+#define getchar(x) coninc(0)
+#endif /* STRATUS */
+
+char * slmsg = NULL;
+
+static int x, y = 0, z;
+static char *s;
+
+extern CHAR feol;
+extern int g_matchdot, hints, xcmdsrc, rcdactive;
+
+extern char * k_info_dir;
+
+#ifndef NOSPL
+extern int nmac;
+extern struct mtab *mactab;
+#endif /* NOSPL */
+
+#ifndef NOXFER
+#ifdef CK_SPEED
+extern short ctlp[]; /* Control-char prefixing table */
+#endif /* CK_SPEED */
+
+#ifdef PIPESEND
+extern char * sndfilter, * g_sfilter;
+extern char * rcvfilter, * g_rfilter;
+#endif /* PIPESEND */
+
+extern char * snd_move;
+extern char * snd_rename;
+extern char * g_snd_move;
+extern char * g_snd_rename;
+extern char * rcv_move;
+extern char * rcv_rename;
+extern char * g_rcv_move;
+extern char * g_rcv_rename;
+
+#ifdef PATTERNS
+extern char *binpatterns[], *txtpatterns[];
+extern int patterns;
+#endif /* PATTERNS */
+
+extern char * remdest;
+#ifdef CK_TMPDIR
+char * dldir = NULL;
+#endif /* CK_TMPDIR */
+
+extern struct ck_p ptab[];
+
+extern int protocol, remfile, rempipe, remappd, reliable, xreliable, fmask,
+ fncnv, frecl, maxrps, wslotr, bigsbsiz, bigrbsiz, urpsiz, rpsiz, spsiz,
+ bctr, npad, timef, timint, spsizr, spsizf, maxsps, spmax, nfils, displa,
+ atcapr, pkttim, rtimo, fncact, mypadn, fdispla, f_save, pktpaus, setreliable,
+ fnrpath, fnspath, atenci, atenco, atdati, atdato, atleni, atleno, atblki,
+ atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
+
+extern int stathack;
+
+extern int atfrmi, atfrmo;
+#ifdef STRATUS
+extern int atcrei, atcreo, atacti, atacto;
+#endif /* STRATUS */
+#ifdef CK_PERMS
+extern int atlpri, atlpro, atgpri, atgpro;
+#endif /* CK_PERMS */
+
+extern CHAR
+ sstate, eol, seol, stchr, mystch, mypadc, padch, ctlq, myctlq;
+
+#ifdef IKSD
+extern int inserver;
+#ifdef IKSDCONF
+extern int iksdcf;
+#endif /* IKSDCONF */
+#endif /* IKSD */
+
+extern char *cmarg, *cmarg2;
+
+#ifndef NOFRILLS
+extern char optbuf[]; /* Buffer for MAIL or PRINT options */
+extern int rprintf; /* REMOTE PRINT flag */
+#endif /* NOFRILLS */
+#endif /* NOXFER */
+
+#ifdef CK_TRIGGER
+extern char * tt_trigger[];
+#endif /* CK_TRIGGER */
+
+extern int tcs_transp;
+#ifdef PCTERM
+extern int tt_pcterm;
+#endif /* PCTERM */
+#ifdef NT
+extern int tt_vtnt;
+#endif /* NT */
+
+#ifdef SSHBUILTIN
+int sl_ssh_xfw = 0;
+int sl_ssh_xfw_saved = 0;
+int sl_ssh_ver = 0;
+int sl_ssh_ver_saved = 0;
+#endif /* SSHBUILTIN */
+
+#ifdef CK_AUTHENTICATION
+extern int auth_type_user[];
+int sl_auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_NULL, AUTHTYPE_NULL};
+int sl_auth_saved = 0;
+int sl_topt_a_su = 0;
+int sl_topt_a_s_saved = 0;
+int sl_topt_a_cm = 0;
+int sl_topt_a_c_saved = 0;
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+extern int cx_type;
+int sl_cx_type = 0;
+int sl_cx_saved = 0;
+int sl_topt_e_su = 0;
+int sl_topt_e_sm = 0;
+int sl_topt_e_s_saved = 0;
+int sl_topt_e_cu = 0;
+int sl_topt_e_cm = 0;
+int sl_topt_e_c_saved = 0;
+#endif /* CK_ENCRYPTION */
+extern char uidbuf[];
+static int uidflag = 0;
+char sl_uidbuf[UIDBUFLEN] = { NUL, NUL };
+int sl_uid_saved = 0;
+#ifdef TNCODE
+int sl_tn_wait = 0;
+int sl_tn_saved = 0;
+#endif /* TNCODE */
+
+#ifdef TNCODE
+extern int tn_wait_flg;
+#endif /* TNCODE */
+
+VOID
+slrestor() {
+#ifdef CK_AUTHENTICATION
+ int x;
+ if (sl_auth_saved) {
+ for (x = 0; x < AUTHTYPLSTSZ; x++)
+ auth_type_user[x] = sl_auth_type_user[x];
+ sl_auth_saved = 0;
+ }
+ if (sl_topt_a_s_saved) {
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_su;
+ sl_topt_a_s_saved = 0;
+ }
+ if (sl_topt_a_c_saved) {
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_cm;
+ sl_topt_a_c_saved = 0;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ if (sl_cx_saved) {
+ cx_type = sl_cx_type;
+ sl_cx_saved = 0;
+ }
+ if (sl_topt_e_s_saved) {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = sl_topt_e_su;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_sm;
+ sl_topt_e_s_saved = 0;
+ }
+ if (sl_topt_e_c_saved) {
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cu;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cm;
+ sl_topt_e_c_saved = 0;
+ }
+#endif /* CK_ENCRYPTION */
+ if (sl_uid_saved) {
+ ckstrncpy(uidbuf,sl_uidbuf,UIDBUFLEN);
+ sl_uid_saved = 0;
+ }
+#ifdef TNCODE
+ if (sl_tn_saved) {
+ tn_wait_flg = sl_tn_wait;
+ sl_tn_saved = 0;
+ }
+#endif /* TNCODE */
+#ifdef SSHBUILTIN
+ if (sl_ssh_xfw_saved) {
+ ssh_xfw = sl_ssh_xfw;
+ sl_ssh_xfw_saved = 0;
+ }
+ if (sl_ssh_ver_saved) {
+ ssh_ver = sl_ssh_ver;
+ sl_ssh_ver_saved = 0;
+ }
+#endif /* SSHBUILTIN */
+}
+
+int oldplex = -1; /* Duplex holder around network */
+
+#ifndef NOICP
+#ifdef LOCUS
+extern int locus, autolocus;
+#endif /* LOCUS */
+#ifndef NODIAL
+extern int dialsta;
+#endif /* NODIAL */
+
+/* Note: gcc -Wall wants braces around each keyword table entry. */
+
+static struct keytab psltab[] = { /* SET LINE/PORT command options */
+ { "/connect", SL_CNX, 0 },
+#ifdef OS2ORVMS
+ { "/noshare", SL_NSH, 0 },
+#endif /* OS2ORVMS */
+ { "/server", SL_SRV, 0 },
+#ifdef OS2ORVMS
+ { "/share", SL_SHR, 0 },
+#endif /* OS2ORVMS */
+ { "", 0, 0 }
+};
+static int npsltab = sizeof(psltab)/sizeof(struct keytab) - 1;
+
+#ifdef NETCONN
+static struct keytab shtab[] = { /* SET HOST command options */
+#ifdef NETCMD
+ /* (COMMAND is also a network type) */
+ { "/command", SL_CMD, CM_INV },
+#endif /* NETCMD */
+ { "/connect", SL_CNX, 0 },
+ { "/network-type", SL_NET, CM_ARG },
+ { "/nowait", SL_NOWAIT, 0 },
+#ifndef NOSPL
+#ifdef CK_AUTHENTICATION
+ { "/password", SL_PSW, CM_ARG },
+#endif /* CK_AUTHENTICATION */
+#endif /* NOSPL */
+#ifdef NETCMD
+ { "/pipe", SL_CMD, 0 },
+#endif /* NETCMD */
+#ifdef NETPTY
+ { "/pty", SL_PTY, 0 },
+#endif /* NETPTY */
+ { "/server", SL_SRV, 0 },
+ { "/timeout", SL_TMO, CM_ARG },
+ { "/userid", SL_UID, CM_ARG },
+ { "/wait", SL_WAIT, 0 },
+ { "", 0, 0 }
+};
+static int nshtab = sizeof(shtab)/sizeof(struct keytab) - 1;
+
+static struct keytab shteltab[] = { /* TELNET command options */
+#ifdef CK_AUTHENTICATION
+ { "/auth", SL_AUTH, CM_ARG },
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ { "/encrypt", SL_ENC, CM_ARG },
+#endif /* CK_ENCRYPTION */
+ { "/nowait", SL_NOWAIT, 0 },
+#ifndef NOSPL
+#ifdef CK_AUTHENTICATION
+ { "/password", SL_PSW, CM_ARG },
+#endif /* CK_AUTHENTICATION */
+#endif /* NOSPL */
+ { "/timeout", SL_TMO, CM_ARG },
+ { "/userid", SL_UID, CM_ARG },
+ { "/wait", SL_WAIT, 0 },
+ { "", 0 ,0 }
+};
+static int nshteltab = sizeof(shteltab)/sizeof(struct keytab) - 1;
+
+#ifdef RLOGCODE
+static struct keytab shrlgtab[] = { /* SET HOST RLOGIN command options */
+#ifdef CK_KERBEROS
+#ifdef CK_ENCRYPTION
+ { "/encrypt", SL_ENC, 0 },
+#endif /* CK_ENCRYPTION */
+ { "/k4", SL_KRB4, CM_INV },
+ { "/k5", SL_KRB5, CM_INV },
+ { "/kerberos4", SL_KRB4, 0 },
+ { "/kerberos5", SL_KRB5, 0 },
+ { "/kerberos_iv", SL_KRB4, CM_INV },
+ { "/kerberos_v", SL_KRB5, CM_INV },
+ { "/krb4", SL_KRB4, CM_INV },
+ { "/krb5", SL_KRB5, CM_INV },
+#endif /* CK_KERBEROS */
+ { "", 0 ,0 }
+};
+static int nshrlgtab = sizeof(shrlgtab)/sizeof(struct keytab)-1;
+#endif /* RLOGCODE */
+
+extern struct keytab netcmd[];
+extern int nnets;
+#ifndef NODIAL
+extern int dirline;
+extern int nnetdir; /* Network services directory */
+extern char *netdir[];
+_PROTOTYP( VOID ndreset, (void) );
+char *nh_p[MAXDNUMS + 1]; /* Network directory entry pointers */
+char *nh_p2[MAXDNUMS + 1]; /* Network directory entry nettype */
+char *nh_px[4][MAXDNUMS + 1]; /* Network-specific stuff... */
+#endif /* NODIAL */
+int nhcount = 0;
+int ndinited = 0;
+char * n_name = NULL; /* Network name pointer */
+#endif /* NETCONN */
+
+_PROTOTYP(int remtxt, (char **) );
+_PROTOTYP(VOID rmsg, (void) );
+_PROTOTYP(static int remcfm, (void) );
+
+extern int nopush;
+
+int mdmsav = -1; /* Save modem type around network */
+extern int isguest; /* Global flag for anonymous login */
+
+extern xx_strp xxstring;
+
+extern int success, binary, b_save, ckwarn, msgflg, quiet, cmask, pflag, local,
+ nettype, escape, mdmtyp, duplex, dfloc, network, cdtimo, autoflow, tnlm,
+ sosi, tlevel, lf_opts, backgrd, flow, debses, parity, ttnproto, ckxech,
+ x_ifnum, cmflgs, haveline, cxtype, cxflow[], maclvl;
+
+#ifdef DCMDBUF
+extern struct cmdptr *cmdstk; /* The command stack itself */
+#else
+extern struct cmdptr cmdstk[]; /* The command stack itself */
+#endif /* DCMDBUF */
+extern FILE * tfile[];
+extern char * macp[];
+
+extern char psave[]; /* For saving & restoring prompt */
+extern int sprmlen, rprmlen;
+
+#ifdef OS2
+static struct keytab strmkeytab[] = {
+ { "clear", 0, 0 },
+ { "default", 1, 0 }
+};
+static int nstrmkeytab = sizeof(strmkeytab)/sizeof(struct keytab);
+
+static struct keytab strmswitab[] = {
+ { "/literal", 0, 0 }
+};
+static int nstrmswitab = sizeof(strmswitab)/sizeof(struct keytab);
+
+static struct keytab normrev[] = {
+ { "dark-display", 0, 0 },
+ { "light-display", 1, 0 },
+ { "normal", 0, 0 },
+ { "reverse", 1, 0 }
+};
+
+static struct keytab prnmtab[] = {
+ { "auto", 1, 0 },
+ { "copy", 2, 0 },
+ { "off", 0, 0 },
+ { "on", 1, CM_INV }, /* Compatibility with XPRINT version */
+ { "user", 3, 0 },
+ { "transparent", 3, CM_INV } /* not really transparent */
+};
+static int nprnmtab = sizeof(prnmtab)/sizeof(struct keytab);
+
+extern int tt_diff_upd;
+
+#ifdef NT
+#define stricmp _stricmp
+extern int tt_attr_bug;
+#endif /* NT */
+extern int tt_rows[], tt_cols[];
+extern int tt_cols_usr;
+extern int tt_szchng[VNUM];
+int tt_modechg = TVC_ENA;
+extern int tt_url_hilite, tt_url_hilite_attr;
+extern struct _vtG G[4];
+extern int priority;
+extern bool send_c1;
+int send_c1_usr = FALSE;
+extern int sgrcolors;
+extern int marginbell, marginbellcol;
+extern int autoscroll, wy_autopage;
+extern int tt_sac;
+extern int dec_nrc, dec_lang, dec_kbd;
+#else /* OS2 */
+extern int tt_rows, tt_cols;
+#endif /* OS2 */
+
+extern int tt_escape;
+extern long speed;
+
+extern char *dftty;
+
+extern char *tp, *lp; /* Temporary buffer & pointers */
+extern char ttname[];
+
+#ifdef CK_TAPI
+int tttapi = 0; /* is Line TAPI? */
+struct keytab * tapilinetab = NULL;
+struct keytab * _tapilinetab = NULL;
+int ntapiline = 0;
+#endif /* CK_TAPI */
+
+#ifdef NETCONN /* Network items */
+
+#ifdef ANYX25
+extern int revcall, closgr, cudata, nx25;
+extern char udata[];
+extern struct keytab x25tab[];
+#ifndef IBMX25
+extern int npadx3;
+extern CHAR padparms[];
+extern struct keytab padx3tab[];
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifdef OS2
+extern bool ttshare;
+#ifndef NT
+extern bool ttslip,ttppp;
+#endif /* NT */
+#endif /* OS2 */
+#ifdef NPIPE
+extern char pipename[];
+#endif /* NPIPE */
+
+#ifdef TCPSOCKET
+static struct keytab tcprawtab[] = { /* SET HOST options */
+ { "/default", NP_DEFAULT, CM_INV },
+#ifdef CK_AUTHENTICATION
+#ifdef CK_KERBEROS
+#ifdef RLOGCODE
+ { "/ek4login", NP_EK4LOGIN, 0 },
+ { "/ek5login", NP_EK5LOGIN, 0 },
+ { "/k4login", NP_K4LOGIN, 0 },
+ { "/k5login", NP_K5LOGIN, 0 },
+#endif /* RLOGCODE */
+#ifdef KRB5_U2U
+ { "/k5user2user", NP_K5U2U, 0 },
+#endif /* KRB5_U2U */
+#endif /* CK_KERBEROS */
+#endif /* CK_AUTHENTICATION */
+ { "/no-telnet-init", NP_NONE, 0 },
+ { "/none", NP_NONE, CM_INV },
+ { "/raw-socket", NP_TCPRAW, 0 },
+#ifdef RLOGCODE
+ { "/rlogin", NP_RLOGIN, 0 },
+#endif /* RLOGCODE */
+#ifdef CK_SSL
+ { "/ssl", NP_SSL, 0 },
+ { "/ssl-telnet", NP_SSL_TELNET, 0 },
+#endif /* CK_SSL */
+ { "/telnet", NP_TELNET, 0 },
+#ifdef CK_SSL
+ { "/tls", NP_TLS, 0 },
+ { "/tls-telnet", NP_TLS_TELNET, 0 },
+#endif /* CK_SSL */
+ { "", 0, 0 }
+};
+static int ntcpraw = (sizeof(tcprawtab) / sizeof(struct keytab)) - 1;
+
+#ifdef RLOGCODE
+_PROTOTYP( int rlog_naws, (void) );
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+
+#ifdef SUPERLAT
+extern char slat_pwd[18];
+#endif /* SUPERLAT */
+#endif /* NETCONN */
+
+#ifdef COMMENT
+#ifndef NOSETKEY
+extern KEY *keymap;
+#ifndef OS2
+#define mapkey(x) keymap[x]
+#endif /* OS2 */
+extern MACRO *macrotab;
+#ifndef NOKVERBS
+extern struct keytab kverbs[];
+extern int nkverbs;
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+#else
+#ifndef NOSETKEY
+extern KEY *keymap;
+extern MACRO *macrotab;
+#ifndef NOKVERBS
+extern struct keytab kverbs[];
+extern int nkverbs;
+#endif /* NOKVERBS */
+#endif /* NOSETKEY */
+#endif /* COMMENT */
+
+#ifdef OS2 /* AUTODOWNLOAD parameters */
+extern int adl_kmode, adl_zmode; /* Match Packet to signal download */
+extern char * adl_kstr; /* KERMIT Download String */
+extern char * adl_zstr; /* ZMODEM Download String */
+extern int adl_kc0, adl_zc0; /* Process ADL C0s in emulation */
+#endif /* OS2 */
+
+/* Keyword tables ... */
+
+extern struct keytab onoff[], rltab[];
+extern int nrlt;
+
+#ifndef NOCSETS
+static struct keytab fdfltab[] = {
+ { "7bit-character-set", 7, 0 },
+ { "8bit-character-set", 8, 0 }
+};
+static int nfdflt = (sizeof(fdfltab) / sizeof(struct keytab));
+#endif /* NOCSETS */
+
+/* SET FILE parameters */
+
+static struct keytab filtab[] = {
+#ifndef NOXFER
+#ifdef PATTERNS
+ { "binary-patterns", XYFIBP, 0 },
+#endif /* PATTERNS */
+ { "bytesize", XYFILS, 0 },
+#ifndef NOCSETS
+ { "character-set", XYFILC, 0 },
+#endif /* NOCSETS */
+ { "collision", XYFILX, 0 },
+ { "default", XYF_DFLT, 0 },
+ { "destination", XYFILY, 0 },
+ { "display", XYFILD, CM_INV },
+#ifdef CK_TMPDIR
+ { "download-directory", XYFILG, 0 },
+#endif /* CK_TMPDIR */
+#endif /* NOXFER */
+ { "end-of-line", XYFILA, 0 },
+ { "eol", XYFILA, CM_INV },
+#ifdef CK_CTRLZ
+ { "eof", XYFILV, 0 },
+#endif /* CK_CTRLZ */
+#ifndef NOXFER
+ { "fastlookups", 9997, CM_INV },
+ { "incomplete", XYFILI, 0 },
+#ifndef datageneral
+ { "inspection", XYF_INSP, CM_INV },
+#endif /* datageneral */
+#ifdef CK_LABELED
+ { "label", XYFILL, 0 },
+#endif /* CK_LABELED */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+ { "listsize", XYF_LSIZ, 0 },
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+ { "names", XYFILN, 0 },
+#ifdef UNIX
+ { "output", XYFILH, 0 },
+#endif /* UNIX */
+#ifdef PATTERNS
+ { "patterns", XYFIPA, 0 },
+#endif /* PATTERNS */
+#ifdef COMMENT /* Not implemented (but see CHMOD) */
+ { "permissions", XYF_PRM, CM_INV },
+ { "protection", XYF_PRM, 0 },
+#endif /* COMMENt */
+#ifdef VMS
+ { "record-length", XYFILR, 0 },
+#endif /* VMS */
+#ifndef datageneral
+ { "scan", XYF_INSP, 0 },
+#endif /* datageneral */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+ { "stringspace", XYF_SSPA, 0 },
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+#ifdef PATTERNS
+ { "t", XYFILT, CM_INV|CM_ABR },
+ { "text-patterns", XYFITP, 0 },
+#endif /* PATTERNS */
+#endif /* NOXFER */
+ { "type", XYFILT, 0 },
+#ifdef UNICODE
+ { "ucs", XYFILU, 0 },
+#endif /* UNICODE */
+#ifndef NOXFER
+ { "warning", XYFILW, CM_INV }
+#endif /* NOXFER */
+};
+static int nfilp = (sizeof(filtab) / sizeof(struct keytab));
+
+struct keytab pathtab[] = {
+ { "absolute", PATH_ABS, 0 },
+ { "none", PATH_OFF, CM_INV },
+ { "off", PATH_OFF, 0 },
+ { "on", PATH_ABS, CM_INV },
+ { "relative", PATH_REL, 0 }
+};
+int npathtab = (sizeof(pathtab) / sizeof(struct keytab));
+
+struct keytab rpathtab[] = {
+ { "absolute", PATH_ABS, 0 },
+ { "auto", PATH_AUTO, 0 },
+ { "none", PATH_OFF, CM_INV },
+ { "off", PATH_OFF, 0 },
+ { "on", PATH_ABS, CM_INV },
+ { "relative", PATH_REL, 0 }
+};
+int nrpathtab = (sizeof(rpathtab) / sizeof(struct keytab));
+
+#ifdef CK_CTRLZ
+struct keytab eoftab[] = { /* EOF detection method */
+ { "ctrl-z", 1, 0 },
+ { "length", 0, 0 },
+ { "noctrl-z", 0, CM_INV }
+};
+#endif /* CK_CTRLZ */
+
+struct keytab fttab[] = { /* File types for SET FILE TYPE */
+ { "ascii", XYFT_T, CM_INV },
+#ifdef VMS
+ { "b", XYFT_B, CM_INV|CM_ABR },
+#endif /* VMS */
+ { "binary", XYFT_B, 0 },
+#ifdef VMS
+ { "block", XYFT_I, CM_INV },
+ { "image", XYFT_I, 0 },
+#endif /* VMS */
+#ifdef CK_LABELED
+ { "labeled", XYFT_L, 0 },
+#endif /* CK_LABELED */
+#ifdef MAC
+ { "macbinary", XYFT_M, 0 },
+#endif /* MAC */
+ { "text", XYFT_T, 0 }
+};
+int nfttyp = (sizeof(fttab) / sizeof(struct keytab));
+
+static struct keytab rfttab[] = { /* File types for REMOTE SET FILE */
+ { "ascii", XYFT_T, CM_INV },
+ { "binary", XYFT_B, 0 },
+#ifdef VMS
+ { "labeled", XYFT_L, 0 },
+#else
+#ifdef OS2
+ { "labeled", XYFT_L, 0 },
+#endif /* OS2 */
+#endif /* VMS */
+ { "text", XYFT_T, 0 }
+};
+static int nrfttyp = (sizeof(rfttab) / sizeof(struct keytab));
+
+#ifdef OS2ORUNIX
+#define ZOF_BLK 0
+#define ZOF_NBLK 1
+#define ZOF_BUF 2
+#define ZOF_NBUF 3
+static struct keytab zoftab[] = {
+ { "blocking", ZOF_BLK, 0 },
+ { "buffered", ZOF_BUF, 0 },
+ { "nonblocking", ZOF_NBLK, 0 },
+ { "unbuffered", ZOF_NBUF, 0 }
+};
+static int nzoftab = (sizeof(zoftab) / sizeof(struct keytab));
+#endif /* OS2ORUNIX */
+
+extern int query; /* Global flag for QUERY active */
+
+#ifndef NOSPL
+#ifndef NOXFER
+static struct keytab vartyp[] = { /* Variable types for REMOTE QUERY */
+ { "global", (int) 'G', CM_INV },
+ { "kermit", (int) 'K', 0 },
+ { "system", (int) 'S', 0 },
+ { "user", (int) 'G', 0 }
+};
+static int nvartyp = (sizeof(vartyp) / sizeof(struct keytab));
+#endif /* NOXFER */
+#endif /* NOSPL */
+
+#ifdef CK_TIMERS
+static struct keytab timotab[] = { /* Timer types */
+ { "dynamic", 1, 0 },
+ { "fixed", 0, 0 }
+};
+#endif /* CK_TIMERS */
+
+#ifdef DCMDBUF
+extern char *atxbuf, *atmbuf; /* Atom buffer */
+extern char *cmdbuf; /* Command buffer */
+extern char *line, *tmpbuf; /* Character buffers for anything */
+extern int *intime; /* INPUT TIMEOUT */
+
+#else /* Not DCMDBUF ... */
+
+extern char atxbuf[], atmbuf[]; /* Atom buffer */
+extern char cmdbuf[]; /* Command buffer */
+extern char line[], tmpbuf[]; /* Character buffer for anything */
+extern int intime[];
+
+#endif /* DCMDBUF */
+
+#ifndef NOCSETS
+extern struct keytab fcstab[]; /* For SET FILE CHARACTER-SET */
+extern struct csinfo fcsinfo[]; /* File character set info. */
+extern struct keytab ttcstab[];
+extern int nfilc, fcharset, tcharset, ntermc, tcsr, tcsl, dcset7, dcset8;
+#ifdef CKOUNI
+extern int tt_utf8;
+#endif /* CKOUNI */
+#ifdef OS2
+_PROTOTYP( int os2setcp, (int) );
+_PROTOTYP( int os2getcp, (void) );
+_PROTOTYP( void os2debugoff, (void) );
+#endif /* OS2 */
+#endif /* NOCSETS */
+
+extern int cmdlvl; /* Overall command level */
+
+#ifndef NOSPL
+#ifdef DCMDBUF
+extern int *inpcas; /* INPUT CASE setting on cmd stack */
+#else
+extern int inpcas[];
+#endif /* DCMDBUF */
+#endif /* NOSPL */
+
+#ifdef CK_CURSES
+#ifndef VMS
+_PROTOTYP(int tgetent,(char *, char *));
+#else
+#ifdef __DECC
+_PROTOTYP(int tgetent,(char *, char *));
+#endif /* __DECC */
+#endif /* VMS */
+#endif /* CK_CURSES */
+
+#ifndef NOXMIT
+#define XMITF 0 /* SET TRANSMIT values */
+#define XMITL 1 /* (Local to this module) */
+#define XMITP 2
+#define XMITE 3
+#define XMITX 4
+#define XMITS 5
+#define XMITW 6
+#define XMITT 7
+
+#define XMBUFL 50
+extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt;
+char xmitbuf[XMBUFL+1] = { NUL }; /* TRANSMIT eof string */
+
+struct keytab xmitab[] = { /* SET TRANSMIT */
+ { "echo", XMITX, 0 },
+ { "eof", XMITE, 0 },
+ { "fill", XMITF, 0 },
+ { "linefeed", XMITL, 0 },
+ { "locking-shift", XMITS, 0 },
+ { "pause", XMITW, 0 },
+ { "prompt", XMITP, 0 },
+ { "timeout", XMITT, 0 }
+};
+int nxmit = (sizeof(xmitab) / sizeof(struct keytab));
+#endif /* NOXMIT */
+
+/* For SET FILE COLLISION */
+/* Some of the following may be possible for some C-Kermit implementations */
+/* but not others. Those that are not possible for your implementation */
+/* should be ifdef'd out. */
+
+struct keytab colxtab[] = { /* SET FILE COLLISION options */
+#ifndef MAC
+ { "append", XYFX_A, 0 }, /* append to old file */
+#endif /* MAC */
+#ifdef COMMENT
+ { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
+#endif
+ { "backup", XYFX_B, 0 }, /* rename old file */
+#ifndef MAC
+ /* This crashes Mac Kermit. */
+ { "discard", XYFX_D, 0 }, /* don't accept new file */
+ { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
+#endif /* MAC */
+ { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
+ { "rename", XYFX_R, 0 }, /* rename the incoming file */
+#ifndef MAC /* This crashes Mac Kermit. */
+ { "update", XYFX_U, 0 }, /* replace if newer */
+#endif /* MAC */
+ { "", 0, 0 }
+};
+int ncolx = (sizeof(colxtab) / sizeof(struct keytab)) - 1;
+
+static struct keytab rfiltab[] = { /* for REMOTE SET FILE */
+#ifndef NOCSETS
+ { "character-set", XYFILC, 0 },
+#endif /* NOCSETS */
+ { "collision", XYFILX, 0 },
+ { "incomplete", XYFILI, 0 },
+ { "names", XYFILN, 0 },
+ { "record-length", XYFILR, 0 },
+ { "type", XYFILT, 0 }
+};
+int nrfilp = (sizeof(rfiltab) / sizeof(struct keytab));
+
+struct keytab eoltab[] = { /* File eof delimiters */
+ { "cr", XYFA_C, 0 },
+ { "crlf", XYFA_2, 0 },
+ { "lf", XYFA_L, 0 }
+};
+static int neoltab = (sizeof(eoltab) / sizeof(struct keytab));
+
+struct keytab fntab[] = { /* File naming */
+ { "converted", XYFN_C, 0 },
+ { "literal", XYFN_L, 0 },
+ { "standard", XYFN_C, CM_INV }
+};
+int nfntab = (sizeof(fntab) / sizeof(struct keytab));
+
+#ifndef NOLOCAL
+/* Terminal parameters table */
+static struct keytab trmtab[] = {
+#ifdef OS2
+ { "answerback", XYTANS, 0 },
+#endif /* OS2 */
+#ifdef CK_APC
+ { "apc", XYTAPC, 0 },
+#endif /* CK_APC */
+#ifdef OS2
+ { "arrow-keys", XYTARR, 0 },
+#endif /* OS2 */
+#ifdef NT
+ { "at", XYTATTR, CM_INV|CM_ABR },
+ { "att", XYTATTR, CM_INV|CM_ABR },
+ { "attr", XYTATTR, CM_INV|CM_ABR },
+ { "attr-bug", XYTATTBUG, CM_INV },
+#endif /* NT */
+#ifdef OS2
+ { "attribute", XYTATTR, 0 },
+#endif /* OS2 */
+#ifdef CK_APC
+#ifdef CK_AUTODL
+ { "autodownload", XYTAUTODL, 0, },
+#endif /* CK_AUTODL */
+#endif /* CK_APC */
+#ifdef OS2
+ { "autopage", XYTAPAGE, 0 },
+ { "autoscroll", XYTASCRL, 0 },
+ { "bell", XYTBEL, CM_INV },
+#endif /* OS2 */
+ { "bytesize", XYTBYT, 0 },
+#ifndef NOCSETS
+ { "character-set", XYTCS, 0 },
+#endif /* NOCSETS */
+#ifdef OS2
+ { "code-page", XYTCPG, 0 },
+ { "color", XYTCOL, 0 },
+ { "controls", XYTCTRL, 0 },
+#endif /* OS2 */
+ { "cr-display", XYTCRD, 0 },
+#ifdef OS2
+ { "cursor", XYTCUR, 0 },
+#endif /* OS2 */
+ { "debug", XYTDEB, 0 },
+#ifdef OS2
+ { "dg-unix-mode", XYTUNX, 0 },
+#endif /* OS2 */
+ { "echo", XYTEC, 0 },
+ { "escape-character", XYTESC, 0 },
+#ifdef OS2
+#ifdef PCFONTS
+ { "font", XYTFON, 0 },
+#else
+#ifdef KUI
+ { "font", XYTFON, 0 },
+#endif /* KUI */
+#endif /* PCFONTS */
+#endif /* OS2 */
+ { "height", XYTHIG, 0 },
+#ifdef CKTIDLE
+ { "idle-action", XYTIACT, 0 },
+ { "idle-limit", XYTITMO, CM_INV },
+ { "idle-send", XYTIDLE, CM_INV },
+ { "idle-timeout", XYTITMO, 0 },
+#endif /* CKTIDLE */
+#ifdef OS2
+#ifndef NOCSETS
+ { "kbd-follows-gl/gr", XYTKBDGL, 0 },
+#endif /* NOCSETS */
+ { "key", XYTKEY, 0 },
+ { "keyboard-mode", XYTKBMOD, 0 },
+ { "keypad-mode", XYTKPD, 0 },
+#endif /* OS2 */
+#ifndef NOCSETS
+#ifdef OS2
+#ifndef KUI
+ { "line-spacing", XYTLSP, CM_INV },
+ { "local-character-set", XYTLCS, 0 },
+#else
+ { "line-spacing", XYTLSP, 0 },
+ { "local-character-set", XYTLCS, CM_INV },
+#endif /* KUI */
+#else
+ { "local-character-set", XYTLCS, CM_INV },
+#endif /* OS2 */
+#endif /* NOCSETS */
+ { "locking-shift", XYTSO, 0 },
+#ifdef OS2
+ { "margin-bell", XYTMBEL, 0 },
+#endif /* OS2 */
+#ifdef OS2MOUSE
+ { "mouse", XYTMOU, CM_INV },
+#endif /* OS2MOUSE */
+ { "newline-mode", XYTNL, 0 },
+#ifdef OS2
+ { "output-pacing", XYTPAC, 0 },
+#ifdef PCTERM
+ { "pcterm", XYTPCTERM, 0 },
+#endif /* PCTERM */
+#endif /* OS2 */
+#ifdef OS2ORUNIX
+ { "print", XYTPRN, 0 },
+#endif /* OS2ORUNIX */
+#ifndef NOCSETS
+#ifdef OS2
+ { "remote-character-set", XYTRCS, 0 },
+#else
+ { "remote-character-set", XYTRCS, CM_INV },
+#endif /* OS2 */
+#endif /* NOCSETS */
+#ifdef OS2
+ { "roll-mode", XYTROL, 0 },
+ { "s", XYTUPD, CM_ABR|CM_INV },
+ { "sc", XYTUPD, CM_ABR|CM_INV },
+ { "scr", XYTUPD, CM_ABR|CM_INV },
+ { "scree", XYTUPD, CM_ABR|CM_INV },
+ { "screen", XYTUPD, CM_ABR|CM_INV },
+ { "screen-", XYTUPD, CM_ABR|CM_INV },
+ { "screen-mode", XYTSCNM, 0 },
+ { "screen-optimize", XYTOPTI, 0 },
+ { "screen-update", XYTUPD, 0 },
+ { "scrollback", XYSCRS, 0 },
+ { "send-data", XYTSEND, 0 },
+ { "send-end-of-block", XYTSEOB, 0 },
+ { "sgr-colors", XYTSGRC, 0 },
+ { "sni-ch.code", XYTSNICC, 0 },
+ { "sni-firmware-versions", XYTSNIFV, 0 },
+ { "sni-language", XYTVTLNG, 0 },
+ { "sni-pagemode", XYTSNIPM, CM_INV },
+ { "sni-scrollmode", XYTSNISM, CM_INV },
+ { "spacing-attribute-character", XYTSAC, CM_INV },
+ { "statusline", XYTSTAT, 0 },
+ { "tra", XYTCTS, CM_INV|CM_ABR },
+ { "transmit-timeout", XYTCTS, 0 },
+#endif /* OS2 */
+
+#ifdef OS2ORUNIX
+ { "transparent-print", XYTPRN, CM_INV },
+#endif /* OS2ORUNIX */
+
+#ifdef CK_TRIGGER
+ { "trigger", XYTRIGGER,0 },
+#endif /* CK_TRIGGER */
+#ifdef OS2
+ { "type", XYTTYP, 0 },
+#else
+ { "type", XYTTYP, CM_INV },
+#endif /* OS2 */
+
+#ifndef NOCSETS
+#ifdef UNICODE
+#ifdef CKOUNI
+ { "unicode", XYTUNI, CM_INV },
+#endif /* CKOUNI */
+#endif /* UNICODE */
+#endif /* NOCSETS */
+#ifdef OS2
+ { "unix-mode", XYTUNX, CM_INV },
+ { "url-highlight", XYTURLHI, 0 },
+#ifdef NT
+ { "video-change", XYTVCH, 0 },
+#endif /* NT */
+ { "vt-language", XYTVTLNG, 0 },
+ { "vt-nrc-mode", XYTVTNRC, 0 },
+#endif /* OS2 */
+ { "width", XYTWID, 0 },
+#ifdef OS2
+ { "wrap", XYTWRP, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int ntrm = (sizeof(trmtab) / sizeof(struct keytab)) - 1;
+
+#ifdef OS2
+struct keytab termctrl[] = { /* SET TERM CONTROLS */
+ { "7", 7, 0 },
+ { "8", 8, 0 }
+};
+int ntermctrl = (sizeof(termctrl) / sizeof(struct keytab));
+
+struct keytab curontab[] = { /* SET TERM CURSOR */
+#ifdef KUI
+ { "noblink", 2, 0 },
+#else
+ { "noblink", 2, CM_INV },
+#endif /* KUI */
+ { "off", 0, 0 },
+ { "on", 1, 0 }
+};
+int ncuron = (sizeof(curontab) / sizeof(struct keytab));
+
+struct keytab rolltab[] = { /* Set TERM Roll Options */
+ { "insert", TTR_INSERT, 0 },
+ { "keystrokes",TTR_KEYS, 0 },
+ { "off", TTR_OVER, CM_INV },
+ { "on", TTR_INSERT, CM_INV },
+ { "overwrite", TTR_OVER, 0 }
+};
+int nroll = (sizeof(rolltab) / sizeof(struct keytab));
+
+struct keytab rollkeytab[] = { /* Set TERM ROLL KEYSTROKES */
+ { "ignore", TTRK_IGN, 0 },
+ { "restore-and-send", TTRK_RST, 0 },
+ { "send", TTRK_SND, 0 }
+};
+int nrollkey = (sizeof(rollkeytab) / sizeof(struct keytab));
+
+#define TT_GR_ALL 4
+#define TT_GR_G0 0
+#define TT_GR_G1 1
+#define TT_GR_G2 2
+#define TT_GR_G3 3
+#define TT_GR_KBD 4
+struct keytab graphsettab[] = { /* DEC VT Graphic Sets */
+ { "all", TT_GR_ALL, 0 },
+ { "g0", TT_GR_G0, 0 },
+ { "g1", TT_GR_G1, 0 },
+ { "g2", TT_GR_G2, 0 },
+ { "g3", TT_GR_G3, 0 },
+ { "keyboard", TT_GR_KBD, 0 }
+};
+int ngraphset = (sizeof(graphsettab) / sizeof(struct keytab));
+#endif /* OS2 */
+
+struct keytab adltab[] = { /* Autodownload Options */
+ { "ask", TAD_ASK, 0 },
+ { "error", TAD_ERR, 0 },
+#ifdef OS2
+ { "kermit", TAD_K, 0 },
+#endif /* OS2 */
+ { "off", TAD_OFF, 0 },
+ { "on", TAD_ON, 0 },
+#ifdef OS2
+ { "zmodem", TAD_Z, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int nadltab = (sizeof(adltab) / sizeof(struct keytab)) - 1;
+
+struct keytab adlerrtab[] = { /* Autodownload Error Options */
+ { "continue", 0, 0 },
+ { "go", 0, CM_INV },
+ { "stop", 1, 0 }
+};
+int nadlerrtab = (sizeof(adlerrtab) / sizeof(struct keytab));
+
+#ifdef OS2
+struct keytab adlxtab[] = { /* Autodownload Options */
+ { "c0-conflicts", TAD_X_C0, 0 },
+ { "detection-method", TAD_X_DETECT, 0 },
+ { "string", TAD_X_STR, 0 }
+};
+int nadlxtab = (sizeof(adlxtab) / sizeof(struct keytab));
+
+struct keytab adldtab[] = { /* Auto-dl Detection Methods */
+ { "packet", ADL_PACK, 0 },
+ { "string", ADL_STR, 0 }
+};
+int nadldtab = (sizeof(adldtab) / sizeof(struct keytab));
+
+struct keytab adlc0tab[] = { /* Auto-dl Detection Methods */
+ { "ignored-by-emulator", 0, 0 },
+ { "processed-by-emulator", 1, 0 }
+};
+int nadlc0tab = (sizeof(adlc0tab) / sizeof(struct keytab));
+
+#ifndef NOCSETS
+struct keytab vtlangtab[] = {
+ { "belgian", VTL_BELGIAN , 0 },
+ { "british", VTL_BRITISH , 0 },
+ { "canadian", VTL_CANADIAN, 0 },
+ { "czech", VTL_CZECH , 0 },
+ { "danish", VTL_DANISH , 0 },
+ { "dutch", VTL_DUTCH , 0 },
+ { "finnish", VTL_FINNISH , 0 },
+ { "french", VTL_FRENCH , 0 },
+ { "french-canadian",VTL_FR_CAN , 0 },
+ { "german", VTL_GERMAN , 0 },
+ { "greek", VTL_GREEK , 0 },
+ { "hebrew", VTL_HEBREW , 0 },
+ { "hungarian", VTL_HUNGARIA, 0 },
+ { "italian", VTL_ITALIAN , 0 },
+ { "latin-american", VTL_LATIN_AM, 0 },
+ { "north-american", VTL_NORTH_AM, 0 },
+ { "norwegian", VTL_NORWEGIA, 0 },
+ { "polish", VTL_POLISH , 0 },
+ { "portugese", VTL_PORTUGES, 0 },
+ { "romanian", VTL_ROMANIAN, 0 },
+ { "russian", VTL_RUSSIAN , 0 },
+ { "scs", VTL_SCS , CM_INV },
+ { "slovak", VTL_SLOVAK , 0 },
+ { "spanish", VTL_SPANISH , 0 },
+ { "swedish", VTL_SWEDISH , 0 },
+ { "swiss-french", VTL_SW_FR , 0 },
+ { "swiss-german", VTL_SW_GR , 0 },
+ { "turkish-f", VTL_TURK_F , CM_INV },
+ { "turkish-q", VTL_TURK_Q , CM_INV }
+};
+int nvtlangtab = (sizeof(vtlangtab) / sizeof(struct keytab));
+#endif /* NOCSETS */
+#endif /* OS2 */
+
+struct keytab crdtab[] = { /* Carriage-return display */
+ { "crlf", 1, 0 },
+ { "normal", 0, 0 }
+};
+extern int tt_crd; /* Carriage-return display variable */
+
+#ifdef CK_APC
+extern int apcstatus, apcactive;
+static struct keytab apctab[] = { /* Terminal APC parameters */
+ { "no-input", APC_ON|APC_NOINP,0 },
+ { "off", APC_OFF, 0 },
+ { "on", APC_ON, 0 },
+ { "unchecked", APC_ON|APC_UNCH, 0 },
+ { "unchecked-no-input", APC_ON|APC_NOINP|APC_UNCH, 0 }
+};
+int napctab = (sizeof(apctab) / sizeof(struct keytab));
+#endif /* CK_APC */
+#endif /* NOLOCAL */
+
+extern int autodl, adl_err, adl_ask;
+
+struct keytab beltab[] = { /* Terminal bell mode */
+#ifdef OS2
+ { "audible", XYB_AUD, 0 },
+ { "none", XYB_NONE, 0 },
+#else
+ { "audible", XYB_AUD, CM_INV },
+ { "none", XYB_NONE, CM_INV },
+#endif /* OS2 */
+#ifdef OS2
+ { "off", XYB_NONE, CM_INV },
+ { "on", XYB_AUD, CM_INV },
+#else
+ { "off", XYB_NONE, 0 },
+ { "on", XYB_AUD, 0 },
+#endif /* OS2 */
+#ifdef OS2
+ { "visible", XYB_VIS, 0 },
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+int nbeltab = sizeof(beltab)/sizeof(struct keytab) - 1;
+
+int tt_unicode = 1; /* Use Unicode if possible */
+#ifdef CKTIDLE
+int tt_idlesnd_tmo = 0; /* Idle Send Timeout, disabled */
+char * tt_idlesnd_str = NULL; /* Idle Send String, none */
+char * tt_idlestr = NULL;
+extern int tt_idleact, tt_idlelimit;
+#endif /* CKTIDLE */
+
+#ifdef OS2
+#ifndef NOLOCAL
+/*
+ OS/2 serial communication devices.
+*/
+struct keytab os2devtab[] = {
+ { "1", 1, CM_INV }, /* Invisible synonyms, like */
+ { "2", 2, CM_INV }, /* "set port 1" */
+ { "3", 3, CM_INV },
+ { "4", 4, CM_INV },
+ { "5", 5, CM_INV },
+ { "6", 6, CM_INV },
+ { "7", 7, CM_INV },
+ { "8", 8, CM_INV },
+ { "com1", 1, 0 }, /* Real device names */
+ { "com2", 2, 0 },
+ { "com3", 3, 0 },
+ { "com4", 4, 0 },
+ { "com5", 5, 0 },
+ { "com6", 6, 0 },
+ { "com7", 7, 0 },
+ { "com8", 8, 0 },
+#ifdef OS2ONLY
+ { "slipcom1", 1, 0 }, /* For use with SLIP driver */
+ { "slipcom2", 2, 0 }, /* shared access */
+ { "slipcom3", 3, 0 },
+ { "slipcom4", 4, 0 },
+ { "slipcom5", 5, 0 },
+ { "slipcom6", 6, 0 },
+ { "slipcom7", 7, 0 },
+ { "slipcom8", 8, 0 },
+ { "pppcom1", 1, 0 }, /* For use with PPP driver */
+ { "pppcom2", 2, 0 }, /* shared access */
+ { "pppcom3", 3, 0 },
+ { "pppcom4", 4, 0 },
+ { "pppcom5", 5, 0 },
+ { "pppcom6", 6, 0 },
+ { "pppcom7", 7, 0 },
+ { "pppcom8", 8, 0 }
+#endif /* OS2ONLY */
+};
+int nos2dev = (sizeof(os2devtab) / sizeof(struct keytab)) - 1;
+
+#ifdef OS2ONLY
+struct keytab os2ppptab[] = {
+ { "0", 0, CM_INV },
+ { "1", 1, CM_INV }, /* Invisible synonyms, like */
+ { "2", 2, CM_INV }, /* "set port 1" */
+ { "3", 3, CM_INV },
+ { "4", 4, CM_INV },
+ { "5", 5, CM_INV },
+ { "6", 6, CM_INV },
+ { "7", 7, CM_INV },
+ { "8", 8, CM_INV },
+ { "9", 9, CM_INV },
+ { "ppp0", 0, 0 },
+ { "ppp1", 1, 0 }, /* For use with PPP driver */
+ { "ppp2", 2, 0 }, /* shared access */
+ { "ppp3", 3, 0 },
+ { "ppp4", 4, 0 },
+ { "ppp5", 5, 0 },
+ { "ppp6", 6, 0 },
+ { "ppp7", 7, 0 },
+ { "ppp8", 8, 0 },
+ { "ppp9", 9, 0 }
+};
+int nos2ppp = (sizeof(os2ppptab) / sizeof(struct keytab));
+#endif /* OS2ONLY */
+
+/*
+ Terminal parameters that can be set by SET commands.
+ Used by the ck?con.c terminal emulator code.
+ For now, only used for #ifdef OS2. Should add these for Macintosh.
+*/
+int tt_arrow = TTK_NORM; /* Arrow key mode: normal (cursor) */
+int tt_keypad = TTK_NORM; /* Keypad mode: normal (numeric) */
+int tt_shift_keypad = 0; /* Keypad Shift mode: Off */
+int tt_wrap = 1; /* Terminal wrap, 1 = On */
+int tt_type = TT_VT320; /* Terminal type, initially VT320 */
+int tt_type_mode = TT_VT320; /* Terminal type set by host command */
+int tt_cursor = 0; /* Terminal cursor, 0 = Underline */
+int tt_cursor_usr = 0; /* Users Terminal cursor type */
+int tt_cursorena_usr = 1; /* Users Terminal cursor enabled */
+int tt_cursor_blink = 1; /* Terminal Cursor Blink */
+int tt_answer = 0; /* Terminal answerback (disabled) */
+int tt_scrsize[VNUM] = {512,512,512,1}; /* Terminal scrollback buffer size */
+int tt_roll[VNUM] = {1,1,1,1}; /* Terminal roll (on) */
+int tt_rkeys[VNUM] = {1,1,1,1}; /* Terminal roll keys (send) */
+int tt_pacing = 0; /* Terminal output-pacing (none) */
+int tt_ctstmo = 15; /* Terminal transmit-timeout */
+int tt_codepage = -1; /* Terminal code-page */
+int tt_update = 100; /* Terminal screen-update interval */
+int tt_updmode = TTU_FAST; /* Terminal screen-update mode FAST */
+extern int updmode;
+#ifndef KUI
+int tt_status[VNUM] = {1,1,0,0}; /* Terminal status line displayed */
+int tt_status_usr[VNUM] = {1,1,0,0};
+#else /* KUI */
+extern CKFLOAT floatval;
+CKFLOAT tt_linespacing[VNUM] = {1.0,1.0,1.0,1.0};
+#ifdef K95G
+int tt_status[VNUM] = {1,1,0,0}; /* Terminal status line displayed */
+int tt_status_usr[VNUM] = {1,1,0,0};
+#else /* K95G */
+int tt_status[VNUM] = {0,0,0,0}; /* Terminal status line displayed */
+int tt_status_usr[VNUM] = {0,0,0,0};
+#endif /* K95G */
+#endif /* KUI */
+int tt_senddata = 0; /* Let host read terminal data */
+extern int wy_blockend; /* Terminal Send Data EOB type */
+int tt_hidattr = 1; /* Attributes are hidden */
+
+extern unsigned char colornormal, colorselect,
+colorunderline, colorstatus, colorhelp, colorborder,
+colorgraphic, colordebug, colorreverse, coloritalic;
+
+extern int trueblink, trueunderline, truereverse, trueitalic, truedim;
+
+extern int bgi, fgi;
+extern int scrninitialized[];
+
+struct keytab audibletab[] = { /* Terminal Bell Audible mode */
+ { "beep", XYB_BEEP, 0 }, /* Values ORd with bell mode */
+ { "system-sounds", XYB_SYS, 0 }
+};
+int naudibletab = sizeof(audibletab)/sizeof(struct keytab);
+
+struct keytab akmtab[] = { /* Arrow key mode */
+ { "application", TTK_APPL, 0 },
+ { "cursor", TTK_NORM, 0 }
+};
+struct keytab kpmtab[] = { /* Keypad mode */
+ { "application", TTK_APPL, 0 },
+ { "numeric", TTK_NORM, 0 }
+};
+
+struct keytab ttcolmodetab[] = {
+ { "current-color", 0, 0 },
+ { "default-color", 1, 0 }
+};
+int ncolmode = sizeof(ttcolmodetab)/sizeof(struct keytab);
+
+#define TTCOLNOR 0
+#define TTCOLREV 1
+#define TTCOLUND 2
+#define TTCOLSTA 3
+#define TTCOLHLP 4
+#define TTCOLBOR 5
+#define TTCOLSEL 6
+#define TTCOLDEB 7
+#define TTCOLGRP 8
+#define TTCOLITA 9
+#define TTCOLRES 10
+#define TTCOLERA 11
+
+struct keytab ttycoltab[] = { /* Terminal Screen coloring */
+ { "border", TTCOLBOR, 0 }, /* Screen border color */
+ { "debug-terminal", TTCOLDEB, 0 }, /* Debug color */
+ { "erase", TTCOLERA, 0 }, /* Erase mode */
+ { "graphic", TTCOLGRP, 0 }, /* Graphic Color */
+ { "help-text", TTCOLHLP, 0 }, /* Help screens */
+ { "italic", TTCOLITA, 0 }, /* Italic Color */
+ { "normal", TTCOLNOR, CM_INV }, /* Normal screen text */
+ { "reset-on-esc[0m", TTCOLRES, 0 }, /* Reset on ESC [ 0 m */
+ { "reverse-video", TTCOLREV, 0 }, /* Reverse video */
+ { "status-line", TTCOLSTA, 0 }, /* Status line */
+ { "selection", TTCOLSEL, 0 }, /* Selection color */
+ { "terminal-screen", TTCOLNOR, 0 }, /* Better name than "normal" */
+ { "underlined-text", TTCOLUND, 0 } /* Underlined text */
+};
+int ncolors = (sizeof(ttycoltab) / sizeof(struct keytab));
+
+#define TTATTNOR 0
+#define TTATTBLI 1
+#define TTATTREV 2
+#define TTATTUND 3
+#define TTATTPRO 4
+#define TTATTBLD 5
+#define TTATTDIM 6
+#define TTATTINV 7
+#define TTATTITA 8
+#define TTATTDONE 9
+
+struct keytab ttyattrtab[] = {
+ { "blink", TTATTBLI, 0 },
+ { "dim", TTATTDIM, 0 },
+ { "italic", TTATTITA, 0 },
+ { "protected", TTATTPRO, 0 },
+ { "reverse", TTATTREV, 0 },
+ { "underline", TTATTUND, 0 }
+};
+int nattrib = (sizeof(ttyattrtab) / sizeof(struct keytab));
+
+struct keytab ttyprotab[] = {
+ { "blink", TTATTBLI, 0 },
+ { "bold", TTATTBLD, 0 },
+ { "dim", TTATTDIM, 0 },
+ { "done", TTATTDONE, CM_INV },
+ { "invisible", TTATTINV, 0 },
+ { "italic", TTATTITA, 0 },
+ { "normal", TTATTNOR, 0 },
+ { "reverse", TTATTREV, 0 },
+ { "underlined", TTATTUND, 0 }
+
+};
+int nprotect = (sizeof(ttyprotab) / sizeof(struct keytab));
+
+struct keytab ttyseobtab[] = {
+ { "crlf_etx", 1, 0 },
+ { "us_cr", 0, 0 }
+};
+
+struct keytab ttyclrtab[] = { /* Colors */
+ { "black", 0, 0 },
+ { "blue", 1, 0 },
+ { "brown", 6, 0 },
+ { "cyan", 3, 0 },
+ { "darkgray", 8, CM_INV },
+ { "dgray", 8, 0 },
+ { "green", 2, 0 },
+ { "lblue", 9, CM_INV },
+ { "lcyan", 11, CM_INV },
+ { "lgray", 7, CM_INV },
+ { "lgreen", 10, CM_INV },
+ { "lightblue", 9, 0 },
+ { "lightcyan", 11, 0 },
+ { "lightgray", 7, 0 },
+ { "lightgreen", 10, 0 },
+ { "lightmagenta", 13, 0 },
+ { "lightred", 12, 0 },
+ { "lmagenta", 13, CM_INV },
+ { "lred", 12, CM_INV },
+ { "magenta", 5, 0 },
+ { "red", 4, 0 },
+ { "white", 15, 0 },
+ { "yellow", 14, 0 }
+};
+int nclrs = (sizeof (ttyclrtab) / sizeof (struct keytab));
+
+struct keytab ttycurtab[] = {
+ { "full", TTC_BLOCK, 0 },
+ { "half", TTC_HALF, 0 },
+ { "underline", TTC_ULINE, 0 }
+};
+int ncursors = 3;
+
+struct keytab ttyptab[] = {
+ { "aaa", TT_AAA, CM_INV }, /* AnnArbor */
+ { "adm3a", TT_ADM3A, 0 }, /* LSI ADM-3A */
+ { "adm5", TT_ADM5, 0 }, /* LSI ADM-5 */
+ { "aixterm", TT_AIXTERM, 0 }, /* IBM AIXterm */
+ { "annarbor", TT_AAA, 0 }, /* AnnArbor */
+ { "ansi-bbs", TT_ANSI, 0 }, /* ANSI.SYS (BBS) */
+ { "at386", TT_AT386, 0 }, /* Unixware ANSI */
+ { "avatar/0+",TT_ANSI, 0 }, /* AVATAR/0+ */
+ { "ba80", TT_BA80, 0 }, /* Nixdorf BA80 */
+ { "be", TT_BEOS, CM_INV|CM_ABR },
+ { "beos-ansi",TT_BEOS, CM_INV }, /* BeOS ANSI */
+ { "beterm", TT_BEOS, 0 }, /* BeOS Terminal (as of PR2 ) */
+ { "d200", TT_DG200, CM_INV|CM_ABR }, /* Data General DASHER 200 */
+ { "d210", TT_DG210, CM_INV|CM_ABR }, /* Data General DASHER 210 */
+ { "d217", TT_DG217, CM_INV|CM_ABR }, /* Data General DASHER 217 */
+ { "dg200", TT_DG200, 0 }, /* Data General DASHER 200 */
+ { "dg210", TT_DG210, 0 }, /* Data General DASHER 210 */
+ { "dg217", TT_DG217, 0 }, /* Data General DASHER 217 */
+ { "h1500", TT_HZL1500, CM_INV }, /* Hazeltine 1500 */
+ { "h19", TT_H19, CM_INV }, /* Heath-19 */
+ { "heath19", TT_H19, 0 }, /* Heath-19 */
+ { "hft", TT_HFT, 0 }, /* IBM High Function Terminal */
+ { "hp2621a", TT_HP2621, 0 }, /* HP 2621A */
+ { "hpterm", TT_HPTERM, 0 }, /* HP TERM */
+ { "hz1500", TT_HZL1500, 0 }, /* Hazeltine 1500 */
+ { "ibm3151", TT_IBM31, 0 }, /* IBM 3101-xx,3161 */
+ { "linux", TT_LINUX, 0 }, /* Linux */
+ { "qansi", TT_QANSI, 0 }, /* QNX ANSI */
+ { "qnx", TT_QNX, 0 }, /* QNX Console */
+ { "scoansi", TT_SCOANSI, 0 }, /* SCO ANSI */
+ { "sni-97801",TT_97801, 0 }, /* SNI 97801 */
+ { "sun", TT_SUN, 0 }, /* SUN Console */
+/*
+ The idea of NONE is to let the console driver handle the escape sequences,
+ which, in theory at least, would give not only ANSI emulation, but also any
+ other kind of emulation that might be provided by alternative console
+ drivers, if any existed.
+
+ For this to work, ckocon.c would need to be modified to make higher-level
+ calls, like VioWrtTTY(), DosWrite(), or (simply) write(), rather than
+ VioWrt*Cell() and similar, and it would also have to give up its rollback
+ feature, and its status line and help screens would also have to be
+ forgotten or else done in an ANSI way.
+
+ As matters stand, we already have perfectly good ANSI emulation built in,
+ and there are no alternative console drivers available, so there is no point
+ in having a terminal type of NONE, so it is commented out. However, should
+ you uncomment it, it will work like a "glass tty" -- no escape sequence
+ interpretation at all; somewhat similar to debug mode, except without the
+ debugging (no highlighting of control chars or escape sequences); help
+ screens, status line, and rollback will still work.
+*/
+#ifdef OS2PM
+#ifdef COMMENT
+ { "tek4014", TT_TEK40, 0 },
+#endif /* COMMENT */
+#endif /* OS2PM */
+ { "tty", TT_NONE, 0 },
+ { "tvi910+", TT_TVI910, 0 },
+ { "tvi925", TT_TVI925, 0 },
+ { "tvi950", TT_TVI950, 0 },
+ { "vc404", TT_VC4404, 0 },
+ { "vc4404", TT_VC4404, CM_INV },
+ { "vip7809", TT_VIP7809,0 },
+ { "vt100", TT_VT100, 0 },
+ { "vt102", TT_VT102, 0 },
+ { "vt220", TT_VT220, 0 },
+ { "vt220pc", TT_VT220PC,0 },
+ { "vt320", TT_VT320, 0 },
+ { "vt320pc", TT_VT320PC,0 },
+ { "vt52", TT_VT52, 0 },
+#ifdef NT
+ { "vtnt", TT_VTNT, 0 },
+#else /* NT */
+ { "vtnt", TT_VTNT, CM_INV },
+#endif /* NT */
+ { "wy160", TT_WY160, 0 },
+ { "wy30", TT_WY30, 0 },
+ { "wy370", TT_WY370, 0 },
+ { "wy50", TT_WY50, 0 },
+ { "wy60", TT_WY60, 0 },
+ { "wyse30", TT_WY30, CM_INV },
+ { "wyse370", TT_WY370, CM_INV },
+ { "wyse50", TT_WY50, CM_INV },
+ { "wyse60", TT_WY60, CM_INV }
+};
+int nttyp = (sizeof(ttyptab) / sizeof(struct keytab));
+
+struct keytab ttkeytab[] = {
+ { "aaa", TT_AAA, CM_INV }, /* AnnArbor */
+ { "adm3a", TT_ADM3A, 0 }, /* LSI ADM-3A */
+ { "adm5", TT_ADM5, 0 }, /* LSI ADM-5 */
+ { "aixterm", TT_AIXTERM, 0 }, /* IBM AIXterm */
+ { "annarbor", TT_AAA, 0 }, /* AnnArbor */
+ { "ansi-bbs", TT_ANSI, 0 }, /* ANSI.SYS (BBS) */
+ { "at386", TT_AT386, 0 }, /* Unixware ANSI */
+ { "avatar/0+", TT_ANSI, 0 }, /* AVATAR/0+ */
+ { "ba80", TT_BA80, 0 }, /* Nixdorf BA80 */
+ { "be", TT_BEOS, CM_INV|CM_ABR },
+ { "beos-ansi", TT_BEOS, CM_INV }, /* BeOS ANSI */
+ { "beterm", TT_BEOS, 0 }, /* BeOS Terminal (DR2) */
+ { "d200", TT_DG200, CM_INV|CM_ABR }, /* DG DASHER 200 */
+ { "d210", TT_DG210, CM_INV|CM_ABR }, /* DG DASHER 210 */
+ { "d217", TT_DG217, CM_INV|CM_ABR }, /* DG DASHER 217 */
+ { "dg200", TT_DG200, 0 }, /* DG DASHER 200 */
+ { "dg210", TT_DG210, 0 }, /* DG DASHER 210 */
+ { "dg217", TT_DG217, 0 }, /* DG DASHER 217 */
+ { "emacs", TT_KBM_EMACS, 0 }, /* Emacs mode */
+ { "h19", TT_H19, CM_INV }, /* Heath-19 */
+ { "heath19", TT_H19, 0 }, /* Heath-19 */
+ { "hebrew", TT_KBM_HEBREW, 0 }, /* Hebrew mode */
+ { "hft", TT_HFT, 0 }, /* IBM High Function Term */
+ { "hp2621a", TT_HP2621, 0 }, /* HP 2621A */
+ { "hpterm", TT_HPTERM, 0 }, /* HP TERM */
+ { "hz1500", TT_HZL1500, 0 }, /* Hazeltine 1500 */
+ { "ibm3151", TT_IBM31, 0 }, /* IBM 3101-xx,3161 */
+ { "linux", TT_LINUX, 0 }, /* Linux */
+ { "qansi", TT_QANSI, 0 }, /* QNX ANSI */
+ { "qnx", TT_QNX, 0 }, /* QNX */
+ { "russian", TT_KBM_RUSSIAN,0 }, /* Russian mode */
+ { "scoansi", TT_SCOANSI, 0 }, /* SCO ANSI */
+ { "sni-97801", TT_97801, 0 }, /* SNI 97801 */
+ { "sun", TT_SUN, 0 }, /* SUN Console */
+#ifdef OS2PM
+#ifdef COMMENT
+ { "tek4014", TT_TEK40, 0 },
+#endif /* COMMENT */
+#endif /* OS2PM */
+ { "tty", TT_NONE, 0 },
+ { "tvi910+", TT_TVI910, 0 },
+ { "tvi925", TT_TVI925, 0 },
+ { "tvi950", TT_TVI950, 0 },
+ { "vc404", TT_VC4404, 0 },
+ { "vc4404", TT_VC4404, CM_INV },
+ { "vip7809", TT_VIP7809, 0 },
+ { "vt100", TT_VT100, 0 },
+ { "vt102", TT_VT102, 0 },
+ { "vt220", TT_VT220, 0 },
+ { "vt220pc", TT_VT220PC, 0 },
+ { "vt320", TT_VT320, 0 },
+ { "vt320pc", TT_VT320PC, 0 },
+ { "vt52", TT_VT52, 0 },
+ { "vtnt", TT_VTNT, CM_INV },
+ { "wp", TT_KBM_WP, 0 }, /* Word Perfect mode */
+ { "wy160", TT_WY160, 0 },
+ { "wy30", TT_WY30, 0 },
+ { "wy370", TT_WY370, 0 },
+ { "wy50", TT_WY50, 0 },
+ { "wy60", TT_WY60, 0 },
+ { "wyse30", TT_WY30, CM_INV },
+ { "wyse370", TT_WY370, CM_INV },
+ { "wyse50", TT_WY50, CM_INV },
+ { "wyse60", TT_WY60, CM_INV }
+};
+int nttkey = (sizeof(ttkeytab) / sizeof(struct keytab));
+
+#ifndef NOSETKEY
+struct keytab kbmodtab[] = {
+ { "emacs", KBM_EM, 0 },
+ { "english", KBM_EN, CM_INV },
+ { "hebrew", KBM_HE, 0 },
+ { "normal", KBM_EN, 0 },
+ { "none", KBM_EN, CM_INV },
+ { "russian", KBM_RU, 0 },
+ { "wp", KBM_WP, 0 }
+};
+int nkbmodtab = (sizeof(kbmodtab) / sizeof(struct keytab));
+#endif /* NOSETKEY */
+#endif /* NOLOCAL */
+
+int tt_inpacing = 0; /* input-pacing (none) */
+
+struct keytab prtytab[] = { /* OS/2 Priority Levels */
+ { "foreground-server", XYP_SRV, 0 },
+ { "idle", XYP_IDLE, CM_INV },
+ { "regular", XYP_REG, 0 },
+ { "time-critical", XYP_RTP, 0 }
+};
+int nprty = (sizeof(prtytab) / sizeof(struct keytab));
+#endif /* OS2 */
+
+#ifdef NT
+struct keytab win95tab[] = { /* Win95 work-arounds */
+ { "8.3-filenames", XYW8_3, 0 },
+ { "alt-gr", XYWAGR, 0 },
+ { "horizontal-scan-line-substitutions", XYWHSL, 0 },
+ { "keyboard-translation", XYWKEY, 0 },
+ { "lucida-substitutions", XYWLUC, 0 },
+ { "overlapped-io", XYWOIO, 0 },
+ { "popups", XYWPOPUP, 0 },
+ { "select-bug", XYWSELECT, 0 }
+};
+int nwin95 = (sizeof(win95tab) / sizeof(struct keytab));
+#endif /* NT */
+
+#ifdef OS2MOUSE
+extern int wideresult;
+int tt_mouse = 1; /* Terminal mouse on/off */
+
+struct keytab mousetab[] = { /* Mouse items */
+ { "activate", XYM_ON, 0 },
+ { "button", XYM_BUTTON, 0 },
+ { "clear", XYM_CLEAR, 0 },
+ { "debug", XYM_DEBUG, 0 }
+};
+int nmtab = (sizeof(mousetab)/sizeof(struct keytab));
+
+struct keytab mousebuttontab[] = { /* event button */
+ { "1", XYM_B1, 0 },
+ { "2", XYM_B2, 0 },
+ { "3", XYM_B3, 0 },
+ { "one", XYM_B1, CM_INV },
+ { "three", XYM_B3, CM_INV },
+ { "two", XYM_B2, CM_INV }
+};
+int nmbtab = (sizeof(mousebuttontab) / sizeof(struct keytab));
+
+struct keytab mousemodtab[] = { /* event button key modifier */
+ { "alt", XYM_ALT, 0 },
+ { "alt-shift", XYM_SHIFT|XYM_ALT, 0 },
+ { "ctrl", XYM_CTRL, 0 },
+ { "ctrl-alt", XYM_CTRL|XYM_ALT, 0 },
+ { "ctrl-alt-shift", XYM_CTRL|XYM_SHIFT|XYM_ALT, 0 },
+ { "ctrl-shift", XYM_CTRL|XYM_SHIFT, 0 },
+ { "none", 0, 0 },
+ { "shift", XYM_SHIFT, 0 }
+};
+int nmmtab = (sizeof(mousemodtab) / sizeof(struct keytab));
+
+struct keytab mclicktab[] = { /* event button click modifier */
+ { "click", XYM_C1, 0 },
+ { "drag", XYM_DRAG, 0 },
+ { "double-click", XYM_C2, 0 }
+};
+int nmctab = (sizeof(mclicktab) / sizeof(struct keytab));
+
+#ifndef NOKVERBS
+extern int nkverbs;
+extern struct keytab kverbs[];
+#endif /* NOKVERBS */
+#endif /* OS2MOUSE */
+
+/* #ifdef VMS */
+struct keytab fbtab[] = { /* Binary record types for VMS */
+ { "fixed", XYFT_B, 0 }, /* Fixed is normal for binary */
+ { "undefined", XYFT_U, 0 } /* Undefined if they ask for it */
+};
+int nfbtyp = (sizeof(fbtab) / sizeof(struct keytab));
+/* #endif */
+
+#ifdef VMS
+struct keytab lbltab[] = { /* Labeled File info */
+ { "acl", LBL_ACL, 0 },
+ { "backup-date", LBL_BCK, 0 },
+ { "name", LBL_NAM, 0 },
+ { "owner", LBL_OWN, 0 },
+ { "path", LBL_PTH, 0 }
+};
+int nlblp = (sizeof(lbltab) / sizeof(struct keytab));
+#else
+#ifdef OS2
+struct keytab lbltab[] = { /* Labeled File info */
+ { "archive", LBL_ARC, 0 },
+ { "extended", LBL_EXT, 0 },
+ { "hidden", LBL_HID, 0 },
+ { "read-only", LBL_RO, 0 },
+ { "system", LBL_SYS, 0 }
+};
+int nlblp = (sizeof(lbltab) / sizeof(struct keytab));
+#endif /* OS2 */
+#endif /* VMS */
+
+#ifdef CK_CURSES
+#ifdef CK_PCT_BAR
+static struct keytab fdftab[] = { /* SET FILE DISPLAY FULL options */
+ { "thermometer", 1, 0, },
+ { "no-thermometer", 0, 0 }
+};
+extern int thermometer;
+#endif /* CK_PCT_BAR */
+#endif /* CK_CURSES */
+
+static struct keytab fdtab[] = { /* SET FILE DISPLAY options */
+#ifdef MAC /* Macintosh */
+ { "fullscreen", XYFD_R, 0 }, /* Full-screen but not curses */
+ { "none", XYFD_N, 0 },
+ { "off", XYFD_N, CM_INV },
+ { "on", XYFD_R, CM_INV },
+ { "quiet", XYFD_N, CM_INV },
+#else /* Not Mac */
+ { "brief", XYFD_B, 0 }, /* Brief */
+ { "crt", XYFD_S, 0 }, /* CRT display */
+#ifdef CK_CURSES
+#ifdef COMMENT
+ { "curses", XYFD_C, CM_INV }, /* Full-screen, curses */
+#endif /* COMMENT */
+ { "fullscreen", XYFD_C, 0 }, /* Full-screen, whatever the method */
+#endif /* CK_CURSES */
+#ifdef KUI
+ { "gui", XYFD_G, 0 }, /* GUI */
+#endif /* KUI */
+ { "none", XYFD_N, 0 }, /* No display */
+ { "off", XYFD_N, CM_INV }, /* Ditto */
+ { "on", XYFD_R, CM_INV }, /* On = Serial */
+ { "quiet", XYFD_N, CM_INV }, /* No display */
+ { "serial", XYFD_R, 0 }, /* Serial */
+#endif /* MAC */
+ { "", 0, 0 }
+};
+int nfdtab = (sizeof(fdtab) / sizeof(struct keytab)) - 1;
+
+struct keytab rsrtab[] = { /* For REMOTE SET RECEIVE */
+ { "packet-length", XYLEN, 0 },
+ { "timeout", XYTIMO, 0 }
+};
+int nrsrtab = (sizeof(rsrtab) / sizeof(struct keytab));
+
+/* Send/Receive Parameters */
+
+struct keytab srtab[] = {
+ { "backup", XYBUP, 0 },
+#ifndef NOCSETS
+ { "character-set-selection", XYCSET, 0 },
+#endif /* NOCSETS */
+ { "control-prefix", XYQCTL, 0 },
+#ifdef CKXXCHAR
+ { "double-character", XYDBL, 0 },
+#endif /* CKXXCHAR */
+ { "end-of-packet", XYEOL, 0 },
+#ifdef PIPESEND
+ { "filter", XYFLTR, 0 },
+#endif /* PIPESEND */
+#ifdef CKXXCHAR
+ { "ignore-character", XYIGN, 0 },
+#endif /* CKXXCHAR */
+ { "i-packets", 993, 0 },
+ { "move-to", XYMOVE, 0 },
+ { "negotiation-string-max-length", XYINIL, CM_INV },
+ { "packet-length", XYLEN, 0 },
+ { "pad-character", XYPADC, 0 },
+ { "padding", XYNPAD, 0 },
+ { "pathnames", XYFPATH, 0 },
+ { "pause", XYPAUS, 0 },
+#ifdef CK_PERMS
+ { "permissions", 994, 0}, /* 206 */
+#endif /* CK_PERMS */
+ { "quote", XYQCTL, CM_INV }, /* = CONTROL-PREFIX */
+ { "rename-to", XYRENAME, 0 },
+ { "start-of-packet", XYMARK, 0 },
+ { "timeout", XYTIMO, 0 },
+#ifdef VMS
+ { "version-numbers", 887, 0 }, /* VMS version numbers */
+#endif /* VMS */
+ { "", 0, 0 }
+};
+int nsrtab = (sizeof(srtab) / sizeof(struct keytab)) - 1;
+
+#ifdef UNICODE
+#define UCS_BOM 1
+#define UCS_BYT 2
+static struct keytab ucstab[] = {
+ { "bom", UCS_BOM, 0 },
+ { "byte-order", UCS_BYT, 0 },
+ { "", 0, 0 }
+};
+int nucstab = (sizeof(ucstab) / sizeof(struct keytab)) - 1;
+
+static struct keytab botab[] = {
+ { "big-endian", 0, 0 },
+ { "little-endian", 1, 0 }
+};
+static int nbotab = 2;
+#endif /* UNICODE */
+
+/* REMOTE SET */
+
+struct keytab rmstab[] = {
+ { "attributes", XYATTR, 0 },
+ { "block-check", XYCHKT, 0 },
+ { "file", XYFILE, 0 },
+ { "incomplete", XYIFD, CM_INV }, /* = REMOTE SET FILE INCOMPLETE */
+ { "match", XYMATCH,0 },
+ { "receive", XYRECV, 0 },
+ { "retry", XYRETR, 0 },
+ { "server", XYSERV, 0 },
+ { "transfer", XYXFER, 0 },
+ { "window", XYWIND, 0 },
+ { "xfer", XYXFER, CM_INV }
+};
+int nrms = (sizeof(rmstab) / sizeof(struct keytab));
+
+struct keytab attrtab[] = {
+#ifdef STRATUS
+ { "account", AT_ACCT, 0 },
+#endif /* STRATUS */
+ { "all", AT_XALL, 0 },
+#ifdef COMMENT
+ { "blocksize", AT_BLKS, 0 }, /* (not used) */
+#endif /* COMMENT */
+#ifndef NOCSETS
+ { "character-set", AT_ENCO, 0 },
+#endif /* NOCSETS */
+#ifdef STRATUS
+ { "creator", AT_CREA, 0 },
+#endif /* STRATUS */
+ { "date", AT_DATE, 0 },
+ { "disposition", AT_DISP, 0 },
+ { "encoding", AT_ENCO, CM_INV },
+ { "format", AT_RECF, CM_INV },
+ { "length", AT_LENK, 0 },
+ { "off", AT_ALLN, 0 },
+ { "on", AT_ALLY, 0 },
+#ifdef COMMENT
+ { "os-specific", AT_SYSP, 0 }, /* (not used by UNIX or VMS) */
+#endif /* COMMENT */
+#ifdef CK_PERMS
+ { "protection", AT_LPRO, 0 },
+ { "permissions", AT_LPRO, CM_INV },
+#endif /* CK_PERMS */
+ { "record-format", AT_RECF, 0 },
+ { "system-id", AT_SYSI, 0 },
+ { "type", AT_FTYP, 0 }
+};
+int natr = (sizeof(attrtab) / sizeof(struct keytab)); /* how many attributes */
+
+#ifdef CKTIDLE
+struct keytab idlacts[] = {
+ { "exit", IDLE_EXIT, 0 },
+ { "hangup", IDLE_HANG, 0 },
+ { "output", IDLE_OUT, 0 },
+ { "return", IDLE_RET, 0 },
+#ifdef TNCODE
+ { "telnet-nop", IDLE_TNOP, 0 },
+ { "telnet-ayt", IDLE_TAYT, 0 },
+#endif /* TNCODE */
+ { "", 0, 0 }
+};
+int nidlacts = (sizeof(idlacts) / sizeof(struct keytab)) - 1;
+#endif /* CKTIDLE */
+
+#ifndef NOSPL
+extern int indef, inecho, insilence, inbufsize, inautodl, inintr;
+#ifdef CKFLOAT
+extern CKFLOAT inscale;
+#endif /* CKFLOAT */
+extern char * inpbuf, * inpbp;
+#ifdef OS2
+extern int interm;
+#endif /* OS2 */
+struct keytab inptab[] = { /* SET INPUT parameters */
+#ifdef CK_AUTODL
+ { "autodownload", IN_ADL, 0 },
+#endif /* CK_AUTODL */
+ { "buffer-length", IN_BUF, 0 },
+ { "cancellation", IN_CAN, 0 },
+ { "case", IN_CAS, 0 },
+ { "default-timeout", IN_DEF, CM_INV }, /* There is no default timeout */
+ { "echo", IN_ECH, 0 },
+#ifdef OS2
+ { "pacing", IN_PAC, CM_INV },
+#endif /* OS2 */
+ { "scale-factor", IN_SCA, 0 },
+ { "silence", IN_SIL, 0 },
+#ifdef OS2
+ { "terminal", IN_TRM, 0 },
+#endif /* OS2 */
+ { "timeout-action", IN_TIM, 0 }
+};
+int ninp = (sizeof(inptab) / sizeof(struct keytab));
+
+struct keytab intimt[] = { /* SET INPUT TIMEOUT parameters */
+ { "proceed", 0, 0 }, /* 0 = proceed */
+ { "quit", 1, 0 } /* 1 = quit */
+};
+
+struct keytab incast[] = { /* SET INPUT CASE parameters */
+ { "ignore", 0, 0 }, /* 0 = ignore */
+ { "observe", 1, 0 } /* 1 = observe */
+};
+#endif /* NOSPL */
+
+struct keytab nabltab[] = { /* For any command that needs */
+ { "disabled", 0, 0 },
+ { "enabled", 1, 0 },
+ { "off", 0, CM_INV }, /* these keywords... */
+ { "on", 1, CM_INV }
+};
+int nnabltab = sizeof(nabltab) / sizeof(struct keytab);
+
+#ifdef OS2
+struct keytab tvctab[] = { /* SET TERM VIDEO-CHANGE */
+ { "disabled", TVC_DIS, 0 },
+ { "enabled", TVC_ENA, 0 },
+#ifdef NT
+ { "win95-safe", TVC_W95, 0 },
+#endif /* NT */
+ { "", 0, 0 }
+};
+int ntvctab = (sizeof(tvctab) / sizeof(struct keytab)) - 1;
+
+struct keytab msktab[] = { /* SET MS-DOS KERMIT compatibilities */
+#ifdef COMMENT
+ { "color", MSK_COLOR, 0 },
+#endif /* COMMENT */
+ { "keycodes", MSK_KEYS, 0 }
+};
+int nmsk = (sizeof(msktab) / sizeof(struct keytab));
+
+struct keytab scrnupd[] = { /* SET TERMINAL SCREEN-UPDATE */
+ { "fast", TTU_FAST, 0 },
+ { "smooth", TTU_SMOOTH, 0 }
+};
+int nscrnupd = (sizeof(scrnupd) / sizeof(struct keytab));
+
+#ifdef PCFONTS
+/* This definition of the term_font[] table is only for */
+/* the OS/2 Full Screen Session and is not used on Windows */
+struct keytab term_font[] = { /* SET TERMINAL FONT */
+#ifdef COMMENT
+ { "cp111", TTF_111, 0 },
+ { "cp112", TTF_112, 0 },
+ { "cp113", TTF_113, 0 },
+#endif /* COMMENT */
+ { "cp437", TTF_437, 0 },
+ { "cp850", TTF_850, 0 },
+#ifdef COMMENT
+ { "cp851", TTF_851, 0 },
+#endif /* COMMENT */
+ { "cp852", TTF_852, 0 },
+#ifdef COMMENT
+ { "cp853", TTF_853, 0 },
+ { "cp860", TTF_860, 0 },
+ { "cp861", TTF_861, 0 },
+#endif /* COMMENT */
+ { "cp862", TTF_862, 0 },
+#ifdef COMMENT
+ { "cp863", TTF_863, 0 },
+ { "cp864", TTF_864, 0 },
+ { "cp865", TTF_865, 0 },
+#endif /* COMMENT */
+ { "cp866", TTF_866, 0 },
+#ifdef COMMENT
+ { "cp880", TTF_880, 0 },
+ { "cp881", TTF_881, 0 },
+ { "cp882", TTF_882, 0 },
+ { "cp883", TTF_883, 0 },
+ { "cp884", TTF_884, 0 },
+ { "cp885", TTF_885, 0 },
+#endif /* COMMENT */
+ { "default",TTF_ROM,0 }
+};
+int ntermfont = (sizeof(term_font) / sizeof(struct keytab));
+int tt_font = TTF_ROM; /* Terminal screen font */
+#else /* PCFONTS */
+#ifdef NT
+#ifdef KUI
+struct keytab * term_font = NULL;
+struct keytab * _term_font = NULL;
+char * tt_facename = NULL;
+int ntermfont = 0;
+int tt_font = 0;
+int tt_font_size = 0;
+#endif /* KUI */
+#endif /* NT */
+#endif /* PCFONTS */
+
+struct keytab anbktab[] = { /* For any command that needs */
+ { "message", 2, 0 }, /* these keywords... */
+ { "off", 0, 0 },
+ { "on", 1, 0 },
+ { "unsafe-messag0", 99, CM_INV },
+ { "unsafe-message", 3, CM_INV }
+};
+int nansbk = (sizeof(anbktab) / sizeof(struct keytab));
+
+int win95_popup = 1;
+#ifdef NT
+#ifdef KUI
+int win95lucida = 0;
+int win95hsl = 1;
+#else /* KUI */
+int win95lucida = 1;
+int win95hsl = 1;
+#endif /* KUI */
+#else /* NT */
+int win95lucida = 0;
+int win95hsl = 1;
+#endif /* NT */
+#ifdef NT
+int win95altgr = 0;
+extern int win95selectbug;
+extern int win95_8_3;
+
+#ifdef COMMENT
+extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
+extern struct keytab tcstab[];
+extern int ntcs;
+#endif /* COMMENT */
+extern int maxow, maxow_usr; owwait; /* Overlapped I/O variables */
+#endif /* NT */
+#endif /* OS2 */
+
+
+/* The following routines broken out of doprm() to give compilers a break. */
+
+/* S E T O N -- Parse on/off (default on), set parameter to result */
+
+int
+seton(prm) int *prm; {
+ int x, y;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ *prm = y;
+ return(1);
+}
+
+/* S E T O N A U T O -- Parse on/off/auto (default auto) & set result */
+
+struct keytab onoffaut[] = {
+ { "auto", SET_AUTO, 0 }, /* 2 */
+ { "off", SET_OFF, 0 }, /* 0 */
+ { "on", SET_ON, 0 } /* 1 */
+};
+
+int
+setonaut(prm) int *prm; {
+ int x, y;
+ if ((y = cmkey(onoffaut,3,"","auto",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ *prm = y;
+ return(1);
+}
+
+/* S E T N U M -- Set parameter to result of cmnum() parse. */
+/*
+ Call with pointer to integer variable to be set,
+ x = number from cnum parse, y = return code from cmnum,
+ max = maximum value to accept, -1 if no maximum.
+ Returns -9 on failure, after printing a message, or 1 on success.
+*/
+int
+setnum(prm,x,y,max) int x, y, *prm, max; {
+ debug(F101,"setnum","",y);
+ if (y == -3) {
+ printf("\n?Value required\n");
+ return(-9);
+ }
+ if (y == -2) {
+ printf("%s?Not a number: %s\n",cmflgs == 1 ? "" : "\n", atxbuf);
+ return(-9);
+ }
+ if (y < 0) return(y);
+ if (max > -1 && x > max) {
+ printf("?Sorry, %d is the maximum\n",max);
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ *prm = x;
+ return(1);
+}
+
+/* S E T C C -- Set parameter var to an ASCII control character value. */
+/*
+ Parses a number, or a literal control character, or a caret (^) followed
+ by an ASCII character whose value is 63-95 or 97-122, then gets confirmation,
+ then sets the parameter to the code value of the character given. If there
+ are any parse errors, they are returned, otherwise on success 1 is returned.
+*/
+int
+setcc(dflt,var) char *dflt; int *var; {
+ int x, y;
+ unsigned int c;
+ char *hlpmsg = "Control character,\n\
+ numeric ASCII value,\n\
+ or in ^X notation,\n\
+ or preceded by a backslash and entered literally";
+
+ /* This is a hack to turn off complaints from expression evaluator. */
+ x_ifnum = 1;
+ y = cmnum(hlpmsg, dflt, 10, &x, xxstring); /* Parse a number */
+ x_ifnum = 0; /* Allow complaints again */
+ if (y < 0) { /* Parse failed */
+ if (y != -2) /* Reparse needed or somesuch */
+ return(y); /* Pass failure back up the chain */
+ }
+ /* Real control character or literal 8-bit character... */
+
+ for (c = strlen(atmbuf) - 1; c > 0; c--) /* Trim */
+ if (atmbuf[c] == SP) atmbuf[c] = NUL;
+
+ if (y < 0) { /* It was not a number */
+ if (((c = atmbuf[0])) && !atmbuf[1]) { /* Literal character? */
+ c &= 0xff;
+ if (((c > 31) && (c < 127)) || (c > 255)) {
+ printf("\n?%d: Out of range - must be 0-31 or 127-255\n",c);
+ return(-9);
+ } else {
+ if ((y = cmcfm()) < 0) /* Confirm */
+ return(y);
+ *var = c; /* Set the variable */
+ return(1);
+ }
+ } else if (atmbuf[0] == '^' && !atmbuf[2]) { /* Or ^X notation? */
+ c = atmbuf[1];
+ if (islower((char) c)) /* Uppercase lowercase letters */
+ c = toupper(c);
+ if (c > 62 && c < 96) { /* Check range */
+ if ((y = cmcfm()) < 0)
+ return(y);
+ *var = ctl(c); /* OK */
+ return(1);
+ } else {
+ printf("?Not a control character - %s\n", atmbuf);
+ return(-9);
+ }
+ } else { /* Something illegal was typed */
+ printf("?Invalid - %s\n", atmbuf);
+ return(-9);
+ }
+ }
+ if (((x > 31) && (x < 127)) || (x > 255)) { /* They typed a number */
+ printf("\n?%d: Out of range - must be 0-31 or 127-255\n",x);
+ return(-9);
+ }
+ if ((y = cmcfm()) < 0) /* In range, confirm */
+ return(y);
+ *var = x; /* Set variable */
+ return(1);
+}
+
+#ifndef NOSPL /* The SORT command... */
+
+static struct keytab srtswtab[] = { /* SORT command switches */
+ { "/case", SRT_CAS, CM_ARG },
+ { "/key", SRT_KEY, CM_ARG },
+ { "/numeric", SRT_NUM, 0 },
+ { "/range", SRT_RNG, CM_ARG },
+ { "/reverse", SRT_REV, 0 }
+};
+static int nsrtswtab = sizeof(srtswtab)/sizeof(struct keytab);
+
+extern char **a_ptr[]; /* Array pointers */
+extern int a_dim[]; /* Array dimensions */
+
+int
+dosort() { /* Do the SORT command */
+ char c, *p = NULL, ** ap, ** xp = NULL;
+ struct FDB sw, fl, cm;
+ int hi, lo;
+ int xn = 0, xr = -1, xk = -1, xc = -1, xs = 0;
+ int getval = 0, range[2], confirmed = 0;
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ "Array name or switch",
+ "", /* default */
+ "", /* addtl string data */
+ nsrtswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ NULL, /* Processing function */
+ srtswtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "Array name", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* Or premature confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ range[0] = -1;
+ range[1] = -1;
+
+ while (1) { /* Parse 0 or more switches */
+ x = cmfdb(&sw);
+ if (x < 0)
+ return(x);
+ if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
+ break;
+ c = cmgbrk();
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case SRT_REV:
+ xr = 1;
+ break;
+ case SRT_KEY:
+ if (getval) {
+ if ((y = cmnum("Column for comparison (1-based)",
+ "1",10,&x,xxstring)) < 0)
+ return(y);
+ xk = x - 1;
+ } else
+ xk = 0;
+ break;
+ case SRT_CAS:
+ if (getval) {
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ xc = y;
+ } else
+ xc = 1;
+ break;
+ case SRT_RNG: /* /RANGE */
+ if (getval) {
+ char buf[32];
+ char buf2[16];
+ int i;
+ char * p, * q;
+ if ((y = cmfld("low:high element","1",&s,NULL)) < 0)
+ return(y);
+ s = brstrip(s);
+ ckstrncpy(buf,s,32);
+ p = buf;
+ for (i = 0; *p && i < 2; i++) { /* Get low and high */
+ q = p; /* Start of this piece */
+ while (*p) { /* Find end of this piece */
+ if (*p == ':') {
+ *p = NUL;
+ p++;
+ break;
+ }
+ p++;
+ }
+ y = 15; /* Evaluate this piece */
+ s = buf2;
+ zzstring(q,&s,&y);
+ s = evalx(buf2);
+ if (s) if (*s) ckstrncpy(buf2,s,16);
+ if (!rdigits(buf2)) {
+ printf("?Not numeric: %s\n",buf2);
+ return(-9);
+ }
+ range[i] = atoi(buf2);
+ }
+ }
+ break;
+ case SRT_NUM: /* /NUMERIC */
+ xn = 1;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ switch (cmresult.fcode) {
+ case _CMCFM:
+ confirmed = 1;
+ break;
+ case _CMFLD:
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of name */
+ s = line;
+ break;
+ default:
+ printf("?Unexpected function code: %d\n",cmresult.fcode);
+ return(-9);
+ }
+ if (confirmed) {
+ printf("?Array name required\n");
+ return(-9);
+ }
+ ckmakmsg(tmpbuf,TMPBUFSIZ,
+ "Second array to sort according to ",s,NULL,NULL);
+ if ((x = cmfld(tmpbuf,"",&p,NULL)) < 0)
+ if (x != -3)
+ return(x);
+ tmpbuf[0] = NUL;
+ ckstrncpy(tmpbuf,p,TMPBUFSIZ);
+ p = tmpbuf;
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+
+ x = arraybounds(s,&lo,&hi); /* Get array index & bounds */
+ if (x < 0) { /* Check */
+ printf("?Bad array name: %s\n",s);
+ return(-9);
+ }
+ if (lo > -1) range[0] = lo; /* Set range */
+ if (hi > -1) range[1] = hi;
+ ap = a_ptr[x]; /* Get pointer to array element list */
+ if (!ap) { /* Check */
+ printf("?Array not declared: %s\n", s);
+ return(-9);
+ }
+ if (range[0] < 0) /* Starting element */
+ range[0] = 1;
+ if (range[1] < 0) /* Final element */
+ range[1] = a_dim[x];
+ if (range[1] > a_dim[x]) {
+ printf("?range %d:%d exceeds array dimension %d\n",
+ range[0],range[1],a_dim[x]
+ );
+ return(-9);
+ }
+ ap += range[0];
+ xs = range[1] - range[0] + 1; /* Number of elements to sort */
+ if (xs < 1) { /* Check */
+ printf("?Bad range: %d:%d\n",range[0],range[1]);
+ return(-9);
+ }
+ if (xk < 0) xk = 0; /* Key position */
+ if (xr < 0) xr = 0; /* Reverse flag */
+ if (xn) /* Numeric flag */
+ xc = 2;
+ else if (xc < 0) /* Not numeric */
+ xc = inpcas[cmdlvl]; /* so alpha case option */
+
+ if (*p) { /* Parallel array given? */
+ y = xarray(p); /* Yes, get its index. */
+ if (y < 0) {
+ printf("?Bad array name: %s\n", p);
+ return(-9);
+ }
+ if (y != x) { /* If the 2 arrays are different */
+ xp = a_ptr[y]; /* Pointer to 2nd array element list */
+ if (!xp) {
+ printf("?Array not declared: %s\n", p);
+ return(-9);
+ }
+ if (a_dim[y] < range[1]) {
+ printf("?Array %s smaller than %s\n", p, s);
+ return(-9);
+ }
+ xp += range[0]; /* Set base to same as 1st array */
+ }
+ }
+ sh_sort(ap,xp,xs,xk,xr,xc); /* Sort the array(s) */
+ return(success = 1); /* Always succeeds */
+}
+#endif /* NOSPL */
+
+static struct keytab purgtab[] = { /* PURGE command switches */
+ { "/after", PU_AFT, CM_ARG },
+ { "/ask", PU_ASK, 0 },
+ { "/before", PU_BEF, CM_ARG },
+ { "/delete", PU_DELE, CM_INV },
+#ifdef UNIXOROSK
+ { "/dotfiles", PU_DOT, 0 },
+#endif /* UNIXOROSK */
+ { "/except", PU_EXC, CM_ARG },
+ { "/heading", PU_HDG, 0 },
+ { "/keep", PU_KEEP, CM_ARG },
+ { "/larger-than", PU_LAR, CM_ARG },
+ { "/list", PU_LIST, 0 },
+ { "/log", PU_LIST, CM_INV },
+ { "/noask", PU_NASK, 0 },
+ { "/nodelete", PU_NODE, CM_INV },
+#ifdef UNIXOROSK
+ { "/nodotfiles", PU_NODOT,0 },
+#endif /* UNIXOROSK */
+ { "/noheading", PU_NOH, 0 },
+ { "/nol", PU_NOLI, CM_INV|CM_ABR },
+ { "/nolist", PU_NOLI, 0 },
+ { "/nolog", PU_NOLI, CM_INV },
+#ifdef CK_TTGWSIZ
+ { "/nopage", PU_NOPA, 0 },
+#endif /* CK_TTGWSIZ */
+ { "/not-after", PU_NAF, CM_ARG },
+ { "/not-before", PU_NBF, CM_ARG },
+ { "/not-since", PU_NAF, CM_INV|CM_ARG },
+#ifdef CK_TTGWSIZ
+ { "/page", PU_PAGE, 0 },
+#endif /* CK_TTGWSIZ */
+ { "/quiet", PU_QUIE, CM_INV },
+#ifdef RECURSIVE
+ { "/recursive", PU_RECU, 0 },
+#endif /* RECURSIVE */
+ { "/since", PU_AFT, CM_ARG|CM_INV },
+ { "/simulate", PU_NODE, 0 },
+ { "/smaller-than", PU_SMA, CM_ARG },
+ { "/verbose", PU_VERB, CM_INV }
+};
+static int npurgtab = sizeof(purgtab)/sizeof(struct keytab);
+
+
+
+
+
+int
+bkupnum(s,i) char * s; int *i; {
+ int k = 0, pos = 0;
+ char * p = NULL, *q;
+ *i = pos;
+ if (!s) s = "";
+ if (!*s)
+ return(-1);
+ if ((k = strlen(s)) < 5)
+ return(-1);
+
+ if (s[k-1] != '~')
+ return(-1);
+ pos = k - 2;
+ q = s + pos;
+ while (q >= s && isdigit(*q)) {
+ p = q--;
+ pos--;
+ }
+ if (!p)
+ return(-1);
+ if (q < s+2)
+ return(-1);
+ if (*q != '~' || *(q-1) != '.')
+ return(-1);
+ pos--;
+ *i = pos;
+ debug(F111,"bkupnum",s+pos,pos);
+ return(atoi(p));
+}
+
+#ifdef CKPURGE
+/* Presently only for UNIX because we need direct access to the file array. */
+/* Not needed for VMS anyway, because we don't make backup files there. */
+
+#define MAXKEEP 32 /* Biggest /KEEP: value */
+
+static int
+ pu_keep = 0, pu_list = 0, pu_dot = 0, pu_ask = 0, pu_hdg = 0;
+
+#ifdef CK_TTGWSIZ
+static int pu_page = -1;
+#else
+static int pu_page = 0;
+#endif /* CK_TTGWSIZ */
+
+#ifndef NOSHOW
+VOID
+showpurgopts() { /* SHOW PURGE command options */
+ int x = 0;
+ extern int optlines;
+ prtopt(&optlines,"PURGE");
+ if (pu_ask > -1) {
+ x++;
+ prtopt(&optlines, pu_ask ? "/ASK" : "/NOASK");
+ }
+#ifdef UNIXOROSK
+ if (pu_dot > -1) {
+ x++;
+ prtopt(&optlines, pu_dot ? "/DOTFILES" : "/NODOTFILES");
+ }
+#endif /* UNIXOROSK */
+ if (pu_keep > -1) {
+ x++;
+ ckmakmsg(tmpbuf,TMPBUFSIZ,"/KEEP:",ckitoa(pu_keep),NULL,NULL);
+ prtopt(&optlines,tmpbuf);
+ }
+ if (pu_list > -1) {
+ x++;
+ prtopt(&optlines, pu_list ? "/LIST" : "/NOLIST");
+ }
+ if (pu_hdg > -1) {
+ x++;
+ prtopt(&optlines, pu_hdg ? "/HEADING" : "/NOHEADING");
+ }
+#ifdef CK_TTGWSIZ
+ if (pu_page > -1) {
+ x++;
+ prtopt(&optlines, pu_page ? "/PAGE" : "/NOPAGE");
+ }
+#endif /* CK_TTGWSIZ */
+ if (!x) prtopt(&optlines,"(no options set)");
+ prtopt(&optlines,"");
+}
+#endif /* NOSHOW */
+
+int
+setpurgopts() { /* Set PURGE command options */
+ int c, z, getval = 0;
+ int
+ x_keep = -1, x_list = -1, x_page = -1,
+ x_hdg = -1, x_ask = -1, x_dot = -1;
+
+ while (1) {
+ if ((y = cmswi(purgtab,npurgtab,"Switch","",xxstring)) < 0) {
+ if (y == -3)
+ break;
+ else
+ return(y);
+ }
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (y) {
+ case PU_KEEP:
+ z = 1;
+ if (c == ':' || c == '=')
+ if ((y = cmnum("How many backup files to keep",
+ "1",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > MAXKEEP) {
+ printf("?Please specify a number between 0 and %d\n",
+ MAXKEEP
+ );
+ return(-9);
+ }
+ x_keep = z;
+ break;
+ case PU_LIST:
+ case PU_VERB:
+ x_list = 1;
+ break;
+ case PU_QUIE:
+ case PU_NOLI:
+ x_list = 0;
+ break;
+#ifdef CK_TTGWSIZ
+ case PU_PAGE:
+ x_page = 1;
+ break;
+ case PU_NOPA:
+ x_page = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+ case PU_HDG:
+ x_hdg = 1;
+ break;
+ case PU_NOH:
+ x_hdg = 0;
+ break;
+ case PU_ASK:
+ x_ask = 1;
+ break;
+ case PU_NASK:
+ x_ask = 0;
+ break;
+#ifdef UNIXOROSK
+ case PU_DOT:
+ x_dot = 1;
+ break;
+ case PU_NODOT:
+ x_dot = 0;
+ break;
+#endif /* UNIXOROSK */
+ default:
+ printf("?This option can not be set\n");
+ return(-9);
+ }
+ }
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ if (x_keep > -1) /* Set PURGE defaults. */
+ pu_keep = x_keep;
+ if (x_list > -1)
+ pu_list = x_list;
+#ifdef CK_TTGWSIZ
+ if (x_page > -1)
+ pu_page = x_page;
+#endif /* CK_TTGWSIZ */
+ if (x_hdg > -1)
+ pu_hdg = x_hdg;
+ if (x_ask > -1)
+ pu_ask = x_ask;
+ if (x_dot > -1)
+ pu_dot = x_dot;
+ return(success = 1);
+}
+
+int
+dopurge() { /* Do the PURGE command */
+ extern char ** mtchs;
+ extern int xaskmore, cmd_rows, recursive;
+ int simulate = 0, asking = 0;
+ int listing = 0, paging = -1, lines = 0, deleting = 1, errors = 0;
+ struct FDB sw, sf, cm;
+ int g, i, j, k, m = 0, n, x, y, z, done = 0, count = 0, flags = 0;
+ int tokeep = 0, getval = 0, havename = 0, confirmed = 0;
+ int xx[MAXKEEP+1]; /* Array of numbers to keep */
+ int min = -1;
+ int x_hdg = 0, fs = 0, rc = 0;
+ long minsize = -1L, maxsize = -1L;
+ char namebuf[CKMAXPATH+4];
+ char basebuf[CKMAXPATH+4];
+ char
+ * pu_aft = NULL,
+ * pu_bef = NULL,
+ * pu_naf = NULL,
+ * pu_nbf = NULL,
+ * pu_exc = NULL;
+ char * pxlist[8]; /* Exception list */
+
+ if (pu_keep > -1) /* Set PURGE defaults. */
+ tokeep = pu_keep;
+ if (pu_list > -1)
+ listing = pu_list;
+#ifdef CK_TTGWSIZ
+ if (pu_page > -1)
+ paging = pu_page;
+#endif /* CK_TTGWSIZ */
+
+ for (i = 0; i <= MAXKEEP; i++) /* Clear this number buffer */
+ xx[i] = 0;
+ for (i = 0; i < 8; i++) /* Initialize these... */
+ pxlist[i] = NULL;
+
+ g_matchdot = matchdot; /* Save these... */
+
+ cmfdbi(&sw, /* 1st FDB - PURGE switches */
+ _CMKEY, /* fcode */
+ "Filename or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ npurgtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ purgtab, /* Keyword table */
+ &sf /* Pointer to next FDB */
+ );
+ cmfdbi(&sf, /* 2nd FDB - filespec to purge */
+ _CMIFI, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ &cm
+ );
+ cmfdbi(&cm, /* Or premature confirmation */
+ _CMCFM, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ NULL,
+ NULL,
+ NULL
+ );
+
+ while (!havename && !confirmed) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) { /* Error */
+ rc = x;
+ goto xpurge;
+ } else if (cmresult.fcode == _CMKEY) {
+ char c;
+ c = cmgbrk();
+ if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ rc = -9;
+ goto xpurge;
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ rc = -9;
+ goto xpurge;
+ }
+ switch (k = cmresult.nresult) {
+ case PU_KEEP:
+ z = 1;
+ if (c == ':' || c == '=') {
+ if ((y = cmnum("How many backup files to keep",
+ "1",10,&z,xxstring)) < 0) {
+ rc = y;
+ goto xpurge;
+ }
+ }
+ if (z < 0 || z > MAXKEEP) {
+ printf("?Please specify a number between 0 and %d\n",
+ MAXKEEP
+ );
+ rc = -9;
+ goto xpurge;
+ }
+ tokeep = z;
+ break;
+ case PU_LIST:
+ listing = 1;
+ break;
+ case PU_NOLI:
+ listing = 0;
+ break;
+#ifdef CK_TTGWSIZ
+ case PU_PAGE:
+ paging = 1;
+ break;
+ case PU_NOPA:
+ paging = 0;
+ break;
+#endif /* CK_TTGWSIZ */
+ case PU_DELE:
+ deleting = 1;
+ break;
+ case PU_NODE:
+ deleting = 0;
+ simulate = 1;
+ listing = 1;
+ break;
+ case PU_ASK:
+ asking = 1;
+ break;
+ case PU_NASK:
+ asking = 0;
+ break;
+ case PU_AFT:
+ case PU_BEF:
+ case PU_NAF:
+ case PU_NBF:
+ if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Date-time required\n");
+ rc = -9;
+ } else
+ rc = x;
+ goto xpurge;
+ }
+ fs++;
+ switch (k) {
+ case PU_AFT: makestr(&pu_aft,s); break;
+ case PU_BEF: makestr(&pu_bef,s); break;
+ case PU_NAF: makestr(&pu_naf,s); break;
+ case PU_NBF: makestr(&pu_nbf,s); break;
+ }
+ break;
+ case PU_SMA:
+ case PU_LAR:
+ if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0) {
+ rc = x;
+ goto xpurge;
+ }
+ fs++;
+ switch (cmresult.nresult) {
+ case PU_SMA: minsize = y; break;
+ case PU_LAR: maxsize = y; break;
+ }
+ break;
+ case PU_DOT:
+ matchdot = 1;
+ break;
+ case PU_NODOT:
+ matchdot = 0;
+ break;
+ case PU_EXC:
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Pattern required\n");
+ rc = -9;
+ } else
+ rc = x;
+ goto xpurge;
+ }
+ fs++;
+ makestr(&pu_exc,s);
+ break;
+ case PU_HDG:
+ x_hdg = 1;
+ break;
+#ifdef RECURSIVE
+ case PU_RECU: /* /RECURSIVE */
+ recursive = 2;
+ break;
+#endif /* RECURSIVE */
+ default:
+ printf("?Not implemented yet - \"%s\"\n",atmbuf);
+ rc = -9;
+ goto xpurge;
+ }
+ } else if (cmresult.fcode == _CMIFI) {
+ havename = 1;
+ } else if (cmresult.fcode == _CMCFM) {
+ confirmed = 1;
+ } else {
+ rc = -2;
+ goto xpurge;
+ }
+ }
+ if (havename) {
+#ifdef CKREGEX
+ ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~[1-9]*~",NULL,NULL);
+#else
+ ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~*~",NULL,NULL);
+#endif /* CKREGEX */
+ } else {
+#ifdef CKREGEX
+ ckstrncpy(line,"*.~[1-9]*~",LINBUFSIZ);
+#else
+ ckstrncpy(line,"*.~*~",LINBUFSIZ);
+#endif /* CKREGEX */
+ }
+ if (!confirmed) {
+ if ((x = cmcfm()) < 0) {
+ rc = x;
+ goto xpurge;
+ }
+ }
+ /* Parse finished - now action */
+
+#ifdef CK_LOGIN
+ if (isguest) {
+ printf("?File deletion by guests not permitted.\n");
+ rc = -9;
+ goto xpurge;
+ }
+#endif /* CK_LOGIN */
+
+#ifdef CK_TTGWSIZ
+ if (paging < 0) /* /[NO]PAGE not given */
+ paging = xaskmore; /* so use prevailing */
+#endif /* CK_TTGWSIZ */
+
+ lines = 0;
+ if (x_hdg > 0) {
+ printf("Purging %s, keeping %d...%s\n",
+ s,
+ tokeep,
+ simulate ? " (SIMULATION)" : "");
+ lines += 2;
+ }
+ flags = ZX_FILONLY;
+ if (recursive) flags |= ZX_RECURSE;
+ n = nzxpand(line,flags); /* Get list of backup files */
+ if (tokeep < 1) { /* Deleting all of them... */
+ for (i = 0; i < n; i++) {
+ if (fs) if (fileselect(mtchs[i],
+ pu_aft,pu_bef,pu_naf,pu_nbf,
+ minsize,maxsize,0,8,pxlist) < 1) {
+ if (listing > 0) {
+ printf(" %s (SKIPPED)\n",mtchs[i]);
+#ifdef CK_TTGWSIZ
+ if (paging)
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ continue;
+ }
+ if (asking) {
+ int x;
+ ckmakmsg(tmpbuf,TMPBUFSIZ," Delete ",mtchs[i],"?",NULL);
+ x = getyesno(tmpbuf,1);
+ switch (x) {
+ case 0: continue;
+ case 1: break;
+ case 2: goto xpurge;
+ }
+ }
+ x = deleting ? zdelet(mtchs[i]) : 0;
+ if (x > -1) {
+ if (listing)
+ printf(" %s (%s)\n", mtchs[i],deleting ? "OK" : "SELECTED");
+ count++;
+ } else {
+ errors++;
+ if (listing)
+ printf(" %s (FAILED)\n", mtchs[i]);
+ }
+#ifdef CK_TTGWSIZ
+ if (listing && paging)
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ goto xpurge;
+ }
+ if (n < tokeep) { /* Not deleting any */
+ count = 0;
+ if (listing)
+ printf(" Matches = %d: Not enough to purge.\n");
+ goto xpurge;
+ }
+
+ /* General case - delete some but not others */
+
+ sh_sort(mtchs,NULL,n,0,0,filecase); /* Alphabetize the list (ESSENTIAL) */
+
+ g = 0; /* Start of current group */
+ for (i = 0; i < n; i++) { /* Go thru sorted file list */
+ x = znext(namebuf); /* Get next file */
+ if (x < 1 || !namebuf[0] || i == n - 1) /* No more? */
+ done = 1; /* NOTE: 'done' must be 0 or 1 only */
+ if (fs) if (fileselect(namebuf,
+ pu_aft,pu_bef,pu_naf,pu_nbf,
+ minsize,maxsize,0,8,pxlist) < 1) {
+ if (listing > 0) {
+ printf(" %s (SKIPPED)\n",namebuf);
+ if (++lines > cmd_rows - 3)
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+ continue;
+ }
+ if (x > 0)
+ if ((m = bkupnum(namebuf,&z)) < 0) /* This file's backup number. */
+ continue;
+ for (j = 0; j < tokeep; j++) { /* Insert in list. */
+ if (m > xx[j]) {
+ for (k = tokeep - 1; k > j; k--)
+ xx[k] = xx[k-1];
+ xx[j] = m;
+ break;
+ }
+ }
+ /* New group? */
+ if (done || (i > 0 && ckstrcmp(namebuf,basebuf,z,1))) {
+ if (i + done - g > tokeep) { /* Do we have enough to purge? */
+ min = xx[tokeep-1]; /* Yes, lowest backup number to keep */
+ debug(F111,"dopurge group",basebuf,min);
+ for (j = g; j < i + done; j++) { /* Go through this group */
+ x = bkupnum(mtchs[j],&z); /* Get file backup number */
+ if (x > 0 && x < min) { /* Below minimum? */
+ x = deleting ? zdelet(mtchs[j]) : 0;
+ if (x < 0) errors++;
+ if (listing)
+ printf(" %s (%s)\n",
+ mtchs[j],
+ ((x < 0) ? "ERROR" :
+ (deleting ? "DELETED" : "SELECTED"))
+ );
+ count++;
+ } else if (listing) /* Not below minimum - keep this one */
+ printf(" %s (KEPT)\n",mtchs[j]);
+#ifdef CK_TTGWSIZ
+ if (listing && paging)
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ } else if (listing && paging) { /* Not enough to purge */
+ printf(" %s.~*~ (KEPT)\n",basebuf);
+#ifdef CK_TTGWSIZ
+ if (++lines > cmd_rows - 3) {
+ if (!askmore()) goto xpurge; else lines = 0;
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ for (j = 0; j < tokeep; j++) /* Clear the backup number list */
+ xx[j] = 0;
+ g = i; /* Reset the group pointer */
+ }
+ if (done) /* No more files, done. */
+ break;
+ strncpy(basebuf,namebuf,z); /* Set basename of this file */
+ basebuf[z] = NUL;
+ }
+ xpurge: /* Common exit point */
+ if (g_matchdot > -1) {
+ matchdot = g_matchdot; /* Restore these... */
+ g_matchdot = -1;
+ }
+ if (rc < 0) return(rc); /* Parse error */
+ if (x_hdg)
+ printf("Files purged: %d%s\n",
+ count,
+ deleting ? "" : " (not really)"
+ );
+ return(success = count > 0 ? 1 : (errors > 0) ? 0 : 1);
+}
+#endif /* CKPURGE */
+
+#ifndef NOXFER
+#ifndef NOLOCAL
+int
+doxdis(which) int which; { /* 1 = Kermit, 2 = FTP */
+ extern int nolocal;
+ int x, y = 0, z;
+#ifdef NEWFTP
+ extern int ftp_dis;
+#endif /* NEWFTP */
+
+#ifdef COMMENT
+ char *s;
+#endif /* COMMENT */
+
+ if ((x = cmkey(fdtab,nfdtab,"file transfer display style","",
+ xxstring)) < 0)
+ return(x);
+#ifdef CK_PCT_BAR
+ if ((y = cmkey(fdftab,2,"","thermometer",xxstring)) < 0)
+ return(y);
+#endif /* CK_PCT_BAR */
+ if ((z = cmcfm()) < 0) return(z);
+#ifdef CK_CURSES
+ if (x == XYFD_C) { /* FULLSCREEN */
+#ifdef COMMENT
+#ifndef MYCURSES
+ extern char * trmbuf; /* Real curses */
+ int z;
+#endif /* MYCURSES */
+#endif /* COMMENT */
+
+ if (nolocal) /* Nothing to do in this case */
+ return(success = 1);
+
+#ifdef COMMENT
+#ifndef MYCURSES
+#ifndef VMS
+ s = getenv("TERM");
+ debug(F110,"doxdis TERM",s,0);
+ if (!s) s = "";
+ fxdinit(x);
+ if (*s && trmbuf) { /* Don't call tgetent */
+ z = tgetent(trmbuf,s); /* if trmbuf not allocated */
+ debug(F111,"doxdis tgetent",s,z);
+ } else {
+ z = 0;
+ debug(F110,"doxdis tgetent skipped",s,0);
+ }
+ if (z < 1) {
+ printf("Sorry, terminal type unknown: \"%s\"\n",s);
+ return(success = 0);
+ }
+#endif /* VMS */
+#endif /* MYCURSES */
+#else
+ fxdinit(x);
+#endif /* COMMENT */
+
+#ifdef CK_PCT_BAR
+ thermometer = y;
+#endif /* CK_PCT_BAR */
+
+ line[0] = '\0'; /* (What's this for?) */
+ }
+#endif /* CK_CURSES */
+ if (which == 1) /* It's OK. */
+ fdispla = x;
+#ifdef NEWFTP
+ else
+ ftp_dis = x;
+#endif /* NEWFTP */
+ return(success = 1);
+}
+#endif /* NOLOCAL */
+#endif /* NOXFER */
+
+int
+setfil(rmsflg) int rmsflg; {
+#ifdef COMMENT
+ extern int en_del;
+#endif /* COMMENT */
+#ifndef NOXFER
+ if (rmsflg) {
+ if ((y = cmkey(rfiltab,nrfilp,"Remote file parameter","",
+ xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Remote file parameter required\n");
+ return(-9);
+ } else return(y);
+ }
+ } else {
+#endif /* NOXFER */
+ if ((y = cmkey(filtab,nfilp,"File parameter","",xxstring)) < 0)
+ return(y);
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+ switch (y) {
+#ifdef COMMENT /* Not needed */
+ case XYFILB: /* Blocksize */
+ if ((y = cmnum("file block size",ckitoa(DBLKSIZ),10,&z,xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S', "311", ckitoa(z), "");
+ return((int) sstate);
+ } else {
+ fblksiz = z;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+
+#ifndef NOXFER
+ case XYFILS: /* Byte size */
+ if ((y = cmnum("file byte size (7 or 8)","8",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 7 && z != 8) {
+ printf("\n?The choices are 7 and 8\n");
+ return(0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ if (z == 7) fmask = 0177;
+ else if (z == 8) fmask = 0377;
+ return(success = 1);
+
+#ifndef NOCSETS
+ case XYFILC: { /* Character set */
+ char * csetname = NULL;
+ extern int
+ r_cset, s_cset, afcset[]; /* SEND CHARACTER-SET AUTO or MANUAL */
+
+ struct FDB kw, fl;
+ cmfdbi(&kw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ rmsflg ? "server character-set name" : "", /* help */
+ "", /* default */
+ "", /* addtl string data */
+ nfilc, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 0 = keyword */
+ xxstring, /* Processing function */
+ fcstab, /* Keyword table */
+ rmsflg ? &fl : NULL /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ if ((x = cmfdb(&kw)) < 0)
+ return(x);
+ if (cmresult.fcode == _CMKEY) {
+ x = cmresult.nresult;
+ csetname = fcsinfo[x].keyword;
+ } else {
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
+ csetname = line;
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ if (rmsflg) {
+ sstate = setgen('S', "320", csetname, "");
+ return((int) sstate);
+ }
+ fcharset = x;
+ if (s_cset == XMODE_A) /* If SEND CHARACTER-SET is AUTO */
+ if (x > -1 && x <= MAXFCSETS)
+ if (afcset[x] > -1 && afcset[x] <= MAXTCSETS)
+ tcharset = afcset[x]; /* Pick corresponding xfer charset */
+ setxlatype(tcharset,fcharset); /* Translation type */
+ /* If I say SET FILE CHARACTER-SET blah, I want to be blah! */
+ r_cset = XMODE_M; /* Don't switch incoming set! */
+ x = fcsinfo[fcharset].size; /* Also set default x-bit charset */
+ if (x == 128) /* 7-bit... */
+ dcset7 = fcharset;
+ else if (x == 256) /* 8-bit... */
+ dcset8 = fcharset;
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+#ifndef NOLOCAL
+ case XYFILD: /* Display */
+ return(doxdis(1)); /* 1 == kermit */
+#endif /* NOLOCAL */
+#endif /* NOXFER */
+
+ case XYFILA: /* End-of-line */
+#ifdef NLCHAR
+ s = "";
+ if (NLCHAR == 015)
+ s = "cr";
+ else if (NLCHAR == 012)
+ s = "lf";
+ if ((x = cmkey(eoltab, neoltab,
+ "local text-file line terminator",s,xxstring)) < 0)
+ return(x);
+#else
+ if ((x = cmkey(eoltab, neoltab,
+ "local text-file line terminator","crlf",xxstring)) < 0)
+ return(x);
+#endif /* NLCHAR */
+ if ((z = cmcfm()) < 0) return(z);
+ feol = (CHAR) x;
+ return(success = 1);
+
+#ifndef NOXFER
+ case XYFILN: /* Names */
+ if ((x = cmkey(fntab,nfntab,"how to handle filenames","converted",
+ xxstring)) < 0)
+ return(x);
+ if ((z = cmcfm()) < 0) return(z);
+ if (rmsflg) {
+ sstate = setgen('S', "301", ckitoa(1 - x), "");
+ return((int) sstate);
+ } else {
+ ptab[protocol].fncn = x; /* Set structure */
+ fncnv = x; /* Set variable */
+ f_save = x; /* And set "permanent" variable */
+ return(success = 1);
+ }
+
+ case XYFILR: /* Record length */
+ if ((y = cmnum("file record length",
+ ckitoa(DLRECL),10,&z,xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S', "312", ckitoa(z), "");
+ return((int) sstate);
+ } else {
+ frecl = z;
+ return(success = 1);
+ }
+
+#ifdef COMMENT
+ case XYFILO: /* Organization */
+ if ((x = cmkey(forgtab,nforg,"file organization","sequential",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "314", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+ forg = x;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT /* Not needed */
+ case XYFILF: /* Format */
+ if ((x = cmkey(frectab,nfrec,"file record format","stream",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "313", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+ frecfm = x;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+
+#ifdef COMMENT
+ case XYFILP: /* Printer carriage control */
+ if ((x = cmkey(fcctab,nfcc,"file carriage control","newline",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ if (rmsflg) {
+ sstate = setgen('S', "315", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+ fcctrl = x;
+ return(success = 1);
+ }
+#endif /* COMMENT */
+#endif /* NOXFER */
+
+ case XYFILT: /* Type */
+ if ((x = cmkey(rmsflg ? rfttab : fttab,
+ rmsflg ? nrfttyp : nfttyp,
+ "type of file transfer","text",xxstring)) < 0)
+ return(x);
+
+#ifdef VMS
+ /* Allow VMS users to choose record format for binary files */
+ if ((x == XYFT_B) && (rmsflg == 0)) {
+ if ((x = cmkey(fbtab,nfbtyp,"VMS record format","fixed",
+ xxstring)) < 0)
+ return(x);
+ }
+#endif /* VMS */
+ if ((y = cmcfm()) < 0) return(y);
+ binary = x;
+ b_save = x;
+#ifdef MAC
+ (void) mac_setfildflg(binary);
+#endif /* MAC */
+#ifndef NOXFER
+ if (rmsflg) {
+ /* Allow for LABELED in VMS & OS/2 */
+ sstate = setgen('S', "300", ckitoa(x), "");
+ return((int) sstate);
+ } else {
+#endif /* NOXFER */
+ return(success = 1);
+#ifndef NOXFER
+ }
+#endif /* NOXFER */
+
+#ifndef NOXFER
+ case XYFILX: /* Collision Action */
+ if ((x = cmkey(colxtab,ncolx,"Filename collision action","backup",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef CK_LOGIN
+ if (isguest) {
+ /* Don't let guests change existing files */
+ printf("?This command not valid for guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+#ifdef COMMENT
+ /* Not appropriate - DISABLE DELETE only refers to server */
+ if ((x == XYFX_X || x == XYFX_B || x == XYFX_U || x == XYFX_A) &&
+ (!ENABLED(en_del))) {
+ printf("?Sorry, file deletion is disabled.\n");
+ return(-9);
+ }
+#endif /* COMMENT */
+ fncact = x;
+ ptab[protocol].fnca = x;
+ if (rmsflg) {
+ sstate = setgen('S', "302", ckitoa(fncact), "");
+ return((int) sstate);
+ } else {
+ if (fncact == XYFX_R) ckwarn = 1; /* FILE WARNING implications */
+ if (fncact == XYFX_X) ckwarn = 0; /* ... */
+ return(success = 1);
+ }
+
+ case XYFILW: /* Warning/Write-Protect */
+ if ((x = seton(&ckwarn)) < 0) return(x);
+ if (ckwarn)
+ fncact = XYFX_R;
+ else
+ fncact = XYFX_X;
+ return(success = 1);
+
+#ifdef CK_LABELED
+ case XYFILL: /* LABELED FILE parameters */
+ if ((x = cmkey(lbltab,nlblp,"Labeled file feature","",
+ xxstring)) < 0)
+ return(x);
+ if ((success = seton(&y)) < 0)
+ return(success);
+ if (y) /* Set or reset the selected bit */
+ lf_opts |= x; /* in the options bitmask. */
+ else
+ lf_opts &= ~x;
+ return(success);
+#endif /* CK_LABELED */
+
+ case XYFILI: { /* INCOMPLETE */
+ extern struct keytab ifdatab[];
+ extern int keep;
+ if ((y = cmkey(ifdatab,3,"","auto",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (rmsflg) {
+ sstate = setgen('S',
+ "310",
+ y == 0 ? "0" : (y == 1 ? "1" : "2"),
+ ""
+ );
+ return((int) sstate);
+ } else {
+ keep = y;
+ return(success = 1);
+ }
+ }
+
+#ifdef CK_TMPDIR
+ case XYFILG: { /* Download directory */
+ int x;
+ char *s;
+#ifdef ZFNQFP
+ struct zfnfp * fnp;
+#endif /* ZFNQFP */
+#ifdef MAC
+ char temp[34];
+#endif /* MAC */
+
+#ifdef GEMDOS
+ if ((x = cmdir("Name of local directory, or carriage return",
+ "",&s,
+ NULL)) < 0 ) {
+ if (x != -3)
+ return(x);
+ }
+#else
+#ifdef OS2
+ if ((x = cmdir("Name of PC disk and/or directory,\n\
+ or press the Enter key to use current directory",
+ "",&s,xxstring)) < 0 ) {
+ if (x != -3)
+ return(x);
+ }
+#else
+#ifdef MAC
+ x = ckstrncpy(temp,zhome(),32);
+ if (x > 0) if (temp[x-1] != ':') { temp[x] = ':'; temp[x+1] = NUL; }
+ if ((x = cmtxt("Name of Macintosh volume and/or folder,\n\
+ or press the Return key for the desktop on the boot disk",
+ temp,&s, xxstring)) < 0 )
+ return(x);
+#else
+ if ((x = cmdir("Name of local directory, or carriage return",
+ "", &s, xxstring)) < 0 ) {
+ if (x != -3)
+ return(x);
+ }
+#endif /* MAC */
+#endif /* OS2 */
+#endif /* GEMDOS */
+ debug(F110,"download dir",s,0);
+
+#ifndef MAC
+ if (x == 2) {
+ printf("?Wildcards not allowed in directory name\n");
+ return(-9);
+ }
+#endif /* MAC */
+
+#ifdef ZFNQFP
+ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
+ if (fnp->fpath)
+ if ((int) strlen(fnp->fpath) > 0)
+ s = fnp->fpath;
+ }
+ debug(F110,"download zfnqfp",s,0);
+#endif /* ZFNQFP */
+
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */
+#ifndef MAC
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+#endif /* MAC */
+
+#ifdef CK_LOGIN
+ if (isguest) {
+ /* Don't let guests change existing files */
+ printf("?This command not valid for guests\n");
+ return(-9);
+ }
+#endif /* CK_LOGIN */
+ x = strlen(s);
+
+ if (x) {
+#ifdef datageneral /* AOS/VS */
+ if (s[x-1] == ':') /* homdir ends in colon, */
+ s[x-1] = NUL; /* and "dir" doesn't like that... */
+#else
+#ifdef OS2ORUNIX /* Unix or K-95... */
+ if ((x < (LINBUFSIZ - 2)) && /* Add trailing dirsep */
+ (s[x-1] != '/')) { /* if none present. */
+ s[x] = '/'; /* Note that Windows path has */
+ s[x+1] = NUL; /* been canonicalized to forward */
+ } /* slashes at this point. */
+#endif /* OS2ORUNIX */
+#endif /* datageneral */
+ makestr(&dldir,s);
+ } else
+ makestr(&dldir,NULL); /* dldir is NULL when not assigned */
+
+ return(success = 1);
+ }
+#endif /* CK_TMPDIR */
+ case XYFILY:
+ return(setdest());
+#endif /* NOXFER */
+
+#ifdef CK_CTRLZ
+ case XYFILV: { /* EOF */
+ extern int eofmethod;
+ if ((x = cmkey(eoftab,3,"end-of-file detection method","",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ eofmethod = x;
+ return(success = 1);
+ }
+#endif /* CK_CTRLZ */
+
+#ifndef NOXFER
+#ifdef UNIX
+ case XYFILH: { /* OUTPUT */
+ extern int zofbuffer, zobufsize, zofblock;
+#ifdef DYNAMIC
+ extern char * zoutbuffer;
+#endif /* DYNAMIC */
+
+ if ((x = cmkey(zoftab,nzoftab,"output file writing method","",
+ xxstring)) < 0)
+ return(x);
+ if (x == ZOF_BUF || x == ZOF_NBUF) {
+ if ((y = cmnum("output buffer size","32768",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 1) {
+ printf("?Bad size - %d\n", z);
+ return(-9);
+ }
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ switch (x) {
+ case ZOF_BUF:
+ case ZOF_NBUF:
+ zofbuffer = (x == ZOF_BUF);
+ zobufsize = z;
+ break;
+ case ZOF_BLK:
+ case ZOF_NBLK:
+ zofblock = (x == ZOF_BLK);
+ break;
+ }
+#ifdef DYNAMIC
+ if (zoutbuffer) free(zoutbuffer);
+ if (!(zoutbuffer = (char *)malloc(z))) {
+ printf("MEMORY ALLOCATION ERROR - FATAL\n");
+ doexit(BAD_EXIT,-1);
+ } else
+ zobufsize = z;
+#else
+ if (z <= OBUFSIZE) {
+ zobufsize = z;
+ } else {
+ printf("?Sorry, %d is too big - %d is the maximum\n",z,OBUFSIZE);
+ return(-9);
+ }
+#endif /* DYNAMIC */
+ return(success = 1);
+ }
+#endif /* UNIX */
+
+#ifdef PATTERNS
+ case XYFIBP: /* BINARY-PATTERN */
+ case XYFITP: { /* TEXT-PATTERN */
+ char * tmp[FTPATTERNS];
+ int i, n = 0;
+ while (n < FTPATTERNS) {
+ tmp[n] = NULL;
+ if ((x = cmfld("Pattern","",&s,xxstring)) < 0)
+ break;
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+ makestr(&(tmp[n++]),s);
+ }
+ if (x == -3) x = cmcfm();
+ for (i = 0; i <= n; i++) {
+ if (x > -1) {
+ if (y == XYFIBP)
+ makestr(&(binpatterns[i]),tmp[i]);
+ else
+ makestr(&(txtpatterns[i]),tmp[i]);
+ }
+ free(tmp[i]);
+ }
+ if (y == XYFIBP) /* Null-terminate the list */
+ makestr(&(binpatterns[i]),NULL);
+ else
+ makestr(&(txtpatterns[i]),NULL);
+ return(x);
+ }
+
+ case XYFIPA: /* PATTERNS */
+ if ((x = setonaut(&patterns)) < 0)
+ return(x);
+ return(success = 1);
+#endif /* PATTERNS */
+#endif /* NOXFER */
+
+#ifdef UNICODE
+ case XYFILU: { /* UCS */
+ extern int ucsorder, ucsbom, byteorder;
+ if ((x = cmkey(ucstab,nucstab,"","",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case UCS_BYT:
+ if ((y = cmkey(botab,nbotab,
+ "Byte order",
+ byteorder ? "little-endian" : "big-endian",
+ xxstring
+ )
+ ) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ ucsorder = y;
+ return(success = 1);
+ case UCS_BOM:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ ucsbom = y;
+ return(success = 1);
+ default:
+ return(-2);
+ }
+ }
+#endif /* UNICODE */
+
+#ifndef datageneral
+ case XYF_INSP: { /* SCAN (INSPECTION) */
+ extern int filepeek, nscanfile;
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(x);
+ if (y) {
+ if ((y = cmnum("How much to scan",ckitoa(SCANFILEBUF),
+ 10,&z,xxstring)) < 0)
+ return(y);
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+#ifdef VMS
+ filepeek = 0;
+ nscanfile = 0;
+ return(success = 0);
+#else
+ filepeek = x;
+ nscanfile = z;
+ return(success = 1);
+#endif /* VMS */
+ }
+#endif /* datageneral */
+
+ case XYF_DFLT:
+ y = 0;
+#ifndef NOCSETS
+ if ((y = cmkey(fdfltab,nfdflt,"","",xxstring)) < 0)
+ return(y);
+ if (y == 7 || y == 8) {
+ if (y == 7)
+ s = fcsinfo[dcset7].keyword;
+ else
+ s = fcsinfo[dcset8].keyword;
+ if ((x = cmkey(fcstab,nfilc,"character-set",s,xxstring)) < 0)
+ return(x);
+ }
+ ckstrncpy(line,fcsinfo[x].keyword,LINBUFSIZ);
+ s = line;
+#endif /* NOCSETS */
+ if ((z = cmcfm()) < 0)
+ return(z);
+ switch (y) {
+#ifndef NOCSETS
+ case 7:
+ if (fcsinfo[x].size != 128) {
+ printf("%s - Not a 7-bit set\n",s);
+ return(-9);
+ }
+ dcset7 = x;
+ break;
+ case 8:
+ if (fcsinfo[x].size != 256) {
+ printf("%s - Not an 8-bit set\n",s);
+ return(-9);
+ }
+ dcset8 = x;
+ break;
+#endif /* NOCSETS */
+ default:
+ return(-2);
+ }
+ return(success = 1);
+
+#ifndef NOXFER
+ case 9997: /* FASTLOOKUPS */
+ return(success = seton(&stathack));
+#endif /* NOXFER */
+
+#ifdef UNIX
+#ifdef DYNAMIC
+ case XYF_LSIZ: { /* LISTSIZE */
+ int zz;
+ y = cmnum("Maximum number of filenames","",10,&x,xxstring);
+ if ((x = setnum(&zz,x,y,-1)) < 0)
+ return(x);
+ if (zsetfil(zz,3) < 0) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ return(success = 1);
+ }
+ case XYF_SSPA: { /* STRINGSPACE */
+ int zz;
+ y = cmnum("Number of characters for filename list",
+ "",10,&x,xxstring);
+ if ((x = setnum(&zz,x,y,-1)) < 0)
+ return(x);
+ if (zsetfil(zz,1) < 0) {
+ printf("?Memory allocation failure\n");
+ return(-9);
+ }
+ return(success = 1);
+ }
+
+#endif /* DYNAMIC */
+#endif /* UNIX */
+
+ default:
+ printf("?unexpected file parameter\n");
+ return(-2);
+ }
+}
+
+#ifndef NOLOCAL
+#ifdef OS2
+/* MS-DOS KERMIT compatibility modes */
+int
+setmsk() {
+ if ((y = cmkey(msktab,nmsk,"MS-DOS Kermit compatibility mode",
+ "keycodes",xxstring)) < 0) return(y);
+
+ switch ( y ) {
+#ifdef COMMENT
+ case MSK_COLOR:
+ return(seton(&mskcolors));
+#endif /* COMMENT */
+ case MSK_KEYS:
+ return(seton(&mskkeys));
+ default: /* Shouldn't get here. */
+ return(-2);
+ }
+}
+#endif /* OS2 */
+
+int
+settrmtyp() {
+#ifdef OS2
+#ifdef TNCODE
+ extern int ttnum; /* Last Telnet Terminal Type sent */
+ extern int ttnumend; /* Has end of list been found */
+#endif /* TNCODE */
+ if ((x = cmkey(ttyptab,nttyp,"","vt320",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0)
+ return(y);
+ settermtype(x,1);
+#ifdef TNCODE
+ /* So we send the correct terminal name to the host if it asks for it */
+ ttnum = -1; /* Last Telnet Terminal Type sent */
+ ttnumend = 0; /* end of list not found */
+#endif /* TNCODE */
+ return(success = 1);
+#else /* Not OS2 */
+ printf(
+"\n Sorry, this version of C-Kermit does not support the SET TERMINAL TYPE\n");
+ printf(
+" command. Type \"help set terminal\" for further information.\n");
+#endif /* OS2 */
+ return(success = 0);
+}
+
+#ifdef CKTIDLE
+static char iactbuf[132];
+
+char *
+getiact() {
+ switch (tt_idleact) {
+ case IDLE_RET: return("return");
+ case IDLE_EXIT: return("exit");
+ case IDLE_HANG: return("hangup");
+#ifdef TNCODE
+ case IDLE_TNOP: return("Telnet NOP");
+ case IDLE_TAYT: return("Telnet AYT");
+#endif /* TNCODE */
+
+ case IDLE_OUT: {
+ int c, k, n;
+ char * p, * q, * t;
+ k = ckstrncpy(iactbuf,"output ",132);
+ n = k;
+ q = &iactbuf[k];
+ p = tt_idlestr;
+ if (!p) p = "";
+ if (!*p) return("output (nothing)");
+ while ((c = *p++) && n < 131) {
+ c &= 0xff;
+ if (c == '\\') {
+ if (n > 130) break;
+ *q++ = '\\';
+ *q++ = '\\';
+ *q = NUL;
+ n += 2;
+ } else if ((c > 31 && c < 127) || c > 159) {
+ *q++ = c;
+ *q = NUL;
+ n++;
+ } else {
+ if (n > (131 - 6))
+ break;
+ sprintf(q,"\\{%d}",c);
+ k = strlen(q);
+ q += k;
+ n += k;
+ *q = NUL;
+ }
+ }
+ *q = NUL;
+#ifdef OS2
+ k = tt_cols[VTERM];
+#else
+ k = tt_cols;
+#endif /* OS2 */
+ if (n > k - 52) {
+ n = k - 52;
+ iactbuf[n-2] = '.';
+ iactbuf[n-1] = '.';
+ iactbuf[n] = NUL;
+ }
+ return(iactbuf);
+ }
+ default: return("unknown");
+ }
+}
+#endif /* CKTIDLE */
+
+#ifndef NOCSETS
+VOID
+setlclcharset(x) int x; {
+ int i;
+ tcsl = y; /* Local character set */
+#ifdef OS2
+ for (i = 0; i < 4; i++) {
+ G[i].init = TRUE;
+ x = G[i].designation;
+ G[i].c1 = (x != tcsl) && cs_is_std(x);
+ x = G[i].def_designation;
+ G[i].def_c1 = (x != tcsl) && cs_is_std(x);
+ }
+#endif /* OS2 */
+}
+
+VOID
+setremcharset(x, z) int x, z; {
+ int i;
+
+#ifdef KUI
+ KuiSetProperty( KUI_TERM_REMCHARSET, (long) x, (long) z ) ;
+#endif /* KUI */
+#ifdef UNICODE
+ if (x == TX_TRANSP)
+#else /* UNICODE */
+ if (x == FC_TRANSP)
+#endif /* UNICODE */
+ { /* TRANSPARENT? */
+#ifndef OS2
+ tcsr = tcsl; /* Make both sets the same */
+#else /* OS2 */
+#ifdef CKOUNI
+ tt_utf8 = 0; /* Turn off UTF8 flag */
+ tcsr = tcsl = dec_kbd = TX_TRANSP; /* No translation */
+ tcs_transp = 1;
+
+ if (!cs_is_nrc(tcsl)) {
+ G[0].def_designation = G[0].designation = TX_ASCII;
+ G[0].init = TRUE;
+ G[0].def_c1 = G[0].c1 = FALSE;
+ G[0].size = cs94;
+ G[0].national = FALSE;
+ }
+ for (i = cs_is_nrc(tcsl) ? 0 : 1; i < 4; i++) {
+ G[i].def_designation = G[i].designation = tcsl;
+ G[i].init = TRUE;
+ G[i].def_c1 = G[i].c1 = FALSE;
+ switch (cs_size(G[i].designation)) { /* 94, 96, or 128 */
+ case 128:
+ case 96:
+ G[i].size = G[i].def_size = cs96;
+ break;
+ case 94:
+ G[i].size = G[i].def_size = cs94;
+ break;
+ default:
+ G[i].size = G[i].def_size = csmb;
+ break;
+ }
+ G[i].national = cs_is_nrc(x);
+ }
+#else /* CKOUNI */
+ tcsr = tcsl; /* Make both sets the same */
+ for (i = 0; i < 4; i++) {
+ G[i].def_designation = G[i].designation = FC_TRANSP;
+ G[i].init = FALSE;
+ G[i].size = G[i].def_size = cs96;
+ G[i].c1 = G[i].def_c1 = FALSE;
+ G[i].rtoi = NULL;
+ G[i].itol = NULL;
+ G[i].ltoi = NULL;
+ G[i].itor = NULL;
+ G[i].national = FALSE;
+ }
+#endif /* CKOUNI */
+#endif /* OS2 */
+ return;
+ }
+#ifdef OS2
+#ifdef CKOUNI
+ else if (x == TX_UTF8) {
+ tcs_transp = 0;
+ tt_utf8 = 1; /* Turn it on if we are UTF8 */
+ return;
+ }
+#endif /* CKOUNI */
+ else {
+ tcs_transp = 0;
+ tcsr = x; /* Remote character set */
+#ifdef CKOUNI
+ tt_utf8 = 0; /* Turn off UTF8 flag */
+#endif /* CKOUNI */
+
+ if (z == TT_GR_ALL) {
+ int i;
+#ifdef UNICODE
+ dec_kbd = x;
+#endif /* UNICODE */
+ for (i = 0; i < 4; i++) {
+ G[i].init = TRUE;
+ if ( i == 0 && !cs_is_nrc(x) ) {
+ G[0].designation = G[0].def_designation = FC_USASCII;
+ G[0].size = G[0].def_size = cs94;
+ G[0].national = 1;
+ } else {
+ G[i].def_designation = G[i].designation = x;
+ switch (cs_size(x)) { /* 94, 96, or 128 */
+ case 128:
+ case 96:
+ G[i].size = G[i].def_size = cs96;
+ break;
+ case 94:
+ G[i].size = G[i].def_size = cs94;
+ break;
+ default:
+ G[i].size = G[i].def_size = csmb;
+ break;
+ }
+ G[i].national = cs_is_nrc(x);
+ }
+ G[i].c1 = G[i].def_c1 = x != tcsl && cs_is_std(x);
+ }
+#ifdef UNICODE
+ } else if (z == TT_GR_KBD) { /* Keyboard only */
+ dec_kbd = x;
+#endif /* UNICODE */
+ } else { /* Specific Gn */
+ G[z].def_designation = G[z].designation = x;
+ G[z].init = TRUE;
+ switch (cs_size(x)) { /* 94, 96, or 128 */
+ case 128:
+ case 96:
+ G[z].size = G[z].def_size = cs96;
+ break;
+ case 94:
+ G[z].size = G[z].def_size = cs94;
+ break;
+ default:
+ G[z].size = G[z].def_size = csmb;
+ break;
+ }
+ G[z].c1 = G[z].def_c1 = x != tcsl && cs_is_std(x);
+ G[z].national = cs_is_nrc(x);
+ }
+ }
+#else /* not OS2 */
+ tcsr = x; /* Remote character set */
+#endif /* OS2 */
+}
+#endif /* NOCSETS */
+
+VOID
+setcmask(x) int x; {
+ if (x == 7) {
+ cmask = 0177;
+ } else if (x == 8) {
+ cmask = 0377;
+ parity = 0;
+ }
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_CMASK,x,0);
+#endif /* KUI */
+}
+
+#ifdef CK_AUTODL
+VOID
+setautodl(x,y) int x,y; {
+ autodl = x;
+ adl_ask = y;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_AUTODOWNLOAD,x?(y?2:1):0,0);
+#endif /* KUI */
+}
+#endif /* CK_AUTODL */
+
+#ifdef OS2
+VOID
+seturlhl(int x) {
+ tt_url_hilite = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_URL_HIGHLIGHT,x,0);
+#endif /* KUI */
+}
+
+VOID
+setaprint(int x) {
+ extern int aprint;
+ aprint = x;
+#ifdef KUI
+ KuiSetProperty(KUI_TERM_PRINTERCOPY,x,0);
+#endif /* KUI */
+}
+#endif /* OS2 */
+
+int
+settrm() {
+ int i = 0;
+#ifdef OS2
+ extern int colorreset, user_erasemode;
+#endif /* OS2 */
+ if ((y = cmkey(trmtab,ntrm,"", "",xxstring)) < 0) return(y);
+#ifdef MAC
+ printf("\n?Sorry, not implemented yet. Please use the Settings menu.\n");
+ return(-9);
+#else
+#ifdef IKSD
+ if (inserver) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ switch (y) {
+ case XYTBYT: /* SET TERMINAL BYTESIZE */
+ if ((y = cmnum("bytesize for terminal connection","8",10,&x,
+ xxstring)) < 0)
+ return(y);
+ if (x != 7 && x != 8) {
+ printf("\n?The choices are 7 and 8\n");
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ setcmask(x);
+#ifdef OS2
+ if (IS97801(tt_type_mode))
+ SNI_bitmode(x);
+#endif /* OS2 */
+ return(success = 1);
+
+ case XYTSO: /* SET TERMINAL LOCKING-SHIFT */
+ return(seton(&sosi));
+
+ case XYTNL: /* SET TERMINAL NEWLINE-MODE */
+ return(seton(&tnlm));
+
+#ifdef OS2
+ case XYTCOL:
+ if ((x = cmkey(ttycoltab,ncolors,"","terminal",xxstring)) < 0)
+ return(x);
+ else if (x == TTCOLRES) {
+ if ((y = cmkey(ttcolmodetab,ncolmode,
+ "","default-color",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ colorreset = y;
+ return(success = 1);
+ } else if (x == TTCOLERA) {
+ if ((y = cmkey(ttcolmodetab,ncolmode,"",
+ "current-color",xxstring)) < 0)
+ return(y);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ user_erasemode = y;
+ return(success=1);
+ } else { /* No parse error */
+ int fg = 0, bg = 0;
+ fg = cmkey(ttyclrtab, nclrs,
+ (x == TTCOLBOR ?
+ "color for screen border" :
+ "foreground color and then background color"),
+ "lgray", xxstring);
+ if (fg < 0)
+ return(fg);
+ if (x != TTCOLBOR) {
+ if ((bg = cmkey(ttyclrtab,nclrs,
+ "background color","blue",xxstring)) < 0)
+ return(bg);
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch (x) {
+ case TTCOLNOR:
+ colornormal = fg | bg << 4;
+ fgi = fg & 0x08;
+ bgi = bg & 0x08;
+ break;
+ case TTCOLREV:
+ colorreverse = fg | bg << 4;
+ break;
+ case TTCOLITA:
+ coloritalic = fg | bg << 4;
+ break;
+ case TTCOLUND:
+ colorunderline = fg | bg << 4;
+ break;
+ case TTCOLGRP:
+ colorgraphic = fg | bg << 4;
+ break;
+ case TTCOLDEB:
+ colordebug = fg | bg << 4;
+ break;
+ case TTCOLSTA:
+ colorstatus = fg | bg << 4;
+ break;
+ case TTCOLHLP:
+ colorhelp = fg | bg << 4;
+ break;
+ case TTCOLBOR:
+ colorborder = fg;
+ break;
+ case TTCOLSEL:
+ colorselect = fg | bg << 4;
+ break;
+ default:
+ printf("%s - invalid\n",cmdbuf);
+ return(-9);
+ break;
+ }
+ scrninitialized[VTERM] = 0;
+ VscrnInit(VTERM);
+ }
+ return(success = 1);
+
+ case XYTCUR: { /* SET TERMINAL CURSOR */
+ extern int cursorena[];
+ extern int cursoron[] ; /* Cursor state on/off */
+ if ((x = cmkey(ttycurtab,ncursors,"","underline",xxstring)) < 0)
+ return(x);
+ if ((z = cmkey(curontab,ncuron,"","on",xxstring)) < 0)
+ return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_cursor = tt_cursor_usr = x;
+ if ( z == 2 ) {
+ cursorena[VTERM] = tt_cursorena_usr = 1;
+ tt_cursor_blink = 0;
+ } else {
+ cursorena[VTERM] = tt_cursorena_usr = z;/* turn cursor on/off */
+ tt_cursor_blink = 1;
+ }
+ cursoron[VTERM] = FALSE; /* Force newcursor to restore the cursor */
+ return(success = 1);
+ }
+#endif /* OS2 */
+
+ case XYTTYP: /* SET TERMINAL TYPE */
+ return(settrmtyp());
+
+#ifdef OS2
+ case XYTARR: /* SET TERMINAL ARROW-KEYS */
+ if ((x = cmkey(akmtab,2,"","",xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_arrow = x; /* TTK_NORM / TTK_APPL; see ckuusr.h */
+ return(success = 1);
+
+ case XYTKPD: /* SET TERMINAL KEYPAD-MODE */
+ if ((x = cmkey(kpmtab,2,"","",xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_keypad = x; /* TTK_NORM / TTK_APPL; see ckuusr.h */
+ return(success = 1);
+
+ case XYTUNX: { /* SET TERM UNIX-MODE (DG) */
+ extern int dgunix,dgunix_usr;
+ x = seton(&dgunix);
+ dgunix_usr = dgunix;
+ return(x);
+ }
+ case XYTKBMOD: { /* SET TERM KEYBOARD MODE */
+ extern int tt_kb_mode;
+ if ((x = cmkey(kbmodtab,
+ nkbmodtab,
+ "normal",
+ "special keyboard mode for terminal emulation",
+ xxstring)
+ ) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_kb_mode = x;
+ return(success = 1);
+ }
+
+ case XYTWRP: /* SET TERMINAL WRAP */
+ return(seton(&tt_wrap));
+
+ case XYSCRS:
+ if ((y = cmnum("CONNECT scrollback buffer size, lines","2000",10,&x,
+ xxstring)) < 0)
+ return(y);
+ /* The max number of lines is the RAM */
+ /* we can actually dedicate to a */
+ /* scrollback buffer given the maximum */
+ /* process memory space of 512MB */
+ if (x < 256 || x > 2000000L) {
+ printf("\n?The size must be between 256 and 2,000,000.\n");
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ tt_scrsize[VTERM] = x;
+ VscrnInit(VTERM);
+ return(success = 1);
+#endif /* OS2 */
+
+#ifndef NOCSETS
+ case XYTCS: { /* SET TERMINAL CHARACTER-SET */
+ int eol;
+ /* set terminal character-set <remote> <local> */
+ if ((x = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "remote terminal character-set","",xxstring)) < 0)
+ return(x);
+
+#ifdef UNICODE
+ if (x == TX_TRANSP
+#ifdef CKOUNI
+ || x == TX_UTF8
+#endif /* CKOUNI */
+ ) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+#ifdef OS2
+ if ( isunicode() && x == TX_TRANSP ) {
+ /* If we are in unicode display mode then transparent
+ * only affects the output direction. We need to know
+ * the actual remote character set in order to perform
+ * the tcsr -> ucs2 translation for display.
+ */
+ x = y = tcsl;
+ } else
+#endif /* OS2 */
+ y = x;
+ }
+#else /* UNICODE */
+ if (x == FC_TRANSP) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+ y = x;
+ }
+#endif /* UNICODE */
+
+ /* Not transparent or UTF8, so get local set to translate it into */
+ s = "";
+#ifdef OS2
+ y = os2getcp(); /* Default is current code page */
+ switch (y) {
+ case 437: s = "cp437"; break;
+ case 850: s = "cp850"; break;
+ case 852: s = "cp852"; break;
+ case 857: s = "cp857"; break;
+ case 858: s = "cp858"; break;
+ case 862: s = "cp862"; break;
+ case 866: s = "cp866"; break;
+ case 869: s = "cp869"; break;
+ case 1250: s = "cp1250"; break;
+ case 1251: s = "cp1251"; break;
+ case 1252: s = "cp1252"; break;
+ case 1253: s = "cp1253"; break;
+ case 1254: s = "cp1254"; break;
+ case 1255: s = "cp1255"; break;
+ case 1256: s = "cp1256"; break;
+ case 1257: s = "cp1257"; break;
+ case 1258: s = "cp1258"; break;
+ }
+#ifdef PCFONTS
+/*
+ If the user has loaded a font with SET TERMINAL FONT then we want
+ to change the default code page to the font that was loaded.
+*/
+ if (tt_font != TTF_ROM) {
+ for (y = 0; y < ntermfont; y++ ) {
+ if (term_font[y].kwval == tt_font) {
+ s = term_font[y].kwd;
+ break;
+ }
+ }
+ }
+#endif /* PCFONTS */
+#else /* Not K95... */
+ s = fcsinfo[fcharset].keyword;
+#endif /* OS2 */
+
+ if ((y = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "local character-set",s,xxstring)) < 0)
+ return(y);
+
+#ifdef UNICODE
+ if (y == TX_UTF8) {
+ printf("?UTF8 may not be used as a local character set.\r\n");
+ return(-9);
+ }
+#endif /* UNICODE */
+#ifdef OS2
+ if ((z = cmkey(graphsettab,ngraphset,
+ "DEC VT intermediate graphic set","all",xxstring)) < 0)
+ return(z);
+#endif /* OS2 */
+ if ((eol = cmcfm()) < 0)
+ return(eol); /* Confirm the command */
+
+ /* End of command parsing - actions begin */
+ setlclcharset(y);
+ setremcharset(x,z);
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+#ifndef NOCSETS
+ case XYTLCS: /* SET TERMINAL LOCAL-CHARACTER-SET */
+ /* set terminal character-set <local> */
+ s = getdcset(); /* Get display character-set name */
+ if ((y = cmkey(
+#ifdef CKOUNI
+ txrtab,ntxrtab,
+#else /* CKOUNI */
+ fcstab,nfilc,
+#endif /* CKOUNI */
+ "local character-set",s,xxstring)) < 0)
+ return(y);
+
+#ifdef UNICODE
+ if (y == TX_UTF8) {
+ printf("?UTF8 may not be used as a local character set.\r\n");
+ return(-9);
+ }
+#endif /* UNICODE */
+ if ((z = cmcfm()) < 0) return(z); /* Confirm the command */
+
+ /* End of command parsing - action begins */
+
+ setlclcharset(y);
+ return(success = 1);
+#endif /* NOCSETS */
+
+#ifndef NOCSETS
+#ifdef UNICODE
+ case XYTUNI: /* SET TERMINAL UNICODE */
+ return(seton(&tt_unicode));
+#endif /* UNICODE */
+
+ case XYTRCS: /* SET TERMINAL REMOTE-CHARACTER-SET */
+ /* set terminal character-set <remote> <Graphic-set> */
+ if ((x = cmkey(
+#ifdef CKOUNI
+ txrtab, ntxrtab,
+#else /* CKOUNI */
+ ttcstab,ntermc,
+#endif /* CKOUNI */
+ "remote terminal character-set","",xxstring)) < 0)
+ return(x);
+
+#ifdef UNICODE
+ if (x == TX_TRANSP
+#ifdef CKOUNI
+ || x == TX_UTF8
+#endif /* CKOUNI */
+ ) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+#ifdef OS2
+ if ( isunicode() && x == TX_TRANSP ) {
+ /* If we are in unicode display mode then transparent
+ * only affects the output direction. We need to know
+ * the actual remote character set in order to perform
+ * the tcsr -> ucs2 translation for display.
+ */
+ x = tcsl;
+ }
+#endif /* OS2 */
+ }
+#else /* UNICODE */
+ if (x == FC_TRANSP) {
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+ }
+#endif /* UNICODE */
+ else {
+#ifdef OS2
+ if ((z = cmkey(graphsettab,ngraphset,
+ "DEC VT intermediate graphic set","all",xxstring)) < 0)
+ return(z);
+#endif /* OS2 */
+ if ((y = cmcfm()) < 0) /* Confirm the command */
+ return(y);
+ }
+ /* Command parsing ends here */
+
+ setremcharset(x,z);
+ return(success = 1);
+#endif /* NOCSETS */
+
+ case XYTEC: /* SET TERMINAL ECHO */
+ if ((x = cmkey(rltab,nrlt,"which side echos during CONNECT",
+ "remote", xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef NETCONN
+ oldplex = x;
+#endif /* NETCONN */
+ duplex = x;
+ return(success = 1);
+
+ case XYTESC: /* SET TERM ESC */
+ if ((x = cmkey(nabltab,nnabltab,"","enabled",xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_escape = x;
+ return(1);
+
+ case XYTCRD: /* SET TERMINAL CR-DISPLAY */
+ if ((x = cmkey(crdtab,2,"", "normal", xxstring)) < 0) return(x);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_crd = x;
+ return(success = 1);
+
+#ifdef OS2
+ case XYTANS: { /* SET TERMINAL ANSWERBACK */
+/*
+ NOTE: We let them enable and disable the answerback sequence, but we
+ do NOT let them change it, and we definitely do not let the host set it.
+ This is a security feature.
+
+ As of 1.1.8 we allow the SET TERM ANSWERBACK MESSAGE <string> to be
+ used just as MS-DOS Kermit does. C0 and C1 controls as well as DEL
+ are not allowed to be used as characters. They are translated to
+ underscore. This may not be set by APC.
+*/
+ if ((x = cmkey(anbktab,nansbk,"", "off", xxstring)) < 0)
+ return(x);
+ if (x < 2) {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tt_answer = x;
+ return(success = 1);
+ } else if ( x == 2 || x == 3) {
+ int len = 0;
+ extern int safeanswerbk;
+ extern char useranswerbk[];
+ if ((y = cmtxt("Answerback extension","",&s,xxstring)) < 0)
+ return(y);
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+ len = strlen(s);
+ if (x == 2) {
+ /* Safe Answerback's don't have C0/C1 chars */
+ for (z = 0; z < len; z++) {
+ if ((s[z] & 0x7F) <= SP || (s[z] & 0x7F) == DEL)
+ useranswerbk[z] = '_';
+ else
+ useranswerbk[z] = s[z];
+ }
+ useranswerbk[z] = '\0';
+ safeanswerbk = 1 ; /* TRUE */
+ } else {
+ ckstrncpy(useranswerbk,s,60); /* (see ckocon.c) */
+ safeanswerbk = 0; /* FALSE */
+ }
+ updanswerbk();
+ return(success = 1);
+ } else
+ return(success = 0);
+ }
+#endif /* OS2 */
+
+#ifdef CK_APC
+ case XYTAPC:
+ if ((y = cmkey(apctab,napctab,
+ "application program command execution","",
+ xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (apcactive == APC_LOCAL ||
+ (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
+ return(success = 0);
+ apcstatus = y;
+ return(success = 1);
+
+#ifdef CK_AUTODL
+ case XYTAUTODL: /* AUTODOWNLOAD */
+ if ((y = cmkey(adltab,nadltab,"Auto-download options","",
+ xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TAD_ON:
+ case TAD_OFF:
+ if ((x = cmcfm()) < 0)
+ return(x);
+ setautodl(y,0);
+ break;
+ case TAD_ASK:
+ if ((x = cmcfm()) < 0)
+ return(x);
+ setautodl(TAD_ON,1);
+ break;
+ case TAD_ERR:
+ if ((y = cmkey(adlerrtab,nadlerrtab,"","", xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_err = y;
+ break;
+#ifdef OS2
+ case TAD_K:
+ if ((y = cmkey(adlxtab,nadlxtab,"","", xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TAD_X_C0:
+ if ((y = cmkey(adlc0tab,nadlc0tab,"",
+ "processed-by-emulator",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_kc0 = y;
+ break;
+ case TAD_X_DETECT:
+ if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_kmode = y;
+ break;
+ case TAD_X_STR:
+ if ((y = cmtxt("Kermit start string","KERMIT READY TO SEND...",
+ &s,xxstring)) < 0)
+ return(y);
+ free(adl_kstr);
+ adl_kstr = strdup(s);
+ break;
+ }
+ break;
+
+ case TAD_Z:
+ if ((y = cmkey(adlxtab,nadlxtab,"","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TAD_X_C0:
+ if ((y = cmkey(adlc0tab,nadlc0tab,"",
+ "processed-by-emulator",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_zc0 = y;
+ break;
+ case TAD_X_DETECT:
+ if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ adl_zmode = y;
+ break;
+ case TAD_X_STR:
+ if ((y = cmtxt("","rz\\{13}",&s,xxstring)) < 0)
+ return(y);
+ free(adl_zstr);
+ adl_zstr = strdup(s);
+ break;
+ }
+ break;
+#endif /* OS2 */
+ }
+ return(success = 1);
+
+#endif /* CK_AUTODL */
+#endif /* CK_APC */
+
+#ifdef OS2
+ case XYTBEL:
+ return(success = setbell());
+
+ case XYTMBEL: /* MARGIN-BELL */
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if (y) { /* ON */
+ if ((z = cmnum("Column at which to set margin bell",
+ "72",10,&x,xxstring)) < 0)
+ return(z);
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ marginbell = y;
+ marginbellcol = x;
+ return(success = 1);
+#endif /* OS2 */
+
+#ifdef CKTIDLE
+ case XYTIDLE: /* IDLE-SEND */
+ case XYTITMO: /* IDLE-TIMEOUT */
+ if ((z = cmnum("seconds of idle time to wait, or 0 to disable",
+ "0",10,&x,xxstring)) < 0)
+ return(z);
+ if (y == XYTIDLE) {
+ if ((y = cmtxt("string to send, may contain kverbs and variables",
+ "\\v(newline)",&s,xxstring)) < 0)
+ return(y);
+ tt_idlesnd_tmo = x; /* (old) */
+ tt_idlelimit = x; /* (new) */
+ makestr(&tt_idlestr,brstrip(s)); /* (new) */
+ tt_idlesnd_str = tt_idlestr; /* (old) */
+ tt_idleact = IDLE_OUT; /* (new) */
+ } else {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ tt_idlelimit = x;
+ }
+#ifdef OS2
+ puterror(VTERM);
+#endif /* OS2 */
+ return(success = 1);
+
+ case XYTIACT: { /* SET TERM IDLE-ACTION */
+ if ((y = cmkey(idlacts,nidlacts,"","",xxstring)) < 0)
+ return(y);
+ if (y == IDLE_OUT) {
+ if ((x = cmtxt("string to send, may contain kverbs and variables"
+ , "\\v(newline)",&s,xxstring)) < 0)
+ return(x);
+ makestr(&tt_idlestr,brstrip(s)); /* (new) */
+ tt_idlesnd_str = tt_idlestr; /* (old) */
+ } else {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ }
+ tt_idleact = y;
+ return(success = 1);
+ }
+#endif /* CKTIDLE */
+
+ case XYTDEB: /* TERMINAL DEBUG */
+ y = seton(&x); /* Go parse ON or OFF */
+ if (y > 0) /* Command succeeded? */
+ setdebses(x);
+ return(y);
+
+#ifdef OS2
+ case XYTASCRL: /* SET TERMINAL AUTOSCROLL */
+ y = seton(&autoscroll);
+ return(y);
+
+ case XYTAPAGE: /* SET TERMINAL AUTOPAGE */
+ y = seton(&wy_autopage);
+ return(y);
+
+ case XYTROL: /* SET TERMINAL ROLL */
+ if ((y = cmkey(rolltab,nroll,"scrollback mode","insert",xxstring))<0)
+ return(y);
+ if (y == TTR_KEYS) {
+ if ((x = cmkey(rollkeytab,nrollkey,"","send",xxstring))<0)
+ return(x);
+ if ((z = cmcfm()) < 0) return(z);
+ tt_rkeys[VTERM] = x;
+ } else {
+ if ((x = cmcfm()) < 0) return(x);
+ tt_roll[VTERM] = y;
+ }
+ return(success = 1);
+
+ case XYTCTS: /* SET TERMINAL TRANSMIT-TIMEOUT */
+ y = cmnum("Maximum seconds to allow CTS off during CONNECT",
+ "5",10,&x,xxstring);
+ return(setnum(&tt_ctstmo,x,y,10000));
+
+ case XYTCPG: { /* SET TERMINAL CODE-PAGE */
+ int i;
+ int cp = -1;
+ y = cmnum("PC code page to use during terminal emulation",
+ ckitoa(os2getcp()),10,&x,xxstring);
+ if ((x = setnum(&cp,x,y,11000)) < 0) return(x);
+ if (os2setcp(cp) != 1) {
+#ifdef NT
+ if (isWin95())
+ printf(
+ "Sorry, Windows 95 does not support code page switching\n");
+ else
+#endif /* NT */
+ printf(
+ "Sorry, %d is not a valid code page for this system.\n",cp);
+ return(-9);
+ }
+ /* Force the terminal character-sets conversions to be updated */
+ for ( i = 0; i < 4; i++ )
+ G[i].init = TRUE;
+ return(1);
+ }
+
+ case XYTPAC: /* SET TERMINAL OUTPUT-PACING */
+ y = cmnum(
+ "Pause between sending each character during CONNECT, milliseconds",
+ "-1",10,&x,xxstring);
+ return(setnum(&tt_pacing,x,y,10000));
+
+#ifdef OS2MOUSE
+ case XYTMOU: { /* SET TERMINAL MOUSE */
+ int old_mou = tt_mouse;
+ if ((x = seton(&tt_mouse)) < 0)
+ return(x);
+ if (tt_mouse != old_mou)
+ if (tt_mouse)
+ os2_mouseon();
+ else
+ os2_mouseoff();
+ return(1);
+ }
+#endif /* OS2MOUSE */
+#endif /* OS2 */
+
+ case XYTWID: {
+ if ((y = cmnum(
+#ifdef OS2
+ "number of columns in display window during CONNECT",
+#else
+ "number of columns on your screen",
+#endif /* OS2 */
+ "80",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+#ifdef OS2
+ return(success = os2_settermwidth(x));
+#else /* Not OS/2 */
+ tt_cols = x;
+ return(success = 1);
+#endif /* OS2 */
+ }
+
+ case XYTHIG:
+ if ((y = cmnum(
+#ifdef OS2
+ "number of rows in display window during CONNECT, not including status line",
+ tt_status[VTERM]?"24":"25",
+#else
+ "24","number of rows on your screen",
+#endif /* OS2 */
+ 10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+
+#ifdef OS2
+ return (success = os2_settermheight(x));
+#else /* Not OS/2 */
+ tt_rows = x;
+ return(success = 1);
+#endif /* OS2 */
+
+#ifdef OS2
+ case XYTPRN: { /* Print Mode */
+ extern bool xprint, aprint, cprint, uprint;
+ if ((y = cmkey(prnmtab,nprnmtab,"","off", xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ switch (y) {
+ case 0:
+ if (cprint || uprint || aprint || xprint)
+ printeroff();
+ cprint = xprint = uprint = 0;
+ setaprint(0);
+ break;
+ case 1:
+ if (!(cprint || uprint || aprint || xprint))
+ printeron();
+ setaprint(1);
+ cprint = xprint = uprint = 0;
+ break;
+ case 2:
+ if (!(cprint || uprint || aprint || xprint))
+ printeron();
+ cprint = 1;
+ setaprint(0);
+ xprint = uprint = 0;
+ break;
+ case 3:
+ if (!(cprint || uprint || aprint || xprint))
+ printeron();
+ uprint = 1;
+ setaprint(0);
+ xprint = cprint = 0;
+ break;
+ }
+ return(1);
+ }
+#else
+#ifdef XPRINT
+ case XYTPRN: {
+ extern int tt_print;
+ if ((x = seton(&tt_print)) < 0)
+ return(x);
+ return(success = 1);
+ }
+#endif /* XPRINT */
+#endif /* OS2 */
+
+#ifdef OS2
+ case XYTSCNM: {
+ extern int decscnm, decscnm_usr;
+ if ((y = cmkey(normrev,4,"",
+ decscnm_usr?"reverse":"normal",
+ xxstring)
+ ) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ decscnm_usr = y;
+ if (decscnm != decscnm_usr)
+ flipscreen(VTERM);
+ return(1);
+ }
+ case XYTOPTI:
+ if ((y = cmkey(onoff,2,"",tt_diff_upd?"on":"off",
+ xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ tt_diff_upd = y;
+ return(1);
+ case XYTUPD: {
+ int mode, delay;
+ if ((mode = cmkey(scrnupd,nscrnupd,"","fast",xxstring)) < 0) {
+ return(mode);
+ } else {
+ y = cmnum(
+ "Pause between FAST screen updates in CONNECT mode, milliseconds",
+ "100",10,&x,xxstring
+ );
+ if (x < 0 || x > 1000 ) {
+ printf(
+ "\n?The update rate must be between 0 and 1000 milliseconds.\n"
+ );
+ return(success = 0);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+
+ updmode = tt_updmode = mode;
+ return(setnum(&tt_update,x,y,10000));
+ }
+ }
+ case XYTCTRL:
+ if ((x = cmkey(termctrl,ntermctrl,"","7",xxstring)) < 0) {
+ return(x);
+ } else {
+ if ((y = cmcfm()) < 0)
+ return(y);
+ switch ( x ) {
+ case 8:
+ send_c1 = send_c1_usr = TRUE;
+ break;
+ case 7:
+ default:
+ send_c1 = send_c1_usr = FALSE;
+ break;
+ }
+ }
+ return(success = TRUE);
+ break;
+
+#ifdef PCFONTS
+ case XYTFON:
+ if ( !IsOS2FullScreen() ) {
+ printf(
+ "\n?SET TERMINAL FONT is only supported in Full Screen sessions.\n");
+ return(success = FALSE);
+ }
+
+ if ((x = cmkey(term_font,ntermfont,"","default",xxstring)) < 0) {
+ return(x);
+ } else {
+ if ((y = cmcfm()) < 0) return(y);
+ if ( !os2LoadPCFonts() ) {
+ tt_font = x;
+ return(success = TRUE);
+ } else {
+ printf(
+ "\n?PCFONTS.DLL is not available in CKERMIT executable directory.\n");
+ return(success = FALSE);
+ }
+ }
+ break;
+#else /* PCFONTS */
+#ifdef NT
+#ifdef KUI
+ case XYTFON:
+ return(setguifont()); /* ckuus3.c */
+#endif /* KUI */
+#endif /* NT */
+#endif /* PCFONTS */
+
+ case XYTVCH: {
+ extern int pheight, marginbot, cmd_rows, cmd_cols;
+ if ((x = cmkey(tvctab,ntvctab,"",isWin95()?"win95-safe":"enabled",
+ xxstring)) < 0)
+ return(x);
+ if ((y = cmcfm()) < 0) return(y);
+#ifndef KUI
+ if (x != tt_modechg) {
+ switch (x) {
+ case TVC_DIS:
+ /* When disabled the heights of all of the virtual screens */
+ /* must be equal to the physical height of the console */
+ /* window and may not be changed. */
+ /* The width of the window may not be altered. */
+ tt_modechg = TVC_ENA; /* Temporary */
+ if (marginbot > pheight-(tt_status[VTERM]?1:0))
+ marginbot = pheight-(tt_status[VTERM]?1:0);
+ tt_szchng[VCMD] = 1 ;
+ tt_rows[VCMD] = pheight;
+ VscrnInit(VCMD);
+ SetCols(VCMD);
+ cmd_rows = y;
+
+ tt_szchng[VTERM] = 2 ;
+ tt_rows[VTERM] = pheight - (tt_status[VTERM]?1:0);
+ VscrnInit(VTERM);
+
+ break;
+
+ case TVC_ENA:
+ /* When enabled the physical height of the console windows */
+ /* should be adjusted to the height of the virtual screen */
+ /* The width may be set to anything. */
+ /* nothing to do */
+ break;
+
+ case TVC_W95:
+ /* Win95-safe mode allows the physical height to change */
+ /* but restricts it to a width of 80 and a height equal to */
+ /* 25, 43, or 50. Must be adjusted now. */
+ /* The virtual heights must be equal to the above. */
+ if (pheight != 25 && pheight != 43 && pheight != 50) {
+ if (pheight < 25)
+ y = 25;
+ else if (pheight < 43)
+ y = 43;
+ else
+ y = 50;
+ } else
+ y = pheight;
+
+ tt_modechg = TVC_ENA; /* Temporary */
+
+ tt_szchng[VCMD] = 1;
+ tt_rows[VCMD] = y;
+ tt_cols[VCMD] = 80;
+ VscrnInit(VCMD);
+ SetCols(VCMD);
+ cmd_rows = y;
+ cmd_cols = 80;
+
+ marginbot = y-(tt_status[VTERM]?1:0);
+ tt_szchng[VTERM] = 2;
+ tt_rows[VTERM] = y - (tt_status[VTERM]?1:0);
+ tt_cols[VTERM] = 80;
+ VscrnInit(VTERM);
+ break;
+ }
+ tt_modechg = x;
+ }
+ return(success = 1);
+#else
+ return(success = 0);
+#endif /* KUI */
+ }
+ case XYTSTAT: {
+ extern int marginbot;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (y != tt_status[VTERM] || y != tt_status_usr[VTERM]) {
+ /* Might need to fixup the margins */
+ if ( marginbot == VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) )
+ if (y) {
+ marginbot--;
+ } else {
+ marginbot++;
+ }
+ tt_status_usr[VTERM] = tt_status[VTERM] = y;
+ if (y) {
+ tt_szchng[VTERM] = 2;
+ tt_rows[VTERM]--;
+ VscrnInit(VTERM); /* Height set here */
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ tn_snaws();
+#endif /* TNCODE */
+#ifdef RLOGCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ rlog_naws();
+#endif /* RLOGCODE */
+#ifdef SSHBUILTIN
+ if (TELOPT_ME(TELOPT_NAWS))
+ ssh_snaws();
+#endif /* SSHBUILTIN */
+ } else {
+ tt_szchng[VTERM] = 1;
+ tt_rows[VTERM]++;
+ VscrnInit(VTERM); /* Height set here */
+#ifdef TNCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ tn_snaws();
+#endif /* TNCODE */
+#ifdef RLOGCODE
+ if (TELOPT_ME(TELOPT_NAWS))
+ rlog_naws();
+#endif /* RLOGCODE */
+#ifdef SSHBUILTIN
+ if (TELOPT_ME(TELOPT_NAWS))
+ ssh_snaws();
+#endif /* SSHBUILTIN */
+ }
+ }
+ return(1);
+ }
+#endif /* OS2 */
+
+#ifdef NT
+ case XYTATTBUG:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ tt_attr_bug = y;
+ return(1);
+#endif /* NT */
+
+#ifdef OS2
+ case XYTSGRC:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sgrcolors = y;
+ return(1);
+
+ case XYTSEND:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ tt_senddata = y;
+ return(1);
+
+ case XYTSEOB:
+ if ((y = cmkey(ttyseobtab,2,"","us_cr",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ wy_blockend = y;
+ return(1);
+
+ case XYTURLHI: {
+ int done = 0, attr = VT_CHAR_ATTR_NORMAL;
+
+ if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(x);
+ if (x) {
+ z = 0;
+ while (!done) {
+ if ((y = cmkey(ttyprotab,nprotect,"",
+ z?"done":"reverse",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TTATTDONE:
+ done = TRUE;
+ break;
+ case TTATTBLI:
+ attr |= VT_CHAR_ATTR_BLINK;
+ break;
+ case TTATTREV:
+ attr |= VT_CHAR_ATTR_REVERSE;
+ break;
+ case TTATTITA:
+ attr |= VT_CHAR_ATTR_ITALIC;
+ break;
+ case TTATTUND:
+ attr |= VT_CHAR_ATTR_UNDERLINE;
+ break;
+ case TTATTBLD:
+ attr |= VT_CHAR_ATTR_BOLD;
+ break;
+ case TTATTDIM:
+ attr |= VT_CHAR_ATTR_DIM;
+ break;
+ case TTATTINV:
+ attr |= VT_CHAR_ATTR_INVISIBLE;
+ break;
+ case TTATTNOR:
+ break;
+ }
+ z = 1; /* One attribute has been chosen */
+ }
+ }
+ if ((z = cmcfm()) < 0) return(z);
+ seturlhl(x);
+ if (x)
+ tt_url_hilite_attr = attr;
+ return(1);
+ }
+ case XYTATTR:
+ if ((x = cmkey(ttyattrtab,nattrib,"","underline",xxstring)) < 0)
+ return(x);
+ switch (x) {
+ case TTATTBLI:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ trueblink = y;
+#ifndef KUI
+ if ( !trueblink && trueunderline ) {
+ trueunderline = 0;
+ printf("Warning: Underline being simulated by color.\n");
+ }
+
+#endif /* KUI */
+ break;
+
+ case TTATTDIM:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ truedim = y;
+ break;
+
+ case TTATTREV:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ truereverse = y;
+ break;
+
+ case TTATTUND:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ trueunderline = y;
+#ifndef KUI
+ if (!trueblink && trueunderline) {
+ trueblink = 1;
+ printf("Warning: True blink mode is active.\n");
+ }
+#endif /* KUI */
+ break;
+
+ case TTATTITA:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ trueitalic = y;
+ break;
+
+ case TTATTPRO: { /* Set default Protected Character attribute */
+ extern vtattrib WPattrib; /* current WP Mode Attrib */
+ extern vtattrib defWPattrib; /* default WP Mode Attrib */
+ vtattrib wpa = {0,0,0,0,0,1,0,0,0,0,0}; /* Protected */
+ int done = 0;
+
+ x = 0;
+ while (!done) {
+ if ((y = cmkey(ttyprotab,nprotect,"",
+ x?"done":"dim",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case TTATTNOR:
+ break;
+ case TTATTBLI: /* Blinking doesn't work */
+ wpa.blinking = TRUE;
+ break;
+ case TTATTREV:
+ wpa.reversed = TRUE;
+ break;
+ case TTATTITA:
+ wpa.italic = TRUE;
+ break;
+ case TTATTUND:
+ wpa.underlined = TRUE;
+ break;
+ case TTATTBLD:
+ wpa.bold = TRUE;
+ break;
+ case TTATTDIM:
+ wpa.dim = TRUE;
+ break;
+ case TTATTINV:
+ wpa.invisible = TRUE ;
+ break;
+ case TTATTDONE:
+ done = TRUE;
+ break;
+ }
+ x = 1; /* One attribute has been chosen */
+ }
+ if ((x = cmcfm()) < 0) return(x);
+ WPattrib = defWPattrib = wpa;
+ break;
+ }
+ }
+ return(1);
+
+ case XYTKEY: { /* SET TERMINAL KEY */
+ int t, x, y;
+ int clear = 0, deflt = 0;
+ int confirmed = 0;
+ int flag = 0;
+ int kc = -1; /* Key code */
+ int litstr = 0; /* Literal String? */
+ char *s = NULL; /* Key binding */
+#ifndef NOKVERBS
+ char *p = NULL; /* Worker */
+#endif /* NOKVERBS */
+ con_event defevt;
+ extern int os2gks;
+ extern int mskkeys;
+ extern int initvik;
+ struct FDB kw,sw,nu,cm;
+
+ defevt.type = error;
+
+ if ((t = cmkey(ttkeytab,nttkey,"","",xxstring)) < 0)
+ return(t);
+ cmfdbi(&nu, /* First FDB - command switches */
+ _CMNUM, /* fcode */
+ "/literal, keycode, or action",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ &sw /* Pointer to next FDB */
+ ); /* */
+ cmfdbi(&sw, /* Second FDB - switches */
+ _CMKEY, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ nstrmswitab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ strmswitab, /* Keyword table */
+ &kw /* Pointer to next FDB */
+ );
+ cmfdbi(&kw, /* Third FDB - command switches */
+ _CMKEY, /* fcode */
+ "/literal, keycode, or action",
+ "", /* default */
+ "", /* addtl string data */
+ nstrmkeytab, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2 */
+ xxstring, /* Processing function */
+ strmkeytab, /* Keyword table */
+ &cm /* Pointer to next FDB */
+ );
+ cmfdbi(&cm, /* Final FDB - Confirmation */
+ _CMCFM, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ while (kc < 0) {
+ x = cmfdb(&nu); /* Parse something */
+ if (x < 0)
+ return(x);
+
+ switch (cmresult.fcode) {
+ case _CMCFM:
+ printf(" Press key to be defined: ");
+ conbin((char)escape); /* Put terminal in binary mode */
+ os2gks = 0; /* Turn off Kverb preprocessing */
+ kc = congks(0); /* Get character or scan code */
+ os2gks = 1; /* Turn on Kverb preprocessing */
+ concb((char)escape); /* Restore terminal to cbreak mode */
+ if (kc < 0) { /* Check for error */
+ printf("?Error reading key\n");
+ return(0);
+ }
+ shokeycode(kc,t); /* Show current definition */
+ flag = 1; /* Remember it's a multiline command */
+ break;
+ case _CMNUM:
+ kc = cmresult.nresult;
+ break;
+ case _CMKEY:
+ if (cmresult.fdbaddr == &sw) { /* Switch */
+ if (cmresult.nresult == 0)
+ litstr = 1;
+ } else if (cmresult.fdbaddr == &kw) { /* Keyword */
+ if (cmresult.nresult == 0)
+ clear = 1;
+ else
+ deflt = 1;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (clear)
+ clearkeymap(t);
+ else if (deflt)
+ defaultkeymap(t);
+ initvik = 1;
+ return(1);
+ }
+ }
+ }
+
+ /* Normal SET TERMINAL KEY <terminal> <scancode> <value> command... */
+
+ if (mskkeys)
+ kc = msktock(kc);
+
+ if (kc < 0 || kc >= KMSIZE) {
+ printf("?key code must be between 0 and %d\n", KMSIZE - 1);
+ return(-9);
+ }
+ if (kc == escape) {
+ printf("Sorry, %d is the CONNECT-mode escape character\n",kc);
+ return(-9);
+ }
+ wideresult = -1;
+ if (flag) {
+ cmsavp(psave,PROMPTL);
+ cmsetp(" Enter new definition: ");
+ cmini(ckxech);
+ }
+ def_again:
+ if (flag) prompt(NULL);
+ if ((y = cmtxt("key definition,\n\
+ or Ctrl-C to cancel this command,\n\
+ or Enter to restore default definition",
+ "",&s,NULL)) < 0) {
+ if (flag) /* Handle parse errors */
+ goto def_again;
+ else
+ return(y);
+ }
+ s = brstrip(s);
+#ifndef NOKVERBS
+ p = s; /* Save this place */
+#endif /* NOKVERBS */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else.
+
+ We use this code active for all versions that support SET KEY, even if they
+ don't support \Kverbs, because otherwise \K would behave differently for
+ different versions.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Get remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ if (flag) cmsetp(psave);
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#endif /* NOKVERBS */
+
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Clear individual key def */
+ deletekeymap(t,kc);
+ break;
+ case 1:
+ if (!litstr) {
+ defevt.type = key; /* Single character */
+ defevt.key.scancode = *s;
+ break;
+ }
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ /* Need exact match */
+ debug(F101,"set key kverb lookup",0,y);
+ if (y > -1) {
+ defevt.type = kverb;
+ defevt.kverb.id = y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+ if (litstr) {
+ defevt.type = literal;
+ defevt.literal.string = (char *) malloc(strlen(s)+1);
+ if (defevt.literal.string)
+ strcpy(defevt.literal.string, s); /* safe */
+ } else {
+ defevt.type = macro;
+ defevt.macro.string = (char *) malloc(strlen(s)+1);
+ if (defevt.macro.string)
+ strcpy(defevt.macro.string, s); /* safe */
+ }
+ break;
+ }
+ insertkeymap(t, kc, defevt);
+ if (flag)
+ cmsetp(psave);
+ initvik = 1; /* Update VIK table */
+ return(1);
+ }
+
+#ifdef PCTERM
+ case XYTPCTERM: /* PCTERM Keyboard Mode */
+ if ((x = seton(&tt_pcterm)) < 0) return(x);
+ return(success = 1);
+#endif /* PCTERM */
+#endif /* OS2 */
+
+#ifdef CK_TRIGGER
+ case XYTRIGGER:
+ if ((y = cmtxt("String to trigger automatic return to command mode",
+ "",&s,xxstring)) < 0)
+ return(y);
+ makelist(s,tt_trigger,TRIGGERS);
+ return(1);
+#endif /* CK_TRIGGER */
+
+#ifdef OS2
+ case XYTSAC:
+ if ((y = cmnum("ASCII value to use for spacing attributes",
+ "32",10,&x,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+ tt_sac = x;
+ return(success = 1);
+
+ case XYTKBDGL: { /* SET TERM KBD-FOLLOWS-GL/GR */
+ extern int tt_kb_glgr; /* from ckoco3.c */
+ if ((x = seton(&tt_kb_glgr)) < 0)
+ return(x);
+ return(success = 1);
+ }
+#ifndef NOCSETS
+ case XYTVTLNG: /* SET TERM DEC-LANGUAGE */
+ if ((y = cmkey(vtlangtab,nvtlangtab,"VT language",
+ IS97801(tt_type_mode)?"german":"north-american",
+ xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+
+ /* A real VT terminal would use the language to set the */
+ /* default keyboard language for both 8-bit multinational */
+ /* and 7-bit national modes. For 8-bit mode it would */
+ /* set the terminal character-set to the ISO set if it */
+ /* is not already set. */
+ /* Latin-1 can be replaced by DEC Multinational */
+ switch (y) {
+ case VTL_NORTH_AM: /* North American */
+ /* Multinational: Latin-1 */
+ /* National: US_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_ASCII;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_BRITISH :
+ /* Multinational: Latin-1 */
+ /* National: UK_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_BRITISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_FRENCH :
+ case VTL_BELGIAN :
+ case VTL_CANADIAN:
+ /* Multinational: Latin-1 */
+ /* National: FR_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_FRENCH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_FR_CAN :
+ /* Multinational: Latin-1 */
+ /* National: FC_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_CN_FRENCH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_DANISH :
+ case VTL_NORWEGIA:
+ /* Multinational: Latin-1 */
+ /* National: NO_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_NORWEGIAN;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_FINNISH :
+ /* Multinational: Latin-1 */
+ /* National: FI_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_FINNISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_GERMAN :
+ /* Multinational: Latin-1 */
+ /* National: GR_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_GERMAN;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_DUTCH :
+ /* Multinational: Latin-1 */
+ /* National: DU_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_DUTCH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_ITALIAN :
+ /* Multinational: Latin-1 */
+ /* National: IT_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_ITALIAN;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_SW_FR :
+ case VTL_SW_GR :
+ /* Multinational: Latin-1 */
+ /* National: CH_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_SWISS;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_SWEDISH :
+ /* Multinational: Latin-1 */
+ /* National: SW_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_SWEDISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_SPANISH :
+ /* Multinational: Latin-1 */
+ /* National: SP_ASCII */
+ dec_lang = y;
+ dec_nrc = TX_SPANISH;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_PORTUGES:
+ /* Multinational: Latin-1 */
+ /* National: Portugese ASCII */
+ dec_lang = y;
+ dec_nrc = TX_PORTUGUESE;
+ dec_kbd = TX_8859_1;
+ break;
+ case VTL_HEBREW :
+ /* Multinational: Latin-Hebrew / DEC-Hebrew */
+ /* National: DEC 7-bit Hebrew */
+ dec_lang = y;
+ dec_nrc = TX_HE7;
+ dec_kbd = TX_8859_8;
+ break;
+ case VTL_GREEK :
+ /* Multinational: Latin-Greek / DEC-Greek */
+ /* National: DEC Greek NRC */
+ /* is ELOT927 equivalent to DEC Greek???? */
+ dec_lang = y;
+ dec_nrc = TX_ELOT927;
+ dec_kbd = TX_8859_7;
+ break;
+#ifdef COMMENT
+ case VTL_TURK_Q :
+ case VTL_TURK_F :
+ /* Multinational: Latin-Turkish / DEC-Turkish */
+ /* National: DEC 7-bit Turkish */
+ break;
+#endif /* COMMENT */
+ case VTL_HUNGARIA:
+ /* Multinational: Latin-2 */
+ /* National: no national mode */
+ dec_lang = y;
+ dec_nrc = TX_HUNGARIAN;
+ dec_kbd = TX_8859_2;
+ break;
+ case VTL_SLOVAK :
+ case VTL_CZECH :
+ case VTL_POLISH :
+ case VTL_ROMANIAN:
+ /* Multinational: Latin-2 */
+ /* National: no national mode */
+ dec_lang = y;
+ dec_nrc = TX_ASCII;
+ dec_kbd = TX_8859_2;
+ break;
+ case VTL_RUSSIAN :
+ /* Multinational: Latin-Cyrillic / KOI-8 */
+ /* National: DEC Russian NRC */
+ dec_lang = y;
+ dec_nrc = TX_KOI7;
+ dec_kbd = TX_8859_5;
+ break;
+ case VTL_LATIN_AM:
+ /* Multinational: not listed in table */
+ /* National: not listed in table */
+ dec_lang = y;
+ dec_nrc = TX_ASCII;
+ dec_kbd = TX_8859_1;
+ break;
+#ifdef COMMENT
+ case VTL_SCS :
+ /* Multinational: Latin-2 */
+ /* National: SCS NRC */
+ break;
+#endif /* COMMENT */
+ default:
+ return(success = 0);
+ }
+ if (IS97801(tt_type_mode)) {
+ SNI_bitmode(cmask == 0377 ? 8 : 7);
+ }
+ return(success = 1);
+#endif /* NOCSETS */
+
+ case XYTVTNRC: { /* SET TERM DEC-NRC-MODE */
+ extern int decnrcm_usr, decnrcm; /* from ckoco3.c */
+ if ((x = seton(&decnrcm_usr)) < 0)
+ return(x);
+ decnrcm = decnrcm_usr;
+ return(success = 1);
+ }
+ case XYTSNIPM: { /* SET TERM SNI-PAGEMODE */
+ extern int sni_pagemode, sni_pagemode_usr;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sni_pagemode_usr = sni_pagemode = y;
+ return(success = 1);
+ }
+ case XYTSNISM: { /* SET TERM SNI-SCROLLMODE */
+ extern int sni_scroll_mode, sni_scroll_mode_usr;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sni_scroll_mode_usr = sni_scroll_mode = y;
+ return(success = 1);
+ }
+ case XYTSNICC: { /* SET TERM SNI-CH.CODE */
+ extern int sni_chcode_usr;
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ sni_chcode_usr = y;
+ SNI_chcode(y);
+ return(success = 1);
+ }
+ case XYTSNIFV: { /* SET TERM SNI-FIRMWARE-VERSIONS */
+ extern CHAR sni_kbd_firmware[], sni_term_firmware[];
+ CHAR kbd[7],term[7];
+
+ if ((x = cmfld("Keyboard Firmware Version",sni_kbd_firmware,
+ &s, xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) != 6) {
+ printf("?Sorry - the firmware version must be 6 digits long\n");
+ return(-9);
+ }
+ for (i = 0; i < 6; i++) {
+ if (!isdigit(s[i])) {
+ printf("?Sorry - the firmware version can only contain digits [0-9]\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(kbd,s,7);
+
+ if ((x = cmfld("Terminal Firmware Version",sni_term_firmware,
+ &s, xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) != 6) {
+ printf("?Sorry - the firmware version must be 6 digits long\n");
+ return(-9);
+ }
+ for (i = 0; i < 6; i++) {
+ if (!isdigit(s[i])) {
+ printf("?Sorry - the firmware version can only contain digits [0-9]\n");
+ return(-9);
+ }
+ }
+ ckstrncpy(term,s,7);
+ if ((x = cmcfm()) < 0) return(x);
+
+ ckstrncpy(sni_kbd_firmware,kbd,7);
+ ckstrncpy(sni_term_firmware,term,7);
+ return(success = 1);
+ }
+
+ case XYTLSP: { /* SET TERM LINE-SPACING */
+ if ((x = cmfld("Line Spacing","1",&s, xxstring)) < 0)
+ return(x);
+ if (isfloat(s,0) < 1) { /* (sets floatval) */
+ printf("?Integer or floating-point number required\n");
+ return(-9);
+ }
+ if (floatval < 1.0 || floatval > 3.0) {
+ printf("?Value must within the range 1.0 and 3.0 (inclusive)\n");
+ return(-9);
+ }
+ if ((x = cmcfm()) < 0) return(x);
+#ifdef KUI
+ tt_linespacing[VCMD] = tt_linespacing[VTERM] = floatval;
+ return(success = 1);
+#else /* KUI */
+ printf("?Sorry, Line-spacing is only supported in K95G.EXE.\n");
+ return(success = 0);
+#endif /* KUI */
+ }
+#endif /* OS2 */
+
+ default: /* Shouldn't get here. */
+ return(-2);
+ }
+#endif /* MAC */
+#ifdef COMMENT
+ /*
+ This was supposed to shut up picky compilers but instead it makes
+ most compilers complain about "statement not reached".
+ */
+ return(-2);
+#endif /* COMMENT */
+#ifdef OS2
+return(-2);
+#endif /* OS2 */
+}
+
+#ifdef OS2
+int
+settitle(void) {
+ extern char usertitle[];
+ if ((y = cmtxt("title text","",&s,xxstring)) < 0)
+ return(y);
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ s = brstrip(s);
+ ckstrncpy(usertitle,s,64);
+ os2settitle("",1);
+ return(1);
+}
+
+static struct keytab dialertab[] = { /* K95 Dialer types */
+ "backspace", 0, 0,
+ "enter", 1, 0
+};
+static int ndialer = 2;
+
+int
+setdialer(void) {
+ int t, x, y;
+ int clear = 0, deflt = 0;
+ int kc; /* Key code */
+ char *s = NULL; /* Key binding */
+#ifndef NOKVERBS
+ char *p = NULL; /* Worker */
+#endif /* NOKVERBS */
+ con_event defevt;
+ extern int os2gks;
+ extern int mskkeys;
+ extern int initvik;
+
+ defevt.type = error;
+
+ if (( x = cmkey(dialertab, ndialer,
+ "Kermit-95 dialer work-arounds",
+ "", xxstring)) < 0 )
+ return(x);
+ switch (x) {
+ case 0: /* Backspace */
+ kc = 264;
+ break;
+ case 1: /* Enter */
+ kc = 269;
+ break;
+ default:
+ printf("Illegal value in setdialer()\n");
+ return(-9);
+ }
+ if ((y = cmtxt("Key definition","",&s,xxstring)) < 0)
+ return(y);
+
+#ifdef IKSD
+ if (inserver) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ s = brstrip(s);
+#ifndef NOKVERBS
+ p = s; /* Save this place */
+#endif /* NOKVERBS */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else.
+
+ We use this code active for all versions that support SET KEY, even if they
+ don't support \Kverbs, because otherwise \K would behave differently for
+ different versions.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#endif /* NOKVERBS */
+
+ /* Clear the definition for SET KEY */
+ if (macrotab[kc]) { /* Possibly free old macro from key. */
+ free((char *)macrotab[kc]);
+ macrotab[kc] = NULL;
+ }
+ keymap[kc] = (KEY) kc;
+
+ /* Now reprogram the default value for all terminal types */
+ /* remember to treat Wyse and Televideo terminals special */
+ /* because of their use of Kverbs for Backspace and Enter */
+ for (t = 0; t <= TT_MAX; t++) {
+ if ( ISDG200(t) && kc == 264) {
+ extern char * udkfkeys[] ;
+ if (kc == 264) { /* \Kdgbs */
+ if (udkfkeys[83])
+ free(udkfkeys[83]);
+ udkfkeys[83] = strdup(s);
+ }
+ } else if (ISWYSE(t) || ISTVI(t)) {
+ extern char * udkfkeys[] ;
+ if (kc == 264) { /* \Kwybs or \Ktvibs */
+ if (udkfkeys[32])
+ free(udkfkeys[32]);
+ udkfkeys[32] = strdup(s);
+ }
+ if (kc == 269) { /* \Kwyenter and \Kwyreturn */
+ if (udkfkeys[39]) /* \Ktvienter and \Ktvireturn */
+ free(udkfkeys[39]);
+ udkfkeys[39] = strdup(s);
+ if (udkfkeys[49])
+ free(udkfkeys[49]);
+ udkfkeys[49] = strdup(s);
+ }
+ } else {
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Clear individual key def */
+ deletekeymap(t,kc);
+ break;
+ case 1:
+ defevt.type = key; /* Single character */
+ defevt.key.scancode = *s;
+ break;
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ /* Exact match req'd */
+ debug(F101,"set key kverb lookup",0,y);
+ if (y > -1) {
+ defevt.type = kverb;
+ defevt.kverb.id = y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+ defevt.type = macro;
+ defevt.macro.string = (char *) malloc(strlen(s)+1);
+ if (defevt.macro.string)
+ strcpy(defevt.macro.string, s); /* safe */
+ break;
+ }
+ insertkeymap( t, kc, defevt ) ;
+ initvik = 1; /* Update VIK table */
+ }
+ }
+ return(1);
+}
+#endif /* OS2 */
+
+#ifdef NT
+int
+setwin95( void ) {
+ int x, y, z;
+
+ if (( y = cmkey(win95tab, nwin95,
+ "Windows 95 specific work-arounds",
+ "keyboard-translation",
+ xxstring)) < 0 )
+ return (y);
+ switch (y) {
+ case XYWPOPUP:
+ if ((y = cmkey(onoff,2,"popups are used to prompt the user for data",
+ "on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95_popup = y;
+ return(1);
+
+ case XYW8_3:
+ if ((y = cmkey(onoff,2,"8.3 FAT file names","off",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95_8_3 = y;
+ return(1);
+
+ case XYWSELECT:
+ if ((y = cmkey(onoff,2,"\"select()\" fails on write","off",
+ xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95selectbug = y;
+ return(1);
+
+ case XYWAGR:
+ if ((y = cmkey(onoff,2,"Right-Alt is Alt-Gr","off",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95altgr = y;
+ return(1);
+
+ case XYWOIO:
+ if ((y = cmkey(onoff,2,"Use Overlapped I/O","on",xxstring)) < 0)
+ return(y);
+ if (y) {
+ if ((x = cmnum("Maximum number of outstanding I/O requests",
+ "10",10,&z,xxstring)) < 0)
+ return(x);
+ if (z < 1 || z > 7) {
+ printf(
+"?Maximum outstanding I/O requests must be between 1 and 7.\n");
+ return(-9);
+ }
+ } else
+ z = 1;
+ if ((x = cmcfm()) < 0) return(x);
+ owwait = !y;
+ maxow = maxow_usr = z;
+ return(1);
+
+ case XYWKEY:
+#ifndef COMMENT
+ printf("\n?\"Keyboard-Translation\" is no longer required.\n");
+ return(-9);
+#else /* COMMENT */
+ if (( z = cmkey(tcstab, ntcs,
+ "Keyboard Character Set",
+ "latin1-iso",
+ xxstring)) < 0)
+ return (z);
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ win95kcsi = z;
+ win95kl2 = (win95kcsi == TC_2LATIN);
+
+ if (win95kcsi == TC_TRANSP) {
+ win95kcs = NULL;
+ } else {
+#ifdef UNICODE
+ win95kcs = xlr[win95kcsi][tx2fc(tcsl)];
+#else /* UNICODE */
+ win95kcs = xlr[win95kcsi][tcsl];
+#endif /* UNICODE */
+ }
+ return(1);
+#endif /* COMMENT */
+
+ case XYWLUC:
+ if ((y = cmkey(onoff,2,"Unicode-to-Lucida-Console substitutions",
+ "on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95lucida = y;
+ return(1);
+
+ case XYWHSL:
+ if ((y = cmkey(onoff,2,"Horizontal Scan Line substitutions",
+ "on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ win95hsl = y;
+ return(1);
+
+ default:
+ printf("Illegal value in setwin95()\n");
+ return(-9);
+ }
+}
+#endif /* NT */
+
+#ifdef OS2
+int
+setprty (
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+/* setprty */ ) {
+ int x, y, z;
+
+ if (( y = cmkey(prtytab, nprty,
+ "priority level of terminal and communication threads",
+ "foreground-server",
+ xxstring)) < 0 )
+ return (y);
+
+ if ((x = cmcfm()) < 0)
+ return (x);
+#ifdef IKSD
+ if (inserver &&
+#ifdef IKSDCONF
+ iksdcf
+#else
+ 1
+#endif /* IKSDCONF */
+ ) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ priority = y;
+ return(TRUE);
+}
+#endif /* OS2 */
+
+int
+setbell() {
+ int y, x;
+#ifdef OS2
+ int z;
+#endif /* OS2 */
+
+ if ((y = cmkey(beltab,nbeltab,
+#ifdef OS2
+ "how console and terminal bells should\nbe generated", "audible",
+#else
+ "Whether Kermit should ring the terminal bell (beep)", "on",
+#endif /* OS2 */
+ xxstring)) < 0)
+ return(y);
+
+#ifdef IKSD
+ if (inserver) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ switch (y) { /* SET BELL */
+ case XYB_NONE:
+#ifdef OS2
+ case XYB_VIS:
+#endif /* OS2 */
+ if ((x = cmcfm()) < 0)
+ return(x);
+#ifdef OS2
+ tt_bell = y;
+#else
+ tt_bell = 0;
+#endif /* OS2 */
+ break;
+
+ case XYB_AUD:
+#ifdef OS2
+ if ((x = cmkey(audibletab, naudibletab,
+ "how audible console and terminal\nbells should be generated",
+ "beep",xxstring))<0)
+ return(x);
+ if ((z = cmcfm()) < 0)
+ return(z);
+ tt_bell = y | x;
+#else
+ /* This lets C-Kermit accept but ignore trailing K95 keywords */
+ if ((x = cmtxt("Confirm with carriage return","",&s,xxstring)) < 0)
+ return(x);
+ tt_bell = 1;
+#endif /* OS2 */
+ break;
+ }
+ return(1);
+}
+
+#ifdef OS2MOUSE
+int
+setmou(
+#ifdef CK_ANSIC
+ void
+#endif /* CK_ANSIC */
+ /* setmou */ ) {
+ extern int initvik;
+ int button = 0, event = 0;
+ char * p;
+
+ if ((y = cmkey(mousetab,nmtab,"","",xxstring)) < 0)
+ return(y);
+
+#ifdef IKSD
+ if (inserver) {
+ if ((y = cmcfm()) < 0) return(y);
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+
+ if (y == XYM_ON) { /* MOUSE ACTIVATION */
+ int old_mou = tt_mouse;
+ if ((x = seton(&tt_mouse)) < 0)
+ return(x);
+ if (tt_mouse != old_mou)
+ if (tt_mouse)
+ os2_mouseon();
+ else
+ os2_mouseoff();
+ return(1);
+ }
+
+ if (y == XYM_DEBUG) { /* MOUSE DEBUG */
+ extern int MouseDebug;
+ if ((x = seton(&MouseDebug)) < 0)
+ return(x);
+ return(1);
+ }
+
+ if (y == XYM_CLEAR) { /* Reset Mouse Defaults */
+ if ((x = cmcfm()) < 0) return(x);
+ mousemapinit(-1,-1);
+ initvik = 1; /* Update VIK Table */
+ return 1;
+ }
+ if (y != XYM_BUTTON) { /* Shouldn't happen. */
+ printf("Internal parsing error\n");
+ return(-9);
+ }
+
+ /* MOUSE EVENT ... */
+
+ if ((button = cmkey(mousebuttontab,nmbtab,
+ "Button number","1",
+ xxstring)) < 0)
+ return(button);
+
+ if ((y = cmkey(mousemodtab,nmmtab,
+ "Keyboard modifier","none",
+ xxstring)) < 0)
+ return(y);
+
+ event |= y; /* OR in the bits */
+
+ if ((y = cmkey(mclicktab,nmctab,"","click",xxstring)) < 0)
+ return(y);
+
+ /* Two bits are assigned, if neither are set then it is button one */
+
+ event |= y; /* OR in the bit */
+
+ wideresult = -1;
+
+ if ((y = cmtxt("definition,\n\
+or Ctrl-C to cancel this command,\n\
+or Enter to restore default definition",
+ "",&s,NULL)) < 0) {
+ return(y);
+ }
+ s = brstrip(s);
+ p = s; /* Save this place */
+/*
+ If the definition included any \Kverbs, quote the backslash so the \Kverb
+ will still be in the definition when the key is pressed. We don't do this
+ in zzstring(), because \Kverbs are valid only in this context and nowhere
+ else. This code copied from SET KEY, q.v. for addt'l commentary.
+*/
+ for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
+ if ((x > 0) &&
+ (s[x] == 'K' || s[x] == 'k')
+ ) { /* Have K */
+
+ if ((x == 1 && s[x-1] == CMDQ) ||
+ (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
+ line[y++] = CMDQ; /* Make it \\K */
+ }
+ if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
+ line[y-1] = CMDQ; /* Have \{K */
+ line[y++] = '{'; /* Make it \\{K */
+ }
+ }
+ line[y] = s[x];
+ }
+ line[y++] = NUL; /* Terminate */
+ s = line + y + 1; /* Point to after it */
+ x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
+ if ((x < (LINBUFSIZ / 2)) ||
+ (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
+ printf("?Key definition too long\n");
+ return(-9);
+ }
+ s = line + y + 1; /* Point to result. */
+
+#ifndef NOKVERBS
+/*
+ Special case: see if the definition starts with a \Kverb.
+ If it does, point to it with p, otherwise set p to NULL.
+*/
+ p = s;
+ if (*p++ == CMDQ) {
+ if (*p == '{') p++;
+ p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
+ }
+#else
+ p = NULL;
+#endif /* NOKVERBS */
+
+ /* free the old definition if necessary */
+ if (mousemap[button][event].type == macro) {
+ free( mousemap[button][event].macro.string);
+ mousemap[button][event].macro.string = NULL;
+ }
+ switch (strlen(s)) { /* Action depends on length */
+ case 0: /* Reset to default binding */
+ mousemapinit( button, event );
+ break;
+ case 1: /* Single character */
+ mousemap[button][event].type = key;
+ mousemap[button][event].key.scancode = *s;
+ break;
+ default: /* Character string */
+#ifndef NOKVERBS
+ if (p) {
+ y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
+ debug(F101,"set mouse kverb lookup",0,y); /* need exact match */
+ if (y > -1) {
+ /* Assign the kverb to the event */
+ mousemap[button][event].type = kverb;
+ mousemap[button][event].kverb.id = F_KVERB | y;
+ break;
+ }
+ }
+#endif /* NOKVERBS */
+
+ /* Otherwise, it's a macro, so assign the macro to the event */
+ mousemap[button][event].type = macro;
+ mousemap[button][event].macro.string = (MACRO) malloc(strlen(s)+1);
+ if (mousemap[button][event].macro.string)
+ strcpy((char *) mousemap[button][event].macro.string, s); /* safe */
+ break;
+ }
+ initvik = 1; /* Update VIK Table */
+ if ( (button == XYM_B3) && (mousebuttoncount() < 3) && !quiet )
+ {
+ printf("?Warning: this machine does not have a three button mouse.\n");
+ return(0);
+ }
+ return(1);
+}
+#endif /* OS2MOUSE */
+#endif /* NOLOCAL */
+
+#ifndef NOXFER
+int /* SET SEND/RECEIVE */
+setsr(xx, rmsflg) int xx; int rmsflg; {
+ if (xx == XYRECV)
+ ckstrncpy(line,"Parameter for inbound packets",LINBUFSIZ);
+ else
+ ckstrncpy(line,"Parameter for outbound packets",LINBUFSIZ);
+
+ if (rmsflg) {
+ if ((y = cmkey(rsrtab,nrsrtab,line,"",xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Remote receive parameter required\n");
+ return(-9);
+ } else return(y);
+ }
+ } else {
+ if ((y = cmkey(srtab,nsrtab,line,"",xxstring)) < 0) return(y);
+ }
+ switch (y) {
+ case XYQCTL: /* CONTROL-PREFIX */
+ if ((x = cmnum("ASCII value of control prefix","",10,&y,xxstring)) < 0)
+ return(x);
+ if ((x = cmcfm()) < 0) return(x);
+ if ((y > 32 && y < 63) || (y > 95 && y < 127)) {
+ if (xx == XYRECV)
+ ctlq = (CHAR) y; /* RECEIVE prefix, use with caution! */
+ else
+ myctlq = (CHAR) y; /* SEND prefix, OK to change */
+ return(success = 1);
+ } else {
+ printf("?Illegal value for prefix character\n");
+ return(-9);
+ }
+
+ case XYEOL:
+ if ((y = setcc("13",&z)) < 0)
+ return(y);
+ if (z > 31) {
+ printf("Sorry, the legal values are 0-31\n");
+ return(-9);
+ }
+ if (xx == XYRECV)
+ eol = (CHAR) z;
+ else
+ seol = (CHAR) z;
+ return(success = y);
+
+ case XYLEN:
+ y = cmnum("Maximum number of characters in a packet","90",10,&x,
+ xxstring);
+ if (xx == XYRECV) { /* Receive... */
+ if ((y = setnum(&z,x,y,maxrps)) < 0)
+ return(y);
+ if (protocol != PROTO_K) {
+ printf("?Sorry, this command does not apply to %s protocol.\n",
+ ptab[protocol].p_name
+ );
+ printf("Use SET SEND PACKET-LENGTH for XYZMODEM\n");
+ return(-9);
+ }
+ if (z < 10) {
+ printf("Sorry, 10 is the minimum\n");
+ return(-9);
+ }
+ if (rmsflg) {
+ sstate = setgen('S', "401", ckitoa(z), "");
+ return((int) sstate);
+ } else {
+ if (protocol == PROTO_K) {
+ if (z > MAXRP) z = MAXRP;
+ y = adjpkl(z,wslotr,bigrbsiz);
+ if (y != z) {
+ urpsiz = y;
+ if (!xcmdsrc)
+ if (msgflg) printf(
+" Adjusting receive packet-length to %d for %d window slots\n",
+ y, wslotr);
+ }
+ urpsiz = y;
+ ptab[protocol].rpktlen = urpsiz;
+ rpsiz = (y > 94) ? 94 : y;
+ } else {
+#ifdef CK_XYZ
+ if ((protocol == PROTO_X || protocol == PROTO_XC) &&
+ z != 128 && z != 1024) {
+ printf("Sorry, bad packet length for XMODEM.\n");
+ printf("Please use 128 or 1024.\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ urpsiz = rpsiz = z;
+ }
+ }
+ } else { /* Send... */
+ if ((y = setnum(&z,x,y,maxsps)) < 0)
+ return(y);
+ if (z < 10) {
+ printf("Sorry, 10 is the minimum\n");
+ return(-9);
+ }
+ if (protocol == PROTO_K) {
+ if (z > MAXSP) z = MAXSP;
+ spsiz = z; /* Set it */
+ y = adjpkl(spsiz,wslotr,bigsbsiz);
+ if (y != spsiz && !xcmdsrc)
+ if (msgflg)
+ printf("Adjusting packet size to %d for %d window slots\n",
+ y,wslotr);
+ } else
+ y = z;
+#ifdef CK_XYZ
+ if ((protocol == PROTO_X || protocol == PROTO_XC) &&
+ z != 128 && z != 1024) {
+ printf("Sorry, bad packet length for XMODEM.\n");
+ printf("Please use 128 or 1024.\n");
+ return(-9);
+ }
+#endif /* CK_XYZ */
+ spsiz = spmax = spsizr = y; /* Set it and flag that it was set */
+ spsizf = 1; /* to allow overriding Send-Init. */
+ ptab[protocol].spktflg = spsizf;
+ ptab[protocol].spktlen = spsiz;
+ }
+ if (pflag && protocol == PROTO_K && !xcmdsrc) {
+ if (z > 94 && !reliable && msgflg) {
+ /* printf("Extended-length packets requested.\n"); */
+ if (bctr < 2 && z > 200) printf("\
+Remember to SET BLOCK 2 or 3 for long packets.\n");
+ }
+ if (speed <= 0L) speed = ttgspd();
+#ifdef COMMENT
+/*
+ Kermit does this now itself.
+*/
+ if (speed <= 0L && z > 200 && msgflg) {
+ printf("\
+Make sure your timeout interval is long enough for %d-byte packets.\n",z);
+ }
+#endif /* COMMENT */
+ }
+ return(success = y);
+
+ case XYMARK:
+#ifdef DOOMSDAY
+/*
+ Printable start-of-packet works for UNIX and VMS only!
+*/
+ x_ifnum = 1;
+ y = cmnum("Code for packet-start character","1",10,&x,xxstring);
+ x_ifnum = 0;
+ if ((y = setnum(&z,x,y,126)) < 0) return(y);
+#else
+ if ((y = setcc("1",&z)) < 0)
+ return(y);
+#endif /* DOOMSDAY */
+ if (xx == XYRECV)
+ stchr = (CHAR) z;
+ else {
+ mystch = (CHAR) z;
+#ifdef IKS_OPTION
+ /* If IKS negotiation in use */
+ if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT))
+ tn_siks(KERMIT_SOP); /* Report change to other side */
+#endif /* IKS_OPTION */
+ }
+ return(success = y);
+
+ case XYNPAD: /* PADDING */
+ y = cmnum("How many padding characters for inbound packets","0",10,&x,
+ xxstring);
+ if ((y = setnum(&z,x,y,94)) < 0) return(y);
+ if (xx == XYRECV)
+ mypadn = (CHAR) z;
+ else
+ npad = (CHAR) z;
+ return(success = y);
+
+ case XYPADC: /* PAD-CHARACTER */
+ if ((y = setcc("0",&z)) < 0) return(y);
+ if (xx == XYRECV) mypadc = z; else padch = z;
+ return(success = y);
+
+ case XYTIMO: /* TIMEOUT */
+ if (xx == XYRECV) {
+ y = cmnum("Packet timeout interval",ckitoa(URTIME),10,&x,xxstring);
+ if ((y = setnum(&z,x,y,94)) < 0) return(y);
+
+ if (rmsflg) { /* REMOTE SET RECEIVE TIMEOUT */
+ sstate = setgen('S', "402", ckitoa(z), "");
+ return((int) sstate);
+ } else { /* SET RECEIVE TIMEOUT */
+ pkttim = z; /* Value to put in my negotiation */
+ } /* packet for other Kermit to use */
+
+ } else { /* SET SEND TIMEOUT */
+#ifdef CK_TIMERS
+ extern int rttflg, mintime, maxtime;
+ int tmin = 0, tmax = 0;
+#endif /* CK_TIMERS */
+ y = cmnum("Packet timeout interval",ckitoa(DMYTIM),10,&x,xxstring);
+ if (y == -3) { /* They cancelled a previous */
+ x = DMYTIM; /* SET SEND command, so restore */
+ timef = 0; /* and turn off the override flag */
+ y = cmcfm();
+ }
+#ifdef CK_TIMERS
+ if (y < 0) return(y);
+ if (x < 0) {
+ printf("?Out of range - %d\n",x);
+ return(-9);
+ }
+ if ((z = cmkey(timotab,2,"","dynamic",xxstring)) < 0) return(z);
+ if (z) {
+ if ((y = cmnum("Minimum timeout to allow",
+ "1",10,&tmin,xxstring)) < 0)
+ return(y);
+ if (tmin < 1) {
+ printf("?Out of range - %d\n",tmin);
+ return(-9);
+ }
+ if ((y = cmnum("Maximum timeout to allow",
+ "0",10,&tmax,xxstring)) < 0)
+ return(y);
+ /* 0 means let Kermit choose, < 0 means no maximum */
+ }
+ if ((y = cmcfm()) < 0)
+ return(y);
+ rttflg = z; /* Round-trip timer flag */
+ z = x;
+#else
+ if ((y = setnum(&z,x,y,94)) < 0)
+ return(y);
+#endif /* CK_TIMERS */
+ timef = 1; /* Turn on the override flag */
+ timint = rtimo = z; /* Override value for me to use */
+#ifdef CK_TIMERS
+ if (rttflg) { /* Lower and upper bounds */
+ mintime = tmin;
+ maxtime = tmax;
+ }
+#endif /* CK_TIMERS */
+ }
+ return(success = 1);
+
+ case XYFPATH: /* PATHNAMES */
+ if (xx == XYRECV) {
+ y = cmkey(rpathtab,nrpathtab,"","auto",xxstring);
+ } else {
+ y = cmkey(pathtab,npathtab,"","off",xxstring);
+ }
+ if (y < 0) return(y);
+
+ if ((x = cmcfm()) < 0) return(x);
+ if (xx == XYRECV) { /* SET RECEIVE PATHNAMES */
+ fnrpath = y;
+ ptab[protocol].fnrp = fnrpath;
+ } else { /* SET SEND PATHNAMES */
+ fnspath = y;
+ ptab[protocol].fnsp = fnspath;
+ }
+ return(success = 1); /* Note: 0 = ON, 1 = OFF */
+ /* In other words, ON = leave pathnames ON, OFF = take them off. */
+
+ case XYPAUS: /* SET SEND/RECEIVE PAUSE */
+ y = cmnum("Milliseconds to pause between packets","0",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,15000)) < 0)
+ return(y);
+ pktpaus = z;
+ return(success = 1);
+
+#ifdef CKXXCHAR /* SET SEND/RECEIVE IGNORE/DOUBLE */
+ case XYIGN:
+ case XYDBL: {
+ int i, zz;
+ short *p;
+ extern short dblt[];
+ extern int dblflag, ignflag;
+
+ /* Make space for a temporary copy of the ignore/double table */
+
+ zz = y;
+#ifdef COMMENT
+ if (zz == XYIGN && xx == XYSEND) {
+ blah blah who cares
+ }
+ if (zz == XYDBL && xx == XYRECV) {
+ blah blah
+ }
+#endif /* COMMENT */
+ p = (short *)malloc(256 * sizeof(short));
+ if (!p) {
+ printf("?Internal error - malloc failure\n");
+ return(-9);
+ }
+ for (i = 0; i < 256; i++) p[i] = dblt[i]; /* Copy current table */
+
+ while (1) { /* Collect a list of numbers */
+#ifndef NOSPL
+ x_ifnum = 1; /* Turn off complaints from eval() */
+#endif /* NOSPL */
+ if ((x = cmnum(zz == XYDBL ?
+ "Character to double" :
+ "Character to ignore",
+ "",10,&y,xxstring
+ )) < 0) {
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ if (x == -3) /* Done */
+ break;
+ if (x == -2) {
+ if (p) { free(p); p = NULL; }
+ debug(F110,"SET S/R DOUBLE/IGNORE atmbuf",atmbuf,0);
+ if (!ckstrcmp(atmbuf,"none",4,0) ||
+ !ckstrcmp(atmbuf,"non",3,0) ||
+ !ckstrcmp(atmbuf,"no",2,0) ||
+ !ckstrcmp(atmbuf,"n",1,0)) {
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+ for (y = 0; y < 256; y++)
+ dblt[y] &= (zz == XYDBL) ? 1 : 2;
+ if (zz == XYDBL) dblflag = 0;
+ if (zz == XYIGN) ignflag = 0;
+ return(success = 1);
+ } else {
+ printf(
+ "?Please specify a number or the word NONE\n");
+ return(-9);
+ }
+ } else {
+ free(p);
+ p = NULL;
+ return(x);
+ }
+ }
+#ifndef NOSPL
+ x_ifnum = 0;
+#endif /* NOSPL */
+ if (y < 0 || y > 255) {
+ printf("?Please enter a character code in range 0-255\n");
+ free(p);
+ p = NULL;
+ return(-9);
+ }
+ p[y] |= (zz == XYDBL) ? 2 : 1;
+ if (zz == XYDBL) dblflag = 1;
+ if (zz == XYIGN) ignflag = 1;
+ } /* End of while loop */
+
+ if ((x = cmcfm()) < 0) return(x);
+/*
+ Get here only if they have made no mistakes. Copy temporary table back to
+ permanent one, then free temporary table and return successfully.
+*/
+ if (p) {
+ for (i = 0; i < 256; i++) dblt[i] = p[i];
+ free(p);
+ p = NULL;
+ }
+ return(success = 1);
+ }
+#endif /* CKXXCHAR */
+
+#ifdef PIPESEND
+ case XYFLTR: { /* SET { SEND, RECEIVE } FILTER */
+ if ((y = cmtxt((xx == XYSEND) ?
+ "Filter program for sending files -\n\
+ use \\v(filename) to substitute filename" :
+ "Filter program for receiving files -\n\
+ use \\v(filename) to substitute filename",
+ "",&s,NULL)) < 0)
+ return(y);
+ if (!*s) { /* Removing a filter... */
+ if (xx == XYSEND && sndfilter) {
+ makestr(&g_sfilter,NULL);
+ makestr(&sndfilter,NULL);
+ } else if (rcvfilter) {
+ makestr(&g_rfilter,NULL);
+ makestr(&rcvfilter,NULL);
+ }
+ return(success = 1);
+ } /* Adding a filter... */
+ s = brstrip(s); /* Strip any braces */
+ y = strlen(s);
+ if (xx == XYSEND) { /* For SEND filter... */
+ for (x = 0; x < y; x++) { /* make sure they included "\v(...)" */
+ if (s[x] != '\\') continue;
+ if (s[x+1] == 'v') break;
+ }
+ if (x == y) {
+ printf(
+ "?Filter must contain a replacement variable for filename.\n"
+ );
+ return(-9);
+ }
+ }
+ if (xx == XYSEND) {
+ makestr(&sndfilter,s);
+ makestr(&g_sfilter,s);
+ } else {
+ makestr(&rcvfilter,s);
+ makestr(&g_rfilter,s);
+ }
+ return(success = 1);
+ }
+#endif /* PIPESEND */
+
+ case XYINIL:
+ y = cmnum("Max length for protocol init string","-1",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,-1)) < 0)
+ return(y);
+ if (xx == XYSEND)
+ sprmlen = z;
+ else
+ rprmlen = z;
+ return(success = 1);
+
+ case 993: {
+ extern int sendipkts;
+ if (xx == XYSEND) {
+ if ((x = seton(&sendipkts)) < 0)
+ return(x);
+ }
+ return(1);
+ }
+#ifdef CK_PERMS
+ case 994:
+ switch(xx) {
+ case XYSEND:
+ if ((x = seton(&atlpro)) < 0) return(x);
+ atgpro = atlpro;
+ return(1);
+ case XYRECV:
+ if ((x = seton(&atlpri)) < 0) return(x);
+ atgpri = atlpri;
+ return(1);
+ default:
+ return(-2);
+ }
+#endif /* CK_PERMS */
+
+#ifndef NOCSETS
+ case XYCSET: { /* CHARACTER-SET-SELECTION */
+ extern struct keytab xfrmtab[];
+ extern int r_cset, s_cset;
+ if ((y = cmkey(xfrmtab,2,"","automatic",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (xx == XYSEND)
+ s_cset = y;
+ else
+ r_cset = y;
+ return(success = 1);
+ }
+#endif /* NOCSETS */
+
+ case XYBUP:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ if ((x = cmcfm()) < 0) return(x);
+ if (xx == XYSEND) {
+ extern int skipbup;
+ skipbup = (y == 0) ? 1 : 0;
+ return(success = 1);
+ } else {
+ printf(
+"?Please use SET FILE COLLISION to choose the desired action\n");
+ return(-9);
+ }
+
+ case XYMOVE:
+#ifdef COMMENT
+ y = cmdir("Directory to move file(s) to after successful transfer",
+ "",&s,xxstring);
+#else
+ y = cmtxt("Directory to move file(s) to after successful transfer",
+ "",&s,xxstring);
+#endif /* COMMENT */
+
+ if (y < 0 && y != -3)
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+
+#ifdef COMMENT
+ /* Only needed for cmdir() */
+ if ((x = cmcfm()) < 0)
+ return(x);
+#endif /* COMMENT */
+
+ /* Check directory existence if absolute */
+ /* THIS MEANS IT CAN'T INCLUDE ANY DEFERRED VARIABLES! */
+ if (s) if (*s) {
+ if (isabsolute(s) && !isdir(s)) {
+ printf("?Directory does not exist - %s\n",s);
+ return(-9);
+ }
+ }
+ if (xx == XYSEND) {
+ if (*s) {
+#ifdef COMMENT
+ /* Allow it to be relative */
+ zfnqfp(s,LINBUFSIZ,line);
+#endif /* COMMENT */
+ makestr(&snd_move,line);
+ makestr(&g_snd_move,line);
+ } else {
+ makestr(&snd_move,NULL);
+ makestr(&g_snd_move,NULL);
+ }
+ } else {
+ if (*s) {
+#ifdef COMMENT
+ /* Allow it to be relative */
+ zfnqfp(s,LINBUFSIZ,line);
+#endif /* COMMENT */
+ makestr(&rcv_move,line);
+ makestr(&g_rcv_move,line);
+ } else {
+ makestr(&rcv_move,NULL);
+ makestr(&g_rcv_move,NULL);
+ }
+ }
+ return(success = 1);
+
+ case XYRENAME:
+ y = cmtxt("Template to rename file(s) to after successful transfer",
+ "",&s,NULL); /* NOTE: no xxstring */
+ if (y < 0 && y != -3) /* Evaluation is deferred */
+ return(y);
+ ckstrncpy(line,s,LINBUFSIZ);
+ s = brstrip(line);
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if (xx == XYSEND) {
+ if (*s) {
+ makestr(&snd_rename,s);
+ makestr(&g_snd_rename,s);
+ } else {
+ makestr(&snd_rename,NULL);
+ makestr(&g_snd_rename,NULL);
+ }
+ } else {
+ if (*s) {
+ makestr(&rcv_rename,s);
+ makestr(&g_rcv_rename,s);
+ } else {
+ makestr(&rcv_rename,NULL);
+ makestr(&g_rcv_rename,NULL);
+ }
+ }
+ return(success = 1);
+
+#ifdef VMS
+ case 887: /* VERSION-NUMBERS */
+ if (xx == XYSEND) {
+ extern int vmssversions;
+ return(seton(&vmssversions));
+ } else {
+ extern int vmsrversions;
+ return(seton(&vmsrversions));
+ }
+#endif /* VMS */
+
+ default:
+ return(-2);
+ } /* End of SET SEND/RECEIVE... */
+}
+#endif /* NOXFER */
+
+#ifndef NOXMIT
+int
+setxmit() {
+ if ((y = cmkey(xmitab,nxmit,"","",xxstring)) < 0) return(y);
+ switch (y) {
+ case XMITE: /* EOF */
+ y = cmtxt("Characters to send at end of file,\n\
+ Use backslash codes for control characters","",&s,xxstring);
+ if (y < 0) return(y);
+ if ((int)strlen(s) > XMBUFL) {
+ printf("?Too many characters, %d maximum\n",XMBUFL);
+ return(-2);
+ }
+ ckstrncpy(xmitbuf,s,XMBUFL);
+ return(success = 1);
+
+ case XMITF: /* Fill */
+ y = cmnum("Numeric code for blank-line fill character","0",10,&x,
+ xxstring);
+ if ((y = setnum(&z,x,y,127)) < 0) return(y);
+ xmitf = z;
+ return(success = 1);
+ case XMITL: /* Linefeed */
+ return(seton(&xmitl));
+ case XMITS: /* Locking-Shift */
+ return(seton(&xmits));
+ case XMITP: /* Prompt */
+ y = cmnum("Numeric code for host's prompt character, 0 for none",
+ "10",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,127)) < 0) return(y);
+ xmitp = z;
+ return(success = 1);
+ case XMITX: /* Echo */
+ return(seton(&xmitx));
+ case XMITW: /* Pause */
+ y = cmnum("Number of milliseconds to pause between binary characters\n\
+or text lines during transmission","0",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,1000)) < 0) return(y);
+ xmitw = z;
+ return(success = 1);
+ case XMITT: /* Timeout */
+ y = cmnum("Seconds to wait for each character to echo",
+ "1",10,&x,xxstring);
+ if ((y = setnum(&z,x,y,1000)) < 0) return(y);
+ xmitt = z;
+ return(success = 1);
+ default:
+ return(-2);
+ }
+}
+#endif /* NOXMIT */
+
+#ifndef NOXFER
+/* D O R M T -- Do a remote command */
+
+VOID
+rmsg() {
+ if (pflag && !quiet && fdispla != XYFD_N)
+ printf(
+#ifdef CK_NEED_SIG
+ " Type your escape character, %s, followed by X or E to cancel.\n",
+ dbchr(escape)
+#else
+ " Press the X or E key to cancel.\n"
+#endif /* CK_NEED_SIG */
+ );
+}
+
+static int xzcmd = 0; /* Global copy of REMOTE cmd index */
+
+/* R E M C F M -- Confirm a REMOTE command */
+/*
+ Like cmcfm(), but allows for a redirection indicator on the end,
+ like "> filename" or "| command". Returns what cmcfm() would have
+ returned: -1 if reparse needed, etc etc blah blah. On success,
+ returns 1 with:
+
+ char * remdest containing the name of the file or command.
+ int remfile set to 1 if there is to be any redirection.
+ int remappd set to 1 if output file is to be appended to.
+ int rempipe set to 1 if remdest is a command, 0 if it is a file.
+*/
+static int
+remcfm() {
+ int x;
+ char *s;
+ char c;
+
+ remfile = 0;
+ rempipe = 0;
+ remappd = 0;
+
+ if ((x = cmtxt(
+ "> filename, | command,\n\
+or type carriage return to confirm the command",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if (remdest) {
+ free(remdest);
+ remdest = NULL;
+ }
+ debug(F101,"remcfm local","",local);
+ debug(F110,"remcfm s",s,0);
+ debug(F101,"remcfm cmd","",xzcmd);
+
+ if (!*s) { /* No redirection indicator */
+ if (!local &&
+ (xzcmd == XZDIR || xzcmd == XZTYP ||
+ xzcmd == XZXIT || xzcmd == XZSPA ||
+ xzcmd == XZHLP || xzcmd == XZPWD ||
+ xzcmd == XZLGI || xzcmd == XZLGO ||
+ xzcmd == XZWHO || xzcmd == XZHOS)) {
+ printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
+ return(-9);
+ } else
+ return(1);
+ }
+ c = *s; /* We have something */
+ if (c != '>' && c != '|') { /* Is it > or | ? */
+ printf("?Not confirmed\n"); /* No */
+ return(-9);
+ }
+ s++; /* See what follows */
+ if (c == '>' && *s == '>') { /* Allow for ">>" too */
+ s++;
+ remappd = 1; /* Append to output file */
+ }
+ while (*s == SP || *s == HT) s++; /* Strip intervening whitespace */
+ if (!*s) {
+ printf("?%s missing\n", c == '>' ? "Filename" : "Command");
+ return(-9);
+ }
+ if (c == '>' && zchko(s) < 0) { /* Check accessibility */
+ printf("?Access denied - %s\n", s);
+ return(-9);
+ }
+ remfile = 1; /* Set global results */
+ rempipe = (c == '|');
+ if (rempipe
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ ) {
+ printf("?Sorry, access to external commands is disabled.\n");
+ return(-9);
+ }
+ makestr(&remdest,s);
+#ifndef NODEBUG
+ if (deblog) {
+ debug(F101,"remcfm remfile","",remfile);
+ debug(F101,"remcfm remappd","",remappd);
+ debug(F101,"remcfm rempipe","",rempipe);
+ debug(F110,"remcfm remdest",remdest, 0);
+ }
+#endif /* NODEBUG */
+ return(1);
+}
+
+/* R E M T X T -- Like remcfm()... */
+/*
+ ... but for REMOTE commands that end with cmtxt().
+ Here we must decipher braces to discover whether the trailing
+ redirection indicator is intended for local use, or to be sent out
+ to the server, as in:
+
+ remote host blah blah > file This end
+ remote host { blah blah } > file This end
+ remote host { blah blah > file } That end
+ remote host { blah blah > file } > file Both ends
+
+ Pipes too:
+
+ remote host blah blah | cmd This end
+ remote host { blah blah } | cmd This end
+ remote host { blah blah | cmd } That end
+ remote host { blah blah | cmd } | cmd Both ends
+
+ Or both:
+
+ remote host blah blah | cmd > file This end, etc etc...
+
+ Note: this really only makes sense for REMOTE HOST, but why be picky?
+ Call after calling cmtxt(), with pointer to string that cmtxt() parsed,
+ as in "remtxt(&s);".
+
+ Returns:
+ 1 on success with braces & redirection things removed & pointer updated,
+ -9 on failure (bad indirection), after printing error message.
+*/
+int
+remtxt(p) char ** p; {
+ int i, x, bpos, ppos;
+ char c, *s, *q;
+
+ remfile = 0; /* Initialize global results */
+ rempipe = 0;
+ remappd = 0;
+ if (remdest) {
+ free(remdest);
+ remdest = NULL;
+ }
+ s = *p;
+ if (!s) /* No redirection indicator */
+ s = "";
+ if (!*s) { /* Ditto */
+ if (!local &&
+ (xzcmd == XZDIR || xzcmd == XZTYP ||
+ xzcmd == XZXIT || xzcmd == XZSPA ||
+ xzcmd == XZHLP || xzcmd == XZPWD ||
+ xzcmd == XZLGI || xzcmd == XZLGO ||
+ xzcmd == XZWHO || xzcmd == XZHOS)) {
+ printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
+ if (hints) {
+ printf("Hint: Try again with an output redirector.\n");
+ }
+ return(-9);
+ } else
+ return(1);
+ }
+ bpos = -1; /* Position of > (bracket) */
+ ppos = -1; /* Position of | (pipe) */
+ x = strlen(s); /* Length of cmtxt() string */
+
+ for (i = x-1; i >= 0; i--) { /* Search right to left. */
+ c = s[i];
+ if (c == '}') /* Break on first right brace */
+ break; /* Don't look at contents of braces */
+ else if (c == '>') /* Record position of > */
+ bpos = i;
+ else if (c == '|') /* and of | */
+ ppos = i;
+ }
+ if (bpos < 0 && ppos < 0) { /* No redirectors. */
+ if (!local &&
+ (xzcmd == XZDIR || xzcmd == XZTYP ||
+ xzcmd == XZXIT || xzcmd == XZSPA ||
+ xzcmd == XZHLP || xzcmd == XZPWD ||
+ xzcmd == XZLGI || xzcmd == XZLGO ||
+ xzcmd == XZWHO || xzcmd == XZHOS)) {
+ printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
+ if (hints) {
+ printf("Hint: Try again with an output redirector.\n");
+ }
+ return(-9);
+ }
+ s = brstrip(s); /* Remove outer braces if any. */
+ *p = s; /* Point to result */
+ return(1); /* and return. */
+ }
+ remfile = 1; /* It's | or > */
+ i = -1; /* Get leftmost symbol */
+ if (bpos > -1) /* Bracket */
+ i = bpos;
+ if (ppos > -1 && (ppos < bpos || bpos < 0)) { /* or pipe */
+ i = ppos;
+ rempipe = 1;
+ }
+ if (rempipe
+#ifndef NOPUSH
+ && nopush
+#endif /* NOPUSH */
+ ) {
+ printf("?Sorry, access to external commands is disabled.\n");
+ return(-9);
+ }
+ c = s[i]; /* Copy of symbol */
+
+ if (c == '>' && s[i+1] == '>') /* ">>" for append? */
+ remappd = 1; /* It's not just a flag it's a number */
+
+ q = s + i + 1 + remappd; /* Point past symbol in string */
+ while (*q == SP || *q == HT) q++; /* and any intervening whitespace */
+ if (!*q) {
+ printf("?%s missing\n", c == '>' ? "Filename" : "Command");
+ return(-9);
+ }
+ if (c == '>' && zchko(q) < 0) { /* (Doesn't work for | cmd > file) */
+ printf("?Access denied - %s\n", q);
+ return(-9);
+ }
+ makestr(&remdest,q); /* Create the destination string */
+ q = s + i - 1; /* Point before symbol */
+ while (q > s && (*q == SP || *q == HT)) /* Strip trailing whitespace */
+ q--;
+ *(q+1) = NUL; /* Terminate the string. */
+ s = brstrip(s); /* Remove any braces */
+ *p = s; /* Set return value */
+
+#ifndef NODEBUG
+ if (deblog) {
+ debug(F101,"remtxt remfile","",remfile);
+ debug(F101,"remtxt remappd","",remappd);
+ debug(F101,"remtxt rempipe","",rempipe);
+ debug(F110,"remtxt remdest",remdest, 0);
+ debug(F110,"remtxt command",s,0);
+ }
+#endif /* NODEBUG */
+
+ return(1);
+}
+
+int
+plogin(xx) int xx; {
+ char *p1 = NULL, *p2 = NULL, *p3 = NULL;
+ int psaved = 0, rc = 0;
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ debug(F101,"plogin local","",local);
+
+ if (!local || (network && ttchk() < 0)) {
+ printf("?No connection\n");
+ return(-9);
+ }
+ if ((x = cmfld("User ID","",&s,xxstring)) < 0) { /* Get User ID */
+ if (x != -3) return(x);
+ }
+ y = strlen(s);
+ if (y > 0) {
+ if ((p1 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ rc = -9;
+ goto XZXLGI;
+ } else
+ strcpy(p1,s); /* safe */
+ if ((rc = cmfld("Password","",&s,xxstring)) < 0)
+ if (rc != -3) goto XZXLGI;
+ y = strlen(s);
+ if (y > 0) {
+ if ((p2 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ rc = -9;
+ goto XZXLGI;
+ } else
+ strcpy(p2,s); /* safe */
+ if ((rc = cmfld("Account","",&s,xxstring)) < 0)
+ if (rc != -3) goto XZXLGI;
+ y = strlen(s);
+ if (y > 0) {
+ if ((p3 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ rc = -9;
+ goto XZXLGI;
+ } else
+ strcpy(p3,s); /* safe */
+ }
+ }
+ }
+ if ((rc = remtxt(&s)) < 0) /* Confirm & handle redirectors */
+ goto XZXLGI;
+
+ if (!p1) { /* No Userid specified... */
+ debok = 0; /* Don't log this */
+ /* Prompt for username, password, and account */
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ psaved = 1;
+ debug(F110,"REMOTE LOGIN saved",psave,0);
+
+ cmsetp("Username: "); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(1);
+ prompt(xxstring);
+ rc = -9;
+ for (x = -1; x < 0; ) { /* Prompt till they answer */
+ cmres(); /* Reset the parser */
+ x = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ }
+ y = strlen(s);
+ if (y < 1) {
+ printf("?Canceled\n");
+ goto XZXLGI;
+ }
+ if ((p1 = malloc(y + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XZXLGI;
+ } else
+ strcpy(p1,s); /* safe */
+
+ cmsetp("Password: "); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(0); /* No echo */
+ prompt(xxstring);
+ debok = 0;
+ for (x = -1; x < 0 && x != -3; ) { /* Get answer */
+ cmres(); /* Reset the parser */
+ x = cmtxt("","",&s,NULL); /* Get literal line of text */
+ }
+ if ((p2 = malloc((int)strlen(s) + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XZXLGI;
+ } else
+ strcpy(p2,s); /* safe */
+ printf("\r\n");
+ if ((rc = cmcfm()) < 0)
+ goto XZXLGI;
+ }
+ sstate = setgen('I',p1,p2,p3); /* Get here with at least user ID */
+ rc = 0;
+
+ XZXLGI: /* Common exit point */
+ if (psaved)
+ cmsetp(psave); /* Restore original prompt */
+ if (p3) { free(p3); p3 = NULL; } /* Free malloc'd storage */
+ if (p2) { free(p2); p2 = NULL; }
+ if (p1) { free(p1); p1 = NULL; }
+ if (rc > -1) {
+ if (local && rc > -1) /* If local, flush tty input buffer */
+ ttflui();
+ }
+ return(rc);
+}
+
+#ifdef OS2
+#ifndef NOLOCAL
+int
+dormt(xx) int xx; {
+ int rc = 0;
+ extern int term_io;
+ int term_io_sav = term_io;
+#ifdef NEWFTP
+ extern int ftpget, ftpisopen();
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(doftprmt(xx,0));
+#endif /* NEWFTP */
+ term_io = 0;
+ rc = xxdormt(xx);
+ term_io = term_io_sav;
+ return rc;
+}
+
+
+int
+xxdormt(xx) int xx;
+#else /* NOLOCAL */
+int
+dormt(xx) int xx;
+#endif /* NOLOCAL */
+#else /* OS2 */
+int
+dormt(xx) int xx;
+#endif /* OS2 */
+{ /* REMOTE commands */
+ int x, y, retcode;
+ char *s, sbuf[50], *s2;
+
+#ifdef NEWFTP
+ extern int ftpget, ftpisopen();
+ if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
+ return(doftprmt(xx,0));
+#endif /* NEWFTP */
+
+ remfile = 0; /* Clear these */
+ rempipe = 0;
+ remappd = 0;
+
+ if (xx < 0) return(xx); /* REMOTE what? */
+
+ xzcmd = xx; /* Make global copy of arg */
+
+ if (xx == XZSET) { /* REMOTE SET */
+ if ((y = cmkey(rmstab,nrms,"","",xxstring)) < 0) {
+ if (y == -3) {
+ printf("?Parameter name required\n");
+ return(-9);
+ } else return(y);
+ }
+ return(doprm(y,1));
+ }
+
+ switch (xx) { /* Others... */
+
+ case XZCDU:
+ if ((x = cmcfm()) < 0) return(x);
+ printf("?Sorry, REMOTE CDUP not supported yet\n");
+ return(-9);
+
+ case XZCWD: /* CWD (CD) */
+ if ((x = cmtxt("Remote directory name","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ debug(F111,"XZCWD: ",s,x);
+ *sbuf = NUL;
+ s2 = sbuf;
+/*
+ The following is commented out because since the disappearance of the
+ DECSYSTEM-20 from the planet, no known computer requires a password for
+ changing directory.
+*/
+#ifdef DIRPWDPR
+ if (*s != NUL) { /* If directory name given, */
+ /* get password on separate line. */
+ if (tlevel > -1) { /* From take file... */
+
+ if (fgets(sbuf,50,tfile[tlevel]) == NULL)
+ fatal("take file ends prematurely in 'remote cwd'");
+ debug(F110," pswd from take file",s2,0);
+ for (x = (int)strlen(sbuf);
+ x > 0 && (sbuf[x-1] == NL || sbuf[x-1] == CR);
+ x--)
+ sbuf[x-1] = '\0';
+
+ } else { /* From terminal... */
+
+ printf(" Password: "); /* get a password */
+#ifdef IKSD
+ if (!local && inserver) {
+ x = coninc(0);
+ } else
+#endif /* IKSD */
+#ifdef OS2
+ x = is_a_tty(0) ? coninc(0) : /* with no echo ... */
+ getchar();
+#else /* OS2 */
+ x = getchar();
+#endif /* OS2 */
+ while ((x != NL) && (x != CR)) {
+ if ((x &= 0177) == '?') {
+ printf("? Password of remote directory\n Password: ");
+ s2 = sbuf;
+ *sbuf = NUL;
+ } else if (x == ESC) /* Mini command line editor... */
+ bleep(BP_WARN);
+ else if (x == BS || x == 0177)
+ s2--;
+ else if (x == 025) { /* Ctrl-U */
+ s2 = sbuf;
+ *sbuf = NUL;
+ } else
+ *s2++ = x;
+
+ /* Get the next character */
+#ifdef IKSD
+ if (!local && inserver) {
+ x = coninc(0);
+ } else
+#endif /* IKSD */
+#ifdef OS2
+ x = is_a_tty(0) ? coninc(0) : /* with no echo ... */
+ getchar();
+#else /* OS2 */
+ x = getchar();
+#endif /* OS2 */
+ }
+ *s2 = NUL;
+ putchar('\n');
+ }
+ s2 = sbuf;
+ } else s2 = "";
+#endif /* DIRPWDPR */
+
+ debug(F110," password",s2,0);
+ rcdactive = 1;
+ sstate = setgen('C',s,s2,"");
+ retcode = 0;
+ break;
+
+ case XZDEL: /* Delete */
+ if ((x = cmtxt("Name of remote file(s) to delete",
+ "",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file(s) required\n");
+ return(-9);
+ } else return(x);
+ }
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ retcode = sstate = rfilop(s,'E');
+ break;
+
+ case XZDIR: /* Directory */
+ if ((x = cmtxt("Remote directory or file specification","",&s,
+ xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ rmsg();
+ retcode = sstate = setgen('D',s,"","");
+ break;
+
+ case XZHLP: /* Help */
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('H',"","","");
+ retcode = 0;
+ break;
+
+ case XZHOS: /* Host */
+ if ((x = cmtxt("Command for remote system","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if ((y = (int)strlen(s)) < 1)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ);
+ cmarg = line;
+ rmsg();
+ retcode = sstate = 'c';
+ break;
+
+#ifndef NOFRILLS
+ case XZKER:
+ if ((x = cmtxt("Command for remote Kermit","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if ((int)strlen(s) < 1) {
+ if (x == -3) {
+ printf("?Remote Kermit command required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ cmarg = line;
+ retcode = sstate = 'k';
+ rmsg();
+ break;
+
+ case XZLGI: /* Login */
+ rcdactive = 1; /* Suppress "Logged in" msg if quiet */
+ return(plogin(XXREM));
+
+ case XZLGO: { /* Logout */
+ extern int bye_active;
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('I',"","","");
+ retcode = 0;
+ bye_active = 1; /* Close connection when done */
+ break;
+ }
+
+ case XZPRI: /* Print */
+ if (!atdiso || !atcapr) { /* Disposition attribute off? */
+ printf("?Disposition Attribute is Off\n");
+ return(-2);
+ }
+ cmarg = "";
+ cmarg2 = "";
+ if ((x = cmifi("Local file(s) to print on remote printer","",&s,&y,
+ xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of local file(s) required\n");
+ return(-9);
+ }
+ return(x);
+ }
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy of filename */
+ *optbuf = NUL; /* Wipe out any old options */
+ if ((x = cmtxt("Options for remote print command","",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if ((int)strlen(optbuf) > 94) { /* Make sure this is legal */
+ printf("?Option string too long\n");
+ return(-9);
+ }
+ ckstrncpy(optbuf,s,OPTBUFLEN); /* Make a safe copy of options */
+ nfils = -1; /* Expand file list internally */
+ cmarg = line; /* Point to file list. */
+ rprintf = 1; /* REMOTE PRINT modifier for SEND */
+ sstate = 's'; /* Set start state to SEND */
+ if (local) displa = 1;
+ retcode = 0;
+ break;
+#endif /* NOFRILLS */
+
+ case XZSPA: /* Space */
+ if ((x = cmtxt("Confirm, or remote directory name",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ retcode = sstate = setgen('U',s,"","");
+ break;
+
+#ifndef NOFRILLS
+ case XZTYP: /* Type */
+ if ((x = cmtxt("Remote file specification","",&s,xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) < 1) {
+ printf("?Remote filename required\n");
+ return(-9);
+ }
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ rmsg();
+ retcode = sstate = rfilop(s,'T');
+ break;
+#endif /* NOFRILLS */
+
+#ifndef NOFRILLS
+ case XZWHO:
+ if ((x = cmtxt("Remote user name, or carriage return",
+ "",&s,xxstring)) < 0)
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ retcode = sstate = setgen('W',s,"","");
+ break;
+#endif /* NOFRILLS */
+
+ case XZPWD: /* PWD */
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('A',"","","");
+ retcode = 0;
+ break;
+
+#ifndef NOSPL
+ case XZQUE: { /* Query */
+ char buf[2];
+ extern char querybuf[], * qbufp;
+ extern int qbufn;
+ if ((y = cmkey(vartyp,nvartyp,"","",xxstring)) < 0)
+ return(y);
+ if ((x = cmtxt(y == 'F' ? "Remote function invocation" :
+ ('K' ? "Remote variable name or function":
+ "Remote variable name"),
+ "",
+ &s,
+ (y == 'K') ? xxstring : NULL
+ )) < 0) /* Don't evaluate */
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ query = 1; /* QUERY is active */
+ qbufp = querybuf; /* Initialize query response buffer */
+ qbufn = 0;
+ querybuf[0] = NUL;
+ buf[0] = (char) (y & 127);
+ buf[1] = NUL;
+ retcode = sstate = setgen('V',"Q",(char *)buf,s);
+ break;
+ }
+
+ case XZASG: { /* Assign */
+ char buf[VNAML];
+ if ((y = cmfld("Remote variable name","",&s,NULL)) < 0) /* No eval */
+ return(y);
+ if ((int)strlen(s) >= VNAML) {
+ printf("?Too long\n");
+ return(-9);
+ }
+ ckstrncpy(buf,s,VNAML);
+ if ((x = cmtxt("Assignment for remote variable",
+ "",&s,xxstring)) < 0) /* Evaluate this one */
+ return(x);
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+#ifdef COMMENT
+/*
+ Server commands can't be long packets. In principle there's no reason
+ why they shouldn't be, except that we don't know at this point if the
+ server is capable of accepting long packets because we haven't started
+ the protocol yet. In practice, allowing a long packet here breaks a lot
+ of assumptions, causes buffer overruns and crashes, etc. To be fixed
+ later. (But since this is commented out, evidently I fixed it later...)
+*/
+ if ((int)strlen(s) > 85) { /* Allow for encoding expansion */
+ printf("?Sorry, value is too long - 85 characters max\n");
+ return(-9);
+ }
+#endif /* COMMENT */
+ retcode = sstate = setgen('V',"S",(char *)buf,s);
+ break;
+ }
+#endif /* NOSPL */
+
+ case XZCPY: { /* COPY */
+ char buf[TMPBUFSIZ];
+ buf[TMPBUFSIZ-1] = '\0';
+ if ((x = cmfld("Name of remote file to copy","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file required\n");
+ return(-9);
+ }
+ else
+ return(x);
+ }
+ ckstrncpy(buf,s,TMPBUFSIZ);
+ if ((x = cmfld("Name of remote destination file or directory",
+ "",&s, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file or directory required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = remcfm()) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ retcode = sstate = setgen('K',buf,tmpbuf,"");
+ break;
+ }
+ case XZREN: { /* Rename */
+ char buf[TMPBUFSIZ];
+ buf[TMPBUFSIZ-1] = '\0';
+ if ((x = cmfld("Name of remote file to rename",
+ "",&s,xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(buf,s,TMPBUFSIZ);
+ if ((x = cmfld("New name of remote file","",&s, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Name of remote file required\n");
+ return(-9);
+ } else return(x);
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ);
+ if ((x = remcfm()) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush device buffer */
+ retcode = sstate = setgen('R',buf,tmpbuf,"");
+ break;
+ }
+ case XZMKD: /* mkdir */
+ case XZRMD: /* rmdir */
+ if ((x = cmtxt((xx == XZMKD) ?
+ "Name of remote directory to create" :
+ "Name of remote directory to delete",
+ "",
+ &s,
+ xxstring
+ )) < 0) {
+ if (x == -3) {
+ printf("?Name required\n");
+ return(-9);
+ } else return(x);
+ }
+ if ((x = remtxt(&s)) < 0)
+ return(x);
+ if (local) ttflui(); /* If local, flush tty input buffer */
+ retcode = sstate = rfilop(s, (char)(xx == XZMKD ? 'm' : 'd'));
+ break;
+
+ case XZXIT: /* Exit */
+ if ((x = remcfm()) < 0) return(x);
+ sstate = setgen('X',"","","");
+ retcode = 0;
+ break;
+
+ default:
+ if ((x = remcfm()) < 0) return(x);
+ printf("?Not implemented - %s\n",cmdbuf);
+ return(-2);
+ }
+ if (local && retcode > -1) /* If local, flush tty input buffer */
+ ttflui();
+ return(retcode);
+}
+
+
+/* R F I L O P -- Remote File Operation */
+
+CHAR
+#ifdef CK_ANSIC
+rfilop(char * s, char t)
+#else
+rfilop(s,t) char *s, t;
+#endif /* CK_ANSIC */
+/* rfilop */ {
+ if (*s == NUL) {
+ printf("?File specification required\n");
+ return((CHAR) 0);
+ }
+ debug(F111,"rfilop",s,t);
+ return(setgen(t,s,"",""));
+}
+#endif /* NOXFER */
+
+#ifdef ANYX25
+int
+setx25() {
+ if ((y = cmkey(x25tab,nx25,"X.25 call options","",xxstring)) < 0)
+ return(y);
+ switch (y) {
+ case XYUDAT:
+ if ((z = cmkey(onoff,2,"X.25 call user data","",xxstring))
+ < 0) return(z);
+ if (z == 0) {
+ if ((z = cmcfm()) < 0) return(z);
+ cudata = 0; /* disable call user data */
+ return (success = 1);
+ }
+ if ((x = cmtxt("X.25 call user data string","",&s,xxstring)) < 0)
+ return(x);
+ if ((int)strlen(s) == 0) {
+ return (-3);
+ } else if ((int)strlen(s) > MAXCUDATA) {
+ printf("?The length must be > 0 and <= %d\n",MAXCUDATA);
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ ckstrncpy(udata,s,MAXCUDATA);
+ cudata = 1; /* X.25 call user data specified */
+ return (success = 1);
+ case XYCLOS:
+ if ((z = cmkey(onoff,2,"X.25 closed user group call","",xxstring))
+ < 0) return(z);
+ if (z == 0) {
+ if ((z = cmcfm()) < 0) return(z);
+ closgr = -1; /* disable closed user group */
+ return (success = 1);
+ }
+ if ((y = cmnum("0 <= cug index >= 99","",10,&x,xxstring)) < 0)
+ return(y);
+ if (x < 0 || x > 99) {
+ printf("?The choices are 0 <= cug index >= 99\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ closgr = x; /* closed user group selected */
+ return (success = 1);
+
+ case XYREVC:
+ if((z = cmkey(onoff,2,"X.25 reverse charge call","",xxstring)) < 0)
+ return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ revcall = z;
+ return (success = 1);
+ }
+}
+
+#ifndef IBMX25
+int
+setpadp() {
+ if ((y = cmkey(padx3tab,npadx3,"PAD X.3 parameter name","",xxstring)) < 0)
+ return(y);
+ x = y;
+ switch (x) {
+ case PAD_BREAK_CHARACTER:
+ if ((y = cmnum("PAD break character value","",10,&z,xxstring)) < 0)
+ return(y);
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_ESCAPE:
+ if ((y = cmnum("PAD escape","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_ECHO:
+ if ((y = cmnum("PAD echo","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_DATA_FORWARD_CHAR:
+ if ((y = cmnum("PAD data forward char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 0 && z != 2) {
+ printf("?The choices are 0 or 2\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_DATA_FORWARD_TIMEOUT:
+ if ((y = cmnum("PAD data forward timeout","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 255) {
+ printf("?The choices are 0 or 1 <= timeout <= 255\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_FLOW_CONTROL_BY_PAD:
+ if ((y = cmnum("PAD pad flow control","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ case PAD_SUPPRESSION_OF_SIGNALS:
+ if ((y = cmnum("PAD service","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_BREAK_ACTION:
+ if ((y = cmnum("PAD break action","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1 && z != 2 && z != 5 && z != 8 && z != 21) {
+ printf("?The choices are 0, 1, 2, 5, 8 or 21\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_SUPPRESSION_OF_DATA:
+ if ((y = cmnum("PAD data delivery","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_PADDING_AFTER_CR:
+ if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 7) {
+ printf("?The choices are 0 or 1 <= crpad <= 7\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_LINE_FOLDING:
+ if ((y = cmnum("PAD linefold","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 255) {
+ printf("?The choices are 0 or 1 <= linefold <= 255\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_LINE_SPEED:
+ if ((y = cmnum("PAD baudrate","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 18) {
+ printf("?The choices are 0 <= baudrate <= 18\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_FLOW_CONTROL_BY_USER:
+ if ((y = cmnum("PAD terminal flow control","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_LF_AFTER_CR:
+ if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z == 3 || z > 7) {
+ printf("?The choices are 0, 1, 2, 4, 5, 6 or 7\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_PADDING_AFTER_LF:
+ if ((y = cmnum("PAD lfpad","",10,&z,xxstring)) < 0) return(y);
+ if (z < 0 || z > 7) {
+ printf("?The choices are 0 or 1 <= lfpad <= 7\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_EDITING:
+ if ((y = cmnum("PAD edit control","",10,&z,xxstring)) < 0) return(y);
+ if (z != 0 && z != 1) {
+ printf("?The choices are 0 or 1\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_CHAR_DELETE_CHAR:
+ if ((y = cmnum("PAD char delete char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 127) {
+ printf("?The choices are 0 or 1 <= chardelete <= 127\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_BUFFER_DELETE_CHAR:
+ if ((y = cmnum("PAD buffer delete char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 127) {
+ printf("?The choices are 0 or 1 <= bufferdelete <= 127\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+
+ case PAD_BUFFER_DISPLAY_CHAR:
+ if ((y = cmnum("PAD display line char","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 0 || z > 127) {
+ printf("?The choices are 0 or 1 <= displayline <= 127\n");
+ return(-2);
+ }
+ if ((y = cmcfm()) < 0) return(y);
+ break;
+ }
+ padparms[x] = z;
+ return(success = 1);
+}
+#endif /* IBMX25 */
+#endif /* ANYX25 */
+
+#ifndef NOXFER
+int
+setat(rmsflg) int rmsflg; {
+ int xx;
+ if ((y = cmkey(attrtab,natr,"File Attribute packets","",xxstring)) < 0)
+ return(y);
+ if (y == AT_XALL) { /* ATTRIBUTES ALL ON or ALL OFF */
+ if ((z = seton(&xx)) < 0) return(z);
+ if (rmsflg) {
+ printf("Sorry, command not available\n");
+ return(-9);
+ } else {
+ atenci = xx; /* Encoding in */
+ atenco = xx; /* Encoding out */
+ atdati = xx; /* Date in */
+ atdato = xx; /* Date out */
+ atdisi = xx; /* Disposition in/out */
+ atdiso = xx;
+ atleni = xx; /* Length in/out (both kinds) */
+ atleno = xx;
+ atblki = xx; /* Blocksize in/out */
+ atblko = xx;
+ attypi = xx; /* File type in/out */
+ attypo = xx;
+ atsidi = xx; /* System ID in/out */
+ atsido = xx;
+ atsysi = xx; /* System-dependent params in/out */
+ atsyso = xx;
+#ifdef CK_PERMS /* Protection */
+ atlpri = xx; /* Local in */
+ atlpro = xx; /* Local out */
+ atgpri = xx; /* Generic in */
+ atgpro = xx; /* Generic out */
+#endif /* CK_PERMS */
+#ifdef STRATUS
+ atfrmi = xx; /* Format in/out */
+ atfrmo = xx;
+ atcrei = xx; /* Creator id in/out */
+ atcreo = xx;
+ atacti = xx; /* Account in/out */
+ atacto = xx;
+#endif /* STRATUS */
+ }
+ return(z);
+ } else if (y == AT_ALLY || y == AT_ALLN) { /* ATTRIBUTES ON or OFF */
+ if ((x = cmcfm()) < 0) return(x);
+ atcapr = (y == AT_ALLY) ? 1 : 0;
+ if (rmsflg) {
+ sstate = setgen('S', "132", atcapr ? "1" : "0", "");
+ return((int) sstate);
+ } else return(success = 1);
+ }
+ /* Otherwise, it's an individual attribute that wants turning off/on */
+
+ if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+
+/* There are better ways to do this... */
+/* The real problem is that we're not separating the in and out cases */
+/* and so we have to arbitrarily pick the "in" case, i.e tell the remote */
+/* server to ignore incoming attributes of the specified type, rather */
+/* than telling it not to send them. The protocol does not (yet) define */
+/* codes for "in-and-out-at-the-same-time". */
+
+ switch (y) {
+#ifdef CK_PERMS
+/* We're lumping local and generic protection together for now... */
+ case AT_LPRO:
+ case AT_GPRO:
+ if (rmsflg) {
+ sstate = setgen('S', "143", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atlpri = atlpro = atgpri = atgpro = z; break;
+#endif /* CK_PERMS */
+ case AT_DISP:
+ if (rmsflg) {
+ sstate = setgen('S', "142", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atdisi = atdiso = z; break;
+ case AT_ENCO:
+ if (rmsflg) {
+ sstate = setgen('S', "141", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atenci = atenco = z; break;
+ case AT_DATE:
+ if (rmsflg) {
+ sstate = setgen('S', "135", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atdati = atdato = z; break;
+ case AT_LENB:
+ case AT_LENK:
+ if (rmsflg) {
+ sstate = setgen('S', "133", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atleni = atleno = z; break;
+ case AT_BLKS:
+ if (rmsflg) {
+ sstate = setgen('S', "139", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atblki = atblko = z; break;
+ case AT_FTYP:
+ if (rmsflg) {
+ sstate = setgen('S', "134", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ attypi = attypo = z; break;
+#ifdef STRATUS
+ case AT_CREA:
+ if (rmsflg) {
+ sstate = setgen('S', "136", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atcrei = atcreo = z; break;
+ case AT_ACCT:
+ if (rmsflg) {
+ sstate = setgen('S', "137", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atacti = atacto = z; break;
+#endif /* STRATUS */
+ case AT_SYSI:
+ if (rmsflg) {
+ sstate = setgen('S', "145", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atsidi = atsido = z; break;
+ case AT_RECF:
+ if (rmsflg) {
+ sstate = setgen('S', "146", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atfrmi = atfrmo = z; break;
+ case AT_SYSP:
+ if (rmsflg) {
+ sstate = setgen('S', "147", z ? "1" : "0", "");
+ return((int) sstate);
+ }
+ atsysi = atsyso = z; break;
+ default:
+ printf("?Not available\n");
+ return(-2);
+ }
+ return(1);
+}
+#endif /* NOXFER */
+
+#ifndef NOSPL
+int
+setinp() {
+ if ((y = cmkey(inptab,ninp,"","",xxstring)) < 0) return(y);
+ switch (y) {
+#ifdef OS2
+ case IN_PAC: /* SET INPUT PACING */
+ z = cmnum("milliseconds","0",10,&x,xxstring);
+ return(setnum(&tt_inpacing,x,z,1000));
+ case IN_TRM: /* SET INPUT TERMINAL */
+ return(seton(&interm));
+#endif /* OS2 */
+ case IN_DEF: /* SET INPUT DEFAULT-TIMEOUT */
+ z = cmnum("Positive number","",10,&x,xxstring);
+ return(setnum(&indef,x,z,94));
+#ifdef CKFLOAT
+ case IN_SCA: /* SET INPUT SCALE-FACTOR */
+ if ((x = cmfld("Number such as 2 or 0.5","1.0",&s, xxstring)) < 0)
+ return(x);
+ if (isfloat(s,0)) { /* A floating-point number? */
+ extern char * inpscale;
+ inscale = floatval; /* Yes, get its value */
+ makestr(&inpscale,s); /* Save it as \v(inscale) */
+ return(success = 1);
+ } else {
+ return(-2);
+ }
+#endif /* CKFLOAT */
+ case IN_TIM: /* SET INPUT TIMEOUT-ACTION */
+ if ((z = cmkey(intimt,2,"","",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ intime[cmdlvl] = z;
+ return(success = 1);
+ case IN_CAS: /* SET INPUT CASE */
+ if ((z = cmkey(incast,2,"","",xxstring)) < 0) return(z);
+ if ((x = cmcfm()) < 0) return(x);
+ inpcas[cmdlvl] = z;
+ return(success = 1);
+ case IN_ECH: /* SET INPUT ECHO */
+ return(seton(&inecho));
+ case IN_SIL: /* SET INPUT SILENCE */
+ z = cmnum("Seconds of inactivity before INPUT fails","",10,&x,
+ xxstring);
+ return(setnum(&insilence,x,z,-1));
+
+ case IN_BUF: /* SET INPUT BUFFER-SIZE */
+ if ((z = cmnum("Number of bytes in INPUT buffer",
+ ckitoa(INPBUFSIZ),10,&x, xxstring)) < 0)
+ return(z);
+ if ((y = cmcfm()) < 0) return(y);
+ inbufsize = 0;
+ if (inpbuf) {
+ free(inpbuf);
+ inpbuf = NULL;
+ inpbp = NULL;
+ }
+ if (!(s = (char *)malloc(x + 1)))
+ return(0);
+ inpbuf = s;
+ inpbp = s;
+ inbufsize = x;
+ for (x = 0; x <= inbufsize; x++)
+ inpbuf[x] = NUL;
+ return(success = 1);
+
+#ifdef CK_AUTODL
+ case IN_ADL: /* AUTODOWNLOAD */
+ return(seton(&inautodl));
+#endif /* CK_AUTODL */
+
+ case IN_CAN: /* SET INPUT INTERRUPTS */
+ return(seton(&inintr));
+ }
+ return(0);
+}
+#endif /* NOSPL */
+
+#ifdef NETCONN
+VOID
+ndreset() {
+#ifndef NODIAL /* This depends on DIAL... */
+ int i=0, j=0;
+ if (!ndinited) /* Don't free garbage... */
+ return;
+ for (i = 0; i < nhcount; i++) { /* Clean out previous list */
+ if (nh_p[i])
+ free(nh_p[i]);
+ nh_p[i] = NULL;
+ if (nh_p2[i])
+ free(nh_p2[i]);
+ nh_p2[i] = NULL;
+ for (j = 0; j < 4; j++) {
+ if (nh_px[j][i])
+ free(nh_px[j][i]);
+ nh_px[j][i] = NULL;
+ }
+ }
+#endif /* NODIAL */
+}
+
+VOID
+ndinit() { /* Net directory pointers */
+#ifndef NODIAL /* This depends on DIAL... */
+ int i, j;
+ if (ndinited++) /* Don't do this more than once. */
+ return;
+ for (i = 0; i < MAXDDIR; i++) { /* Init all pointers to NULL */
+ netdir[i] = NULL;
+ }
+ for (i = 0; i < MAXDNUMS; i++) {
+ nh_p[i] = NULL;
+ nh_p2[i] = NULL;
+ for (j = 0; j < 4; j++)
+ nh_px[j][i] = NULL;
+ }
+#endif /* NODIAL */
+}
+
+#ifndef NODIAL
+#ifdef NETCONN
+VOID /* Get net defaults from environment */
+getnetenv() {
+ char *p = NULL;
+
+ makestr(&p,getenv("K_NET_DIRECTORY")); /* Dialing directories */
+ if (p) {
+ int i;
+ xwords(p,MAXDDIR,netdir,0);
+ for (i = 0; i < MAXDDIR; i++) { /* Fill in any gaps... */
+ if (!netdir[i+1])
+ break;
+ else
+ netdir[i] = netdir[i+1];
+ debug(F111,"netdir[i]",netdir[i],i);
+ }
+ nnetdir = i;
+ }
+}
+#endif /* NETCONN */
+#endif /* NODIAL */
+
+int
+#ifdef CK_ANSIC
+lunet(char *s) /* s = name to look up */
+#else
+lunet(s) char *s;
+#endif /* CK_ANSIC */
+/* lunet */ {
+#ifndef NODIAL /* This depends on DIAL... */
+ int n, n1, t, dd = 0;
+ int ambiguous = 0;
+ FILE * f;
+ char *line = NULL;
+ extern int dialdpy;
+ int netdpy = dialdpy;
+ char *info[8];
+
+ nhcount = 0; /* Set this before returning */
+
+ if (!s || nnetdir < 1) /* Validate arguments */
+ return(-1);
+
+ if (isdigit(*s) || *s == '*' || *s == '.')
+ return(0);
+
+ if ((n1 = (int) strlen(s)) < 1) /* Length of string to look up */
+ return(-1);
+
+ if (!(line = malloc(1024))) /* Allocate input buffer */
+ return(-1);
+
+ lu_again:
+ f = NULL; /* Network directory file descriptor */
+ t = nhcount = 0; /* Match count */
+ dd = 0; /* Directory counter */
+
+ dirline = 0;
+ while (1) { /* We make one pass */
+ if (!f) { /* Directory not open */
+ if (dd >= nnetdir) /* No directories left? */
+ break; /* Done. */
+ if ((f = fopen(netdir[dd],"r")) == NULL) { /* Open it */
+ perror(netdir[dd]); /* Can't, print message saying why */
+ dd++;
+ continue; /* But go on to next one. */
+ }
+ if (netdpy)
+ printf("Opening %s...\n",netdir[dd]);
+ dd++;
+ }
+ line[0] = NUL;
+ if (getnct(line,1023,f,1) < 0) { /* Read a line */
+ if (f) { /* f can be clobbered! */
+ fclose(f); /* Close the file */
+ f = NULL; /* Indicate next one needs opening */
+ }
+ continue;
+ }
+ if (!line[0]) /* Empty line */
+ continue;
+
+ xwords(line,7,info,0); /* Parse it */
+
+ if (!info[1] || !info[2] || !info[3]) /* Required fields */
+ continue;
+ if (*info[1] == ';') /* Full-line comment */
+ continue;
+ if ((n = (int) strlen(info[1])) < 1) /* Length of name-tag */
+ continue;
+ if (n < n1) /* Search name is longer */
+ continue; /* Can't possibly match */
+ if (ambiguous && n != n1)
+ continue;
+ if (ckstrcmp(s,info[1],n1,0)) /* Compare using length of */
+ continue; /* search string s. */
+
+ /* Have a match */
+
+ makestr(&(nh_p[nhcount]), info[3]); /* address */
+ makestr(&(nh_p2[nhcount]),info[2]); /* net type */
+ makestr(&(nh_px[0][nhcount]),info[4]); /* net-specific stuff... */
+ makestr(&(nh_px[1][nhcount]),info[5]);
+ makestr(&(nh_px[2][nhcount]),info[6]);
+ makestr(&(nh_px[3][nhcount]),info[7]);
+
+ nhcount++; /* Count this match */
+ if (nhcount > MAXDNUMS) { /* Watch out for too many */
+ printf("Warning: %d matches found, %d max\n",
+ nhcount,
+ MAXDNUMS
+ );
+ nhcount = MAXDNUMS;
+ break;
+ }
+ if (nhcount == 1) { /* First one - save entry name */
+ if (n_name) { /* Free the one from before if any */
+ free(n_name);
+ n_name = NULL;
+ }
+ if (!(n_name = (char *)malloc(n + 1))) { /* Allocate new storage */
+ printf("?memory allocation error - lunet:3\n");
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ nhcount = 0;
+ return(-1);
+ }
+ t = n; /* Remember its length */
+ strcpy(n_name,info[1]); /* safe */
+ } else { /* Second or subsequent one */
+ if ((int) strlen(info[1]) == t) /* Lengths compare */
+ if (!ckstrcmp(n_name,info[1],t,0)) /* Caseless compare OK */
+ continue;
+
+ /* Name given by user matches entries with different names */
+
+ if (ambiguous) /* Been here before */
+ break;
+
+ ambiguous = 1; /* Now an exact match is required */
+ ndreset(); /* Clear out previous list */
+ goto lu_again; /* Do it all over again. */
+ }
+ }
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ if (nhcount == 0 && ambiguous)
+ printf("?\"%s\" - ambiguous in network directory\n",s);
+#else
+ nhcount = 0;
+#endif /* NODIAL */
+ return(nhcount);
+}
+#endif /* NETCONN */
+
+#ifndef NOLOCAL
+/* C L S C O N N X -- Close connection */
+
+int
+clsconnx(ask) int ask; {
+ int x, rc = 0;
+#ifdef NEWFTP
+ extern int ftpget, ftpisopen(), ftpbye();
+ if ((ftpget == 1) || ((ftpget == 2) && !local && ftpisopen()))
+ return(success = ftpbye());
+#endif /* NEWFTP */
+ debug(F101,"clsconnx local","",local);
+ if (local) {
+ x = ask ? hupok(1) : 1; /* Make sure it's OK to close */
+ if (!x) {
+ rc = -1;
+ debug(F101,"clsconnx hupok says no","",rc);
+ return(rc);
+ }
+ ttflui(); /* Clear away buffered up junk */
+#ifndef NODIAL
+#ifdef OS2ONLY
+/* Don't hangup a line that is shared with the SLIP or PPP driver */
+ if (!ttslip && !ttppp)
+#endif /* OS2ONLY */
+ mdmhup();
+#endif /* NODIAL */
+ if (network && msgflg)
+ printf(" Closing connection\n");
+ ttclos(0); /* Close old connection, if any */
+ rc = 1;
+ {
+ extern int wasclosed, whyclosed;
+ if (wasclosed) {
+ whyclosed = WC_CLOS;
+#ifndef NOSPL
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ /* printf("ON_CLOSE CLSCONNX\n"); */
+ wasclosed = 0;
+ k = mlook(mactab,"on_close",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+#endif /* NOSPL */
+ whyclosed = WC_REMO;
+ wasclosed = 0;
+ }
+ }
+ }
+#ifdef VMS /* Or maybe #ifndef UNIX? */
+ else { /* Need to do this in VMS to */
+ ttclos(0); /* free the tty channel number */
+ rc = 1; /* obtained in ttopen() or else */
+ } /* subsequent ttopen's won't work */
+#endif /* VMS */
+ dologend();
+ haveline = 0;
+ if (mdmtyp < 0) { /* Switching from net to async? */
+ if (mdmsav > -1) /* Restore modem type from last */
+ mdmtyp = mdmsav; /* SET MODEM command, if any. */
+ else
+ mdmtyp = 0;
+ mdmsav = -1;
+ }
+ if (network)
+ network = 0;
+#ifdef NETCONN
+ if (oldplex > -1) { /* Restore previous duplex setting. */
+ duplex = oldplex;
+ oldplex = -1;
+ }
+#endif /* NETCONN */
+#ifndef MAC
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default communication */
+#endif /* MAC */
+ local = dfloc; /* device and local/remote status */
+ if (local) {
+ cxtype = CXT_DIRECT; /* Something reasonable */
+ speed = ttgspd(); /* Get the current speed */
+ } else {
+ cxtype = CXT_REMOTE;
+ speed = -1L;
+ }
+#ifndef NOXFER
+ if (xreliable > -1 && !setreliable) {
+ reliable = xreliable;
+ debug(F101,"clsconnx reliable A","",reliable);
+ } else if (!setreliable) {
+ reliable = SET_AUTO;
+ debug(F101,"clsconnx reliable B","",reliable);
+ }
+#endif /* NOXFER */
+ setflow(); /* Revert flow control */
+ return(rc);
+}
+
+int
+clskconnx(x) int x; { /* Close Kermit connection only */
+ int t, rc; /* (not FTP) */
+#ifdef NEWFTP
+ extern int ftpget;
+ t = ftpget;
+ ftpget = 0;
+#endif /* NEWFTP */
+ rc = clsconnx(x);
+#ifdef NEWFTP
+ ftpget = t;
+#endif /* NEWFTP */
+ return(rc);
+}
+
+/* May 2002: setlin() decomposition starts here ... */
+
+#ifdef OS2
+#define SRVBUFSIZ PIPENAML
+#else /* OS2 */
+#define SRVBUFSIZ 63
+#endif /* OS2 */
+#define HOSTNAMLEN 15*65
+
+int netsave = -1;
+static char * tmpstring = NULL;
+static char * tmpusrid = NULL;
+
+#ifdef SSHCMD
+char * sshcmd = NULL;
+char * defsshcmd = "ssh -e none";
+#else
+#ifdef SSHBUILTIN
+char * sshrcmd = NULL;
+char * sshtmpcmd = NULL;
+#endif /* SSHBUILTIN */
+#endif /* SSHCMD */
+
+/* c x _ f a i l -- Common error exit routine for cx_net, cx_line */
+
+int
+cx_fail(msg, text) int msg; char * text; {
+ makestr(&slmsg,text); /* For the record (or GUI) */
+ if (msg) /* Not GUI, not quiet, etc */
+ printf("?%s\n",text); /* Print error message */
+ slrestor(); /* Restore LINE/HOST to known state */
+ return(msg ? -9 : (success = 0)); /* Return appropriate code */
+}
+
+#ifdef NETCONN
+/* c x _ n e t -- Make a network connection */
+
+/*
+ Call with:
+ net = network type
+ protocol = protocol type
+ host = string pointer to host name.
+ svc = string pointer to service or port on host.
+ username = username for connection
+ password = password for connection
+ command = command to execute
+ param1 = Telnet: Authentication type
+ SSH: Version
+ param2 = Telnet: Encryption type
+ SSH: Command as Subsystem
+ param3 = Telnet: 1 to wait for negotiations, 0 otherwise
+ SSH: X11 Forwarding
+ cx = 1 to automatically enter Connect mode, 0 otherwise.
+ sx = 1 to automatically enter Server mode, 0 otherwise.
+ flag = if no host name given, 1 = close current connection, 0 = resume
+ gui = 1 if called from GUI dialog, 0 otherwise.
+ Returns:
+ 1 on success
+ 0 on failure and no message printed, slmsg set to failure message.
+ -9 on failure and message printed, ditto.
+*/
+int
+#ifdef CK_ANSIC
+cx_net( int net, int protocol, char * xhost, char * svc,
+ char * username, char * password, char * command,
+ int param1, int param2, int param3, int cx, int sx, int flag, int gui)
+#else /* CK_ANSIC */
+cx_net(net, protocol, xhost, svc,
+ username, password, command,
+ param1, param2, param3, cx, sx, flag, gui)
+ char * xhost, * svc, * username, *password, *command;
+ int net, protocol, cx, sx, flag, param1, param2, param3, gui;
+#endif /* CK_ANSIC */
+/* cx_net */ {
+
+ int i, n, x, msg;
+ int _local = -1;
+
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+
+ char srvbuf[SRVBUFSIZ+1]; /* Service */
+ char hostbuf[HOSTNAMLEN]; /* Host buffer to manipulate */
+ char hostname[HOSTNAMLEN]; /* Copy of host parameter */
+ char * host = hostbuf; /* Pointer to copy of host param */
+
+ if (!xhost) xhost = ""; /* Watch out for null pointers */
+ if (!svc) svc = "";
+ ckstrncpy(host,xhost,HOSTNAMLEN); /* Avoid buffer confusion */
+
+ debug(F110,"cx_net host",host,0);
+ debug(F111,"cx_net service",svc,SRVBUFSIZ);
+ debug(F101,"cx_net network type","",net);
+
+ msg = (gui == 0) && msgflg; /* Whether to print messages */
+
+#ifndef NODIAL
+ debug(F101,"cx_net nnetdir","",nnetdir);
+ x = 0; /* Look up in network directory */
+ if (*host == '=') { /* If number starts with = sign */
+ host++; /* strip it */
+ while (*host == SP) host++; /* and any leading spaces */
+ debug(F110,"cx_net host 2",host,0);
+ nhcount = 0;
+ } else if (*host) { /* We want to look it up. */
+ if (nnetdir > 0) /* If there is a directory... */
+ x = lunet(host); /* (sets nhcount) */
+ else /* otherwise */
+ nhcount = 0; /* we didn't find any there */
+ if (x < 0) /* Internal error? */
+ return(cx_fail(msg,"Network directory lookup error"));
+ debug(F111,"cx_net lunet nhcount",host,nhcount);
+ }
+#endif /* NODIAL */
+
+ /* New connection wanted. Make a copy of the host name/address... */
+
+ if (clskconnx(1) < 0) /* Close current Kermit connection */
+ return(cx_fail(msg,"Error closing previous connection"));
+
+ if (*host) { /* They gave a hostname */
+ _local = 1; /* Network connection always local */
+ if (mdmsav < 0)
+ mdmsav = mdmtyp; /* Remember old modem type */
+ mdmtyp = -net; /* Special code for network */
+ } else { /* They just said "set host" */
+ host = dftty; /* So go back to normal */
+ _local = dfloc; /* default tty, location, */
+ if (flag) { /* Close current connection */
+ setflow(); /* Maybe change flow control */
+ haveline = 1; /* (* is this right? *) */
+ dologend();
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ /* XXX - Is this right? */
+ /* Should we be returning without doing anything ? */
+ /* Yes it's right -- we closed the old connection just above. */
+ return(success = 1);
+ }
+ }
+ success = 0;
+ if (host != line) /* line[] is a global */
+ ckstrncpy(line,host,LINBUFSIZ);
+ ckstrncpy(hostname,host,HOSTNAMLEN);
+ ckstrncpy(srvbuf,svc,SRVBUFSIZ+1);
+
+#ifndef NODIAL
+ if ((nhcount > 1) && msg) {
+ int k;
+ printf("%d entr%s found for \"%s\"%s\n",
+ nhcount,
+ (nhcount == 1) ? "y" : "ies",
+ s,
+ (nhcount > 0) ? ":" : "."
+ );
+ for (i = 0; i < nhcount; i++) {
+ printf("%3d. %-12s => %-9s %s",
+ i+1,n_name,nh_p2[i],nh_p[i]);
+ for (k = 0; k < 4; k++) { /* Also list net-specific items */
+ if (nh_px[k][i]) /* free format... */
+ printf(" %s",nh_px[k][i]);
+ else
+ break;
+ }
+ printf("\n");
+ }
+ }
+ if (nhcount == 0)
+ n = 1;
+ else
+ n = nhcount;
+#else
+ n = 1;
+ nhcount = 0;
+#endif /* NODIAL */
+
+ for (i = 0; i < n; i++) { /* Loop for each entry found */
+ debug(F101,"cx_net loop i","",i);
+#ifndef NODIAL
+ if (nhcount > 0) { /* If we found at least one entry... */
+ ckstrncpy(line,nh_p[i],LINBUFSIZ); /* Copy current entry */
+ if (lookup(netcmd,nh_p2[i],nnets,&x) > -1) { /* Net type */
+ int xx;
+ xx = netcmd[x].kwval;
+ /* User specified SSH so don't let net directory override */
+ if (net != NET_SSH || xx != NET_TCPB) {
+ net = xx;
+ mdmtyp = 0 - net;
+ }
+ } else {
+ makestr(&slmsg,"Network type not supported");
+ if (msg)
+ printf("Error - network type \"%s\" not supported\n",
+ nh_p2[i]
+ );
+ continue;
+ }
+ switch (net) { /* Net-specific directory things */
+#ifdef SSHBUILTIN
+ case NET_SSH: /* SSH */
+ /* Any SSH specific network directory stuff? */
+ break; /* NET_SSH */
+#endif /* SSHBUILTIN */
+
+ case NET_TCPB: { /* TCP/IP TELNET,RLOGIN,... */
+#ifdef TCPSOCKET
+ char *q;
+ int flag = 0;
+
+ /* Extract ":service", if any, from host string */
+ debug(F110,"cx_net service 1",line,0);
+ for (q = line; (*q != '\0') && (*q != ':'); q++)
+ ;
+ if (*q == ':') { *q++ = NUL; flag = 1; }
+ debug(F111,"cx_net service 2",line,flag);
+
+ /* Get service, if any, from directory entry */
+
+ if (!*srvbuf) {
+ if (nh_px[0][i]) {
+ ckstrncpy(srvbuf,nh_px[0][i],SRVBUFSIZ);
+ debug(F110,"cx_net service 3",srvbuf,0);
+ }
+ if (flag) {
+ ckstrncpy(srvbuf,q,SRVBUFSIZ);
+ debug(F110,"cx_net service 4",srvbuf,0);
+ }
+ }
+ ckstrncpy(hostname,line,HOSTNAMLEN);
+
+ /* If we have a service, append to host name/address */
+ if (*srvbuf) {
+ ckstrncat(line, ":", LINBUFSIZ);
+ ckstrncat(line, srvbuf, LINBUFSIZ);
+ debug(F110,"cx_net service 5",line,0);
+ }
+#ifdef RLOGCODE
+ /* If no service given but command was RLOGIN */
+ else if (ttnproto == NP_RLOGIN) { /* add this... */
+ ckstrncat(line, ":login",LINBUFSIZ);
+ debug(F110,"cx_net service 6",line,0);
+ }
+#ifdef CK_AUTHENTICATION
+#ifdef CK_KERBEROS
+ else if (ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_K5LOGIN) { /* add this... */
+ ckstrncat(line, ":klogin",LINBUFSIZ);
+ debug(F110,"cx_net service 7",line,0);
+ }
+ else if (ttnproto == NP_EK4LOGIN ||
+ ttnproto == NP_EK5LOGIN) { /* add this... */
+ ckstrncat(line, ":eklogin",LINBUFSIZ);
+ debug(F110,"cx_net service 8",line,0);
+ }
+#endif /* CK_KERBEROS */
+#endif /* CK_AUTHENTICATION */
+#endif /* RLOGCODE */
+ else { /* Otherwise, add ":telnet". */
+ ckstrncat(line, ":telnet", LINBUFSIZ);
+ debug(F110,"cx_net service 9",line,0);
+ }
+ if (username) { /* This is a parameter... */
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+ uidflag = 1;
+ }
+ /* Fifth field, if any, is user ID (for rlogin) */
+
+ if (nh_px[1][i] && !uidflag)
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+#ifdef RLOGCODE
+ if (IS_RLOGIN() && !uidbuf[0])
+ return(cx_fail(msg,"Username required"));
+#endif /* RLOGCODE */
+#endif /* TCPSOCKET */
+ break;
+ }
+ case NET_PIPE: /* Pipe */
+#ifdef NPIPE
+ if (!pipename[0]) { /* User didn't give a pipename */
+ if (nh_px[0][i]) { /* But directory entry has one */
+ if (strcmp(pipename,"\\pipe\\")) {
+ ckstrncpy(pipename,"\\pipe\\",LINBUFSIZ);
+ ckstrncat(srvbuf,nh_px[0][i],PIPENAML-6);
+ } else {
+ ckstrncpy(pipename,nh_px[0][i],PIPENAML);
+ }
+ debug(F110,"cx_net pipeneme",pipename,0);
+ }
+ }
+#endif /* NPIPE */
+ break;
+
+ case NET_SLAT: /* LAT / CTERM */
+#ifdef SUPERLAT
+ if (!slat_pwd[0]) { /* User didn't give a password */
+ if (nh_px[0][i]) { /* But directory entry has one */
+ ckstrncpy(slat_pwd,nh_px[0][i],18);
+ debug(F110,"cx_net SuperLAT password",slat_pwd,0);
+ }
+ }
+#endif /* SUPERLAT */
+ break;
+
+ case NET_SX25: /* X.25 keyword parameters */
+ case NET_IX25:
+ case NET_VX25: {
+#ifdef ANYX25
+ int k; /* Cycle through the four fields */
+ for (k = 0; k < 4; k++) {
+ if (!nh_px[k][i]) /* Bail out if none left */
+ break;
+ if (!ckstrcmp(nh_px[k][i],"cug=",4,0)) {
+ closgr = atoi(nh_px[k][i]+4);
+ debug(F101,"X25 CUG","",closgr);
+ } else if (!ckstrcmp(nh_px[k][i],"cud=",4,0)) {
+ cudata = 1;
+ ckstrncpy(udata,nh_px[k][i]+4,MAXCUDATA);
+ debug(F110,"X25 CUD",cudata,0);
+ } else if (!ckstrcmp(nh_px[k][i],"rev=",4,0)) {
+ revcall = !ckstrcmp(nh_px[k][i]+4,"=on",3,0);
+ debug(F101,"X25 REV","",revcall);
+#ifndef IBMX25
+ } else if (!ckstrcmp(nh_px[k][i],"pad=",4,0)) {
+ int x3par, x3val;
+ char *s1, *s2;
+ s1 = s2 = nh_px[k][i]+4; /* PAD parameters */
+ while (*s2) { /* Pick them apart */
+ if (*s2 == ':') {
+ *s2 = NUL;
+ x3par = atoi(s1);
+ s1 = ++s2;
+ continue;
+ } else if (*s2 == ',') {
+ *s2 = NUL;
+ x3val = atoi(s1);
+ s1 = ++s2;
+ debug(F111,"X25 PAD",x3par,x3val);
+ if (x3par > -1 &&
+ x3par <= MAXPADPARMS)
+ padparms[x3par] = x3val;
+ continue;
+ } else
+ s2++;
+ }
+#endif /* IBMX25 */
+ }
+ }
+#endif /* ANYX25 */
+ break;
+ }
+ default: /* Nothing special for other nets */
+ break;
+ }
+ } else
+#endif /* NODIAL */
+ { /* No directory entries found. */
+ ckstrncpy(line,hostname,LINBUFSIZ); /* Put this back... */
+ /* If the user gave a TCP service */
+ if (net == NET_TCPB || net == NET_SSH)
+ if (*srvbuf) { /* Append it to host name/address */
+ ckstrncat(line, ":", LINBUFSIZ);
+ ckstrncat(line, srvbuf,LINBUFSIZ);
+ }
+ }
+ /*
+ Get here with host name/address and all net-specific
+ parameters set, ready to open the connection.
+ */
+ mdmtyp = -net; /* This should have been done */
+ /* already but just in case ... */
+
+ debug(F110,"cx_net net line[] before ttopen",line,0);
+ debug(F101,"cx_net net mdmtyp before ttopen","",mdmtyp);
+ debug(F101,"cx_net net ttnproto","",ttnproto);
+
+#ifdef SSHBUILTIN
+ if (net == NET_SSH) {
+ makestr(&ssh_hst,hostname); /* Stash everything */
+ if (username) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+ }
+ if (srvbuf[0]) {
+ makestr(&ssh_prt,srvbuf);
+ } else
+ makestr(&ssh_prt,NULL);
+
+ if (command) {
+ makestr(&ssh_cmd,brstrip(command));
+ ssh_cas = param2;
+ } else
+ makestr(&ssh_cmd,NULL);
+
+ if (param1 > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_ver_saved) {
+ sl_ssh_ver = ssh_ver;
+ sl_ssh_ver_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_ver = param1;
+ }
+ if (param3 > -1) {
+#ifndef SSHTEST
+ if (!sl_ssh_xfw_saved) {
+ sl_ssh_xfw = ssh_xfw;
+ sl_ssh_xfw_saved = 1;
+ }
+#endif /* SSHTEST */
+ ssh_xfw = param3;
+ }
+ } else /* NET_SSH */
+#endif /* SSHBUILTIN */
+#ifdef TCPSOCKET
+ if (net == NET_TCPB) {
+ switch (protocol) {
+#ifdef CK_SSL
+ case NP_SSL:
+ ttnproto = protocol;
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS:
+ ttnproto = protocol;
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+
+ case NP_SSL_TELNET:
+ ttnproto = NP_TELNET;
+ ssl_only_flag = 1;
+ tls_only_flag = 0;
+ break;
+
+ case NP_TLS_TELNET:
+ ttnproto = NP_TELNET;
+ ssl_only_flag = 0;
+ tls_only_flag = 1;
+ break;
+#endif /* CK_SSL */
+ case NP_NONE:
+ case NP_TCPRAW:
+ case NP_RLOGIN:
+ case NP_K4LOGIN:
+ case NP_K5LOGIN:
+ case NP_EK4LOGIN:
+ case NP_EK5LOGIN:
+ case NP_TELNET:
+ case NP_KERMIT:
+ default:
+ ttnproto = protocol;
+#ifdef CK_SSL
+ ssl_only_flag = 0;
+ tls_only_flag = 0;
+#endif /* CK_SSL */
+ break;
+ }
+#ifdef CK_AUTHENTICATION
+ if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ param1 > -1) {
+ if (!sl_auth_saved) {
+ int x;
+ for (x = 0; x < AUTHTYPLSTSZ; x++)
+ sl_auth_type_user[x] = auth_type_user[x];
+ sl_auth_saved = 1;
+ }
+ if (!sl_topt_a_s_saved) {
+ sl_topt_a_su = TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION);
+ sl_topt_a_s_saved = 1;
+ }
+ if (!sl_topt_a_c_saved) {
+ sl_topt_a_cm = TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION);
+ sl_topt_a_c_saved = 1;
+ }
+ switch (param1) {
+ case AUTHTYPE_AUTO:
+ auth_type_user[0] = AUTHTYPE_AUTO;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
+ break;
+ case AUTHTYPE_NULL:
+ auth_type_user[0] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
+ break;
+#ifdef CK_SRP
+ case AUTHTYPE_SRP:
+ auth_type_user[0] = AUTHTYPE_SRP;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ case AUTHTYPE_SSL:
+ auth_type_user[0] = AUTHTYPE_SSL;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* CK_SSL */
+#ifdef NT
+ case AUTHTYPE_NTLM:
+ auth_type_user[0] = AUTHTYPE_NTLM;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* NT */
+#ifdef CK_KERBEROS
+ case AUTHTYPE_KERBEROS_V4:
+ auth_type_user[0] = AUTHTYPE_KERBEROS_V4;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+
+ case AUTHTYPE_KERBEROS_V5:
+ auth_type_user[0] = AUTHTYPE_KERBEROS_V5;
+ auth_type_user[1] = AUTHTYPE_NULL;
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
+ break;
+#endif /* CK_KERBEROS */
+ }
+ }
+ /*
+ If the user requires a particular type of Kerberos connection,
+ make sure we have a valid TGT.
+ */
+ makestr(&slmsg,"Authentication failure");
+ if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ (line[0] == '*' &&
+ TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU ||
+ line[0] != '*' &&
+ TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU)
+ ) {
+#ifdef CK_KERBEROS
+ if ( auth_type_user[0] == AUTHTYPE_KERBEROS_V4 ) {
+ extern int krb4_autoget;
+ if (!ck_krb4_is_installed())
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 4) is not installed"));
+#ifdef COMMENT
+ /* This code results in false failures when using */
+ /* kerberos to machines in realms other than the */
+ /* default since we don't know the realm of the */
+ /* other machine until perform the reverse DNS */
+ /* lookup. */
+ else if (line[0] != '*' && !ck_krb4_is_tgt_valid() &&
+ (!krb4_autoget ||
+ krb4_autoget && !ck_krb4_autoget_TGT(NULL))) {
+ return(cx_fail(msg,
+ "Kerberos 4: Ticket Getting Ticket not valid"));
+ }
+#endif /* COMMENT */
+ } else if (auth_type_user[0] == AUTHTYPE_KERBEROS_V5) {
+ extern int krb5_autoget;
+ if (!ck_krb5_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 5) is not installed"));
+ }
+#ifdef COMMENT
+ /* This code results in false failures when using */
+ /* kerberos to machines in realms other than the */
+ /* default since we don't know the realm of the */
+ /* other machine until perform the reverse DNS */
+ /* lookup. */
+ else if (line[0] != '*' && !ck_krb5_is_tgt_valid() &&
+ (!krb5_autoget ||
+ krb5_autoget && !ck_krb5_autoget_TGT(NULL))) {
+ return(cx_fail(msg,
+ "Kerberos 5: Ticket Getting Ticket not valid."));
+ }
+#endif /* COMMENT */
+ }
+#endif /* CK_KERBEROS */
+#ifdef NT
+ if (auth_type_user[0] == AUTHTYPE_NTLM) {
+ if (!ck_ntlm_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (NTLM) is not installed"));
+ } else if (line[0] != '*' && !ck_ntlm_is_valid(0)) {
+ return(cx_fail(msg,"NTLM: Credentials are unavailable."));
+ }
+ }
+#endif /* NT */
+#ifdef CK_SSL
+ if (auth_type_user[0] == AUTHTYPE_SSL) {
+ if (!ck_ssleay_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (SSL) is not installed"));
+ }
+ }
+#endif /* CK_SSL */
+#ifdef CK_SRP
+ if (auth_type_user[0] == AUTHTYPE_SRP) {
+ if (!ck_srp_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (SRP) is not installed"));
+ }
+ }
+#endif /* CK_SRP */
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ param2 > -1) {
+ if (!sl_cx_saved) {
+ sl_cx_type = cx_type;
+ sl_cx_saved = 1;
+ }
+ if (!sl_topt_e_s_saved) {
+ sl_topt_e_su = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_sm = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_s_saved = 1;
+ }
+ if (!sl_topt_e_c_saved) {
+ sl_topt_e_cu = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_cm = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION);
+ sl_topt_e_c_saved = 1;
+ }
+ cx_type = param2;
+ if (cx_type == CX_AUTO) {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
+ } else if (cx_type == CX_NONE) {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
+ } else {
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
+ }
+ }
+ if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN ||
+ (ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
+ ((line[0] == '*' &&
+ TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU &&
+ TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU) ||
+ (line[0] != '*' &&
+ TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU &&
+ TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU))
+ ) {
+ if (!ck_crypt_is_installed()) {
+ return(cx_fail(msg,
+ "Required Encryption methods are not installed"));
+ }
+ }
+#endif /* CK_ENCRYPTION */
+#ifdef RLOGCODE
+#ifdef CK_KERBEROS
+#ifdef KRB4
+ if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN) {
+ extern int krb4_autoget;
+ char tgt[256];
+ char * realm;
+
+ /* We don't have the full hostname at yet so */
+ /* we do a DNS lookup before calling ttopen() */
+
+ realm = ck_krb4_realmofhost(ckgetfqhostname(hostname));
+ ckmakmsg(tgt,256,"krbtgt.",realm,"@",realm);
+ if (!ck_krb4_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 4) is not installed"
+ ));
+ } else {
+ if ((ck_krb4_tkt_isvalid(tgt) <= 0) &&
+ (!krb4_autoget ||
+ krb4_autoget && !ck_krb4_autoget_TGT(realm))) {
+ return(cx_fail(msg,
+ "Kerberos 4: Ticket Getting Ticket not valid"));
+ }
+ }
+ }
+#endif /* KRB4 */
+#ifdef KRB5
+ if (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN ||
+ ttnproto == NP_K5U2U)
+ {
+ extern int krb5_autoget;
+ char tgt[256];
+ char * realm;
+
+ /* Must get full hostname before calling ttopen() */
+
+ realm = ck_krb5_realmofhost(ckgetfqhostname(hostname));
+ ckmakmsg(tgt,256,"krbtgt/",realm,"@",realm);
+
+ if (!ck_krb5_is_installed()) {
+ return(cx_fail(msg,
+ "Required authentication method (Kerberos 5) not installed"));
+ } else if (!((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
+ ck_krb5_is_tgt_valid()) &&
+ (!krb5_autoget ||
+ krb5_autoget && !ck_krb5_autoget_TGT(realm))) {
+ return(cx_fail(msg,
+ "Kerberos 5: Ticket Getting Ticket not valid."));
+ }
+ }
+#endif /* KRB5 */
+#endif /* CK_KERBEROS */
+#endif /* RLOGCODE */
+
+#ifndef NOSPL
+#ifdef RLOGCODE
+ if (username) {
+ if (!sl_uid_saved) {
+ ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
+ sl_uid_saved = 1;
+ }
+ ckstrncpy(uidbuf,username,UIDBUFLEN);
+ uidflag = 1;
+ }
+#endif /* RLOGCODE */
+#ifdef TNCODE
+ if (!sl_tn_saved) {
+ sl_tn_wait = tn_wait_flg;
+ sl_tn_saved = 1;
+ }
+ tn_wait_flg = param3;
+#endif /* TNCODE */
+#endif /* NOSPL */
+ } /* if (net == NET_TCPB) */
+#endif /* TCPSOCKET */
+
+#ifndef NOSPL
+#ifdef CK_SECURITY
+ if (password) {
+ if (password[0]) {
+ ckstrncpy(pwbuf,password,PWBUFL+1);
+ pwflg = 1;
+ pwcrypt = 0;
+ } else
+ pwflg = 0;
+ }
+#endif /* CK_SECURITY */
+#endif /* NOSPL */
+
+ /* Try to open - network */
+ ckstrncpy(ttname,line,TTNAMLEN);
+ y = ttopen(line, &_local, mdmtyp, 0 );
+
+#ifndef NOHTTP
+ /* If the connection failed and we are using an HTTP Proxy
+ * and the reason for the failure was an authentication
+ * error, then we need to give the user to ability to
+ * enter a username and password, just like a browser.
+ *
+ * I tried to do all of this within the netopen() call
+ * but it is much too much work.
+ */
+ while (y < 0 && tcp_http_proxy != NULL ) {
+
+ if (tcp_http_proxy_errno == 401 ||
+ tcp_http_proxy_errno == 407 ) {
+ char uid[UIDBUFLEN];
+ char pwd[256];
+ struct txtbox tb[2];
+ int ok;
+
+ tb[0].t_buf = uid;
+ tb[0].t_len = UIDBUFLEN;
+ tb[0].t_lbl = "Proxy Userid: ";
+ tb[0].t_dflt = NULL;
+ tb[0].t_echo = 1;
+ tb[1].t_buf = pwd;
+ tb[1].t_len = 256;
+ tb[1].t_lbl = "Proxy Passphrase: ";
+ tb[1].t_dflt = NULL;
+ tb[1].t_echo = 2;
+
+ ok = uq_mtxt("Proxy Server Authentication Required\n",
+ NULL, 2, tb);
+
+ if (ok && uid[0]) {
+ char * proxy_user, * proxy_pwd;
+
+ proxy_user = tcp_http_proxy_user;
+ proxy_pwd = tcp_http_proxy_pwd;
+
+ tcp_http_proxy_user = uid;
+ tcp_http_proxy_pwd = pwd;
+
+ ckstrncpy(ttname,line,TTNAMLEN);
+ y = ttopen(line, &_local, mdmtyp, 0);
+ memset(pwd,0,sizeof(pwd));
+ tcp_http_proxy_user = proxy_user;
+ tcp_http_proxy_pwd = proxy_pwd;
+ } else
+ break;
+ } else
+ break;
+ }
+#endif /* NOHTTP */
+ if (y < 0) {
+ slrestor();
+ makestr(&slmsg,"Network connection failure");
+#ifdef VMS
+ if (msg && hints && !xcmdsrc && IS_RLOGIN()) {
+ makestr(&slmsg,"RLOGIN failure");
+ if (socket_errno == EACCES) {
+ printf("*************************\n");
+ printf(
+ "Hint: RLOGIN requires privileges to open an outbound port.\n");
+ printf(
+ "(Use SET HINTS OFF to suppress future hints.)\n");
+ printf("*************************\n");
+ }
+ }
+#else /* Not VMS... */
+ if (errno) {
+ int x;
+ debug(F111,"set host line, errno","",errno);
+ makestr(&slmsg,ck_errstr());
+ if (msg) {
+#ifdef OS2
+ printf("Can't connect to %s\n",line);
+#else /* OS2 */
+#ifdef UNIX
+ if (hints && !xcmdsrc && IS_RLOGIN()) {
+ makestr(&slmsg,"RLOGIN failure");
+ printf("*************************\n");
+ printf(
+ "Hint: RLOGIN requires privileges to open an outbound port.\n");
+ printf(
+ "(Use SET HINTS OFF to suppress future hints.)\n");
+ printf("*************************\n");
+ }
+#endif /* UNIX */
+#endif /* OS2 */
+ } else printf("Can't connect to %s\n",line);
+ } else
+#endif /* VMS */
+ if (msg) printf("Can't open connection to %s\n",line);
+ continue;
+ } else {
+ success = 1;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ switch (net) {
+ case NET_TCPA:
+ case NET_TCPB:
+ cxtype = CXT_TCPIP;
+#ifdef COMMENT
+/* This works but it messes up interactive anonymous login */
+#ifndef NOXFER
+#ifdef IKS_OPTION
+ /* If we have connected to an Internet Kermit service */
+ /* and a /USER: switch was given, then log in. */
+
+ if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT)) {
+ debug(F111,"cx_net IKSD /USER:",uidbuf,haveuser);
+ if (haveuser /* && cx == 0 */ ) { /* /USER: given */
+ char * psw = pwbuf; /* Do we have a password? */
+ if (!*psw) { /* No... */
+ if (!strcmp(uidbuf,"anonymous") ||
+ !strcmp(uidbuf,"ftp")) {
+ extern char myhost[];
+ char * u = (char *)sl_uidbuf;
+ char * h = (char *)myhost;
+ if (!*u) u = "nobody";
+ if (!*h) h = "nowhere";
+ ckmakmsg(tmpbuf,TMPBUFSIZ,u,"@",h,NULL);
+ psw = tmpbuf;
+ debug(F110,"cx_net IKSD anon",psw,0);
+ } else {
+ readpass(" Password: ",pwbuf,PWBUFL);
+ }
+ }
+ sstate = setgen('I',uidbuf,psw,"");
+ }
+ }
+#endif /* IKS_OPTION */
+#endif /* NOXFER */
+#endif /* COMMENT */
+ break;
+ case NET_SSH:
+ cxtype = CXT_SSH;
+ duplex = 0; /* Remote echo */
+ break;
+ case NET_SLAT:
+ cxtype = CXT_LAT;
+ break;
+ case NET_SX25:
+ case NET_IX25:
+ case NET_HX25:
+ case NET_VX25:
+ cxtype = CXT_X25;
+ break;
+ case NET_BIOS:
+ cxtype = CXT_NETBIOS;
+ break;
+ case NET_FILE:
+ case NET_PIPE:
+ case NET_CMD:
+ case NET_DLL:
+ case NET_PTY:
+ cxtype = CXT_PIPE;
+ break;
+ default:
+ cxtype = CXT_PIPE;
+ break;
+ }
+ break;
+ }
+ } /* for-loop */
+ s = line;
+
+ debug(F101,"cx_net post ttopen success","",success);
+ if (!success) {
+ local = dfloc; /* Go back to normal */
+#ifndef MAC
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */
+#endif /* MAC */
+ speed = ttgspd();
+ network = 0; /* No network connection active */
+ haveline = 0;
+ if (mdmtyp < 0) { /* Switching from net to async? */
+ if (mdmsav > -1) /* Restore modem type from last */
+ mdmtyp = mdmsav; /* SET MODEM command, if any. */
+ else
+ mdmtyp = 0;
+ mdmsav = -1;
+ }
+ return(0); /* Return failure */
+ }
+ if (_local > -1) local = _local; /* Opened ok, set local/remote. */
+ makestr(&slmsg,NULL);
+ network = (mdmtyp < 0); /* Remember connection type. */
+ ckstrncpy(ttname,s,TTNAMLEN); /* Copy name into real place. */
+ debug(F110,"cx_net ok",ttname,0);
+ debug(F101,"cx_net network","",network);
+#ifndef NOXFER
+ if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */
+ reliable = SET_OFF;
+#endif /* NOXFER */
+ if (!network || istncomport())
+ speed = ttgspd(); /* Get the current speed. */
+ debug(F101,"cx_net local","",local);
+ if (network) {
+ debug(F101,"cx_net net","",net);
+#ifndef NOXFER
+ /* Force prefixing of 255 on TCP/IP connections... */
+ if (net == NET_TCPB
+#ifdef SSHBUILTIN
+ || net == NET_SSH
+#endif /* SSHBUILTIN */
+ ) {
+ debug(F101,"cx_net reliable A","",reliable);
+#ifdef CK_SPEED
+ ctlp[(unsigned)255] = 1;
+#endif /* CK_SPEED */
+ if ((reliable != SET_OFF || !setreliable)) {
+#ifdef TN_COMPORT
+ if (istncomport()) { /* Telnet communication port */
+ reliable = SET_OFF; /* Transport is not reliable */
+ debug(F101,"cx_net reliable istncomport()","",1);
+ } else {
+ reliable = SET_ON; /* Transport is reliable end to end */
+ debug(F101,"cx_net reliable istncomport()","",0);
+ }
+#else
+ reliable = SET_ON; /* Transport is reliable end to end */
+#endif /* ifdef TN_COMPORT */
+ }
+ debug(F101,"cx_net reliable B","",reliable);
+ } else if (net == NET_SX25 ||
+ net == NET_VX25 ||
+ net == NET_IX25 ||
+ net == NET_HX25) {
+ duplex = 1; /* Local echo for X.25 */
+ if (reliable != SET_OFF || !setreliable)
+ reliable = SET_ON; /* Transport is reliable end to end */
+ }
+#endif /* NOXFER */
+ }
+#ifndef NOXFER
+ debug(F101,"cx_net reliable","",reliable);
+#endif /* NOXFER */
+#ifdef OS2
+ if (mdmtyp <= 0) /* Network or Direct Connection */
+ DialerSend(OPT_KERMIT_CONNECT, 0);
+#endif /* OS2 */
+
+ xcx_net:
+
+ setflow(); /* Set appropriate flow control */
+
+ haveline = 1;
+#ifdef CKLOGDIAL
+ dolognet();
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+
+ if (local && (cx || sx)) { /* /CONNECT or /SERVER switch given */
+ if (cx) { /* /CONNECT */
+ if (!gui) {
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+ if (cmdlvl > 0)
+ prepop();
+ }
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ success = doconect(0, cmdlvl == 0 ? 1 : 0);
+ if (ttchk() < 0)
+ dologend();
+ debug(F101,"cx_net post doconect success","",success);
+ return(success);
+#ifndef NOXFER
+ } else if (sx) { /* /SERVER */
+ sstate = 'x';
+#ifdef MAC
+ what = W_RECV;
+ scrcreate();
+#endif /* MAC */
+ if (local) displa = 1;
+#ifdef AMIGA
+ reqoff(); /* No DOS requestors while server */
+#endif /* AMIGA */
+#endif /* NOXFER */
+ }
+ }
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ return(success = 1);
+}
+#endif /* NETCONN */
+
+/* c x _ s e r i a l -- Make a serial connection */
+
+/*
+ Call with:
+ device = string pointer to device name.
+ cx = 1 to automatically enter Connect mode, 0 otherwise.
+ sx = 1 to automatically enter Server mode, 0 otherwise.
+ shr = 1 if device should be opened in shareable mode, 0 otherwise.
+ flag = if no dev name given: 1 = close current connection, 0 = resume.
+ gui = 1 if called from GUI dialog, 0 otherwise.
+ Returns:
+ 1 on success
+ 0 on failure and no message printed, slmsg set to failure message.
+ -9 on failure and message printed, ditto.
+*/
+
+/* these are bit flags */
+#define CX_TAPI 1
+#define CX_PPP 2
+#define CX_SLIP 4
+
+int
+#ifdef CK_ANSIC
+cx_serial(char *device,
+ int cx, int sx, int shr, int flag, int gui, int special)
+#else /* CK_ANSIC */
+cx_serial(device, cx, sx, shr, flag, gui, special)
+ char * device; int cx, sx, shr, flag, gui, special;
+#endif /* CK_ANSIC */
+/* cx_serial */ {
+ int i, n, x, y, msg;
+ int _local = -1;
+ char *s;
+
+ debug(F110,"cx_serial device",device,0);
+ s = device;
+ msg = (gui == 0) && msgflg; /* Whether to print messages */
+ success = 0;
+
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+ debug(F101,"cx_serial mdmtyp","",mdmtyp);
+ if (clskconnx(1) < 0) /* Close the Kermit connection */
+ return(success = 0);
+ if (*s) { /* They gave a device name */
+ _local = -1; /* Let ttopen decide about it */
+ } else { /* They just said "set line" */
+ s = dftty; /* so go back to normal tty */
+ _local = dfloc; /* and mode. */
+ }
+#ifdef VMS
+ {
+ extern int ok_to_share;
+ ok_to_share = shr;
+ }
+#endif /* VMS */
+
+#ifdef OS2 /* Must wait until after ttclos() */
+#ifdef NT /* to change these settings */
+#ifdef CK_TAPI
+ tttapi = special & CX_TAPI;
+#endif /* CK_TAPI */
+#else
+ ttslip = special & CX_SLIP;
+ ttppp = special & CX_PPP;
+#endif /* NT */
+ ttshare = shr; /* Shareable device ? */
+ debug(F110,"OS2 SET PORT final s",s,"");
+#endif /* OS2 */
+
+ /* Open the new line */
+
+ ckstrncpy(ttname,s,TTNAMLEN);
+ if ((y = ttopen(s,&_local,mdmtyp,cdtimo)) > -1) {
+ cxtype = (mdmtyp > 0) ? CXT_MODEM : CXT_DIRECT;
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#ifdef CK_TAPI
+ /* if the line is a tapi device, then we need to auto-execute */
+ /* SET MODEM TYPE TAPI - which we do the equivalent of here. */
+ if (tttapi) {
+ extern int usermdm;
+ usermdm = 0;
+ initmdm(38); /* From ckudia.c n_TAPI == 38 */
+ }
+#endif /* CK_TAPI */
+#endif /* NODIAL */
+ success = 1;
+ } else { /* Failed */
+#ifdef OS2ONLY
+ if (!strcmp(s,dftty)) /* Do not generate an error with dftty */
+ ;
+ else if (y == -6 && ttslip) {
+ makestr(&slmsg,"Can't access SLIP driver");
+ if (msg) printf("?%s\n",slmsg);
+ } else if (y == -6 && ttppp) {
+ makestr(&slmsg,"Can't access PPP driver");
+ if (msg) printf("?%s\n",slmsg);
+ } else
+#endif /* OS2ONLY */
+ if (y == -2) {
+ makestr(&slmsg,"Timed out - no carrier");
+ if (msg) {
+ printf("?%s\n",slmsg);
+ if (hints) {
+ printf("\n*************************\n");
+ printf(
+ "HINT (Use SET HINTS OFF to suppress future hints):\n");
+ printf(
+ "Try SET CARRIER OFF and SET LINE again, or else\n");
+ printf("SET MODEM, SET LINE, and then DIAL.\n");
+ printf("*************************\n\n");
+ }
+ }
+ } else if (y == -3) {
+ makestr(&slmsg,"Access to lock denied");
+ if (msg) {
+#ifdef UNIX
+ printf(
+ "Sorry, write access to UUCP lockfile directory denied.\n");
+#ifndef NOHINTS
+ if (hints) {
+ printf("\n*************************\n");
+ printf(
+ "HINT (Use SET HINTS OFF to suppress future hints):\n");
+ printf(
+ "Please read the installation instructions file, %sckuins.txt,\n",
+ k_info_dir ? k_info_dir : ""
+ );
+ printf(
+ "or the UNIX appendix of the manual, \"Using C-Kermit\"\n"
+ );
+ printf(
+ "or visit http://www.columbia.edu/kermit/ckuins.html \n"
+ );
+ printf("*************************\n\n");
+ }
+#endif /* NOHINTS */
+#else
+ printf("Sorry, access to lock denied: %s\n",s);
+#endif /* UNIX */
+ }
+ } else if (y == -4) {
+ makestr(&slmsg,"Access to device denied");
+ if (msg) {
+ printf("Sorry, access to device denied: %s\n",s);
+#ifdef UNIX
+#ifndef NOHINTS
+ if (hints) {
+ printf("\n*************************\n");
+ printf(
+ "HINT (Use SET HINTS OFF to suppress future hints):\n");
+ printf(
+ "Please read the installation instructions file, %sckuins.txt,\n",
+ k_info_dir ? k_info_dir : ""
+ );
+ printf(
+ "or the UNIX appendix of the manual, \"Using C-Kermit\".\n"
+ );
+ printf("*************************\n\n");
+ }
+#endif /* NOHINTS */
+#endif /* UNIX */
+ }
+ } else if (y == -5) {
+ makestr(&slmsg,"Device is in use or unavailable");
+ if (msg)
+#ifdef VMS
+ printf(
+ "Sorry, device is in use or otherwise unavailable: %s\n",s);
+#else
+ printf("Sorry, device is in use: %s\n",s);
+#endif /* VMS */
+ } else { /* Other error. */
+ makestr(&slmsg,"Device open failed");
+ if (
+#ifdef VMS
+ 1
+#else
+ errno
+#endif /* VMS */
+ ) {
+ int x; /* Find a safe, long buffer */
+ makestr(&slmsg,ck_errstr());
+#ifndef VMS
+ debug(F111,"cx_serial serial errno",slmsg,errno);
+#endif /* VMS */
+ if (msg)
+ printf("Connection to %s failed: %s\n",s,slmsg);
+ } else if (msg)
+ printf("Sorry, can't open connection: %s\n",s);
+ }
+ }
+ network = 0; /* No network connection active */
+ speed = ttgspd();
+ if (!success) {
+ local = dfloc; /* Go back to normal */
+#ifndef MAC
+ ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */
+#endif /* MAC */
+ haveline = 0;
+ if (mdmtyp < 0) { /* Switching from net to async? */
+ if (mdmsav > -1) /* Restore modem type from last */
+ mdmtyp = mdmsav; /* SET MODEM command, if any. */
+ else
+ mdmtyp = 0;
+ mdmsav = -1;
+ }
+ return(msg ? -9 : 0); /* Return failure */
+ }
+ if (_local > -1)
+ local = _local; /* Opened ok, set local/remote. */
+ makestr(&slmsg,NULL); /* Erase SET LINE message */
+ ckstrncpy(ttname,s,TTNAMLEN); /* Copy name into real place. */
+ debug(F110,"cx_serial ok",ttname,0);
+#ifndef NOXFER
+ if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */
+ reliable = SET_OFF;
+#endif /* NOXFER */
+
+ xcx_serial:
+ setflow(); /* Set appropriate flow control */
+ haveline = 1;
+#ifdef CKLOGDIAL
+ dologline();
+#endif /* CKLOGDIAL */
+
+#ifndef NOSPL
+ if (local) {
+ if (nmac) { /* Any macros defined? */
+ int k; /* Yes */
+ k = mlook(mactab,"on_open",nmac); /* Look this up */
+ if (k >= 0) { /* If found, */
+ if (dodo(k,ttname,0) > -1) /* set it up, */
+ parser(1); /* and execute it */
+ }
+ }
+ }
+#endif /* NOSPL */
+
+ if (local && (cx || sx)) { /* /CONNECT or /SERVER switch given */
+ extern int carrier;
+ if (carrier != CAR_OFF) { /* Looking for carrier? */
+ /* Open() turns on DTR -- wait up to a second for CD to come up */
+ int i, x;
+ for (i = 0; i < 10; i++) { /* WAIT 1 CD... */
+ x = ttgmdm();
+ if (x < 0 || x & BM_DCD)
+ break;
+ msleep(100);
+ }
+ }
+ if (cx) { /* /CONNECT */
+ /* Command was confirmed so we can pre-pop command level. */
+ /* This is so CONNECT module won't think we're executing a */
+ /* script if CONNECT was the final command in the script. */
+
+ if (cmdlvl > 0)
+ prepop();
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ success = doconect(0, cmdlvl == 0 ? 1 : 0);
+ if (ttchk() < 0)
+ dologend();
+ return(success);
+#ifndef NOXFER
+ } else if (sx) { /* /SERVER */
+ sstate = 'x';
+#ifdef MAC
+ what = W_RECV;
+ scrcreate();
+#endif /* MAC */
+ if (local) displa = 1;
+#ifdef AMIGA
+ reqoff(); /* No DOS requestors while server */
+#endif /* AMIGA */
+#endif /* NOXFER */
+ }
+ }
+#ifndef NODIAL
+ dialsta = DIA_UNK;
+#endif /* NODIAL */
+#ifdef LOCUS
+ if (autolocus) {
+ setlocus(1,1);
+ }
+#endif /* LOCUS */
+ return(success = 1);
+}
+
+
+/* S E T L I N -- parse name of and then open communication device. */
+/*
+ Call with:
+ xx == XYLINE for a serial (tty) line, XYHOST for a network host,
+ zz == 0 means if user doesn't give a device name, continue current
+ active connection (if any);
+ zz != 0 means if user doesn't give a device name, then close the
+ current connection and restore the default communication device.
+ fc == 0 to just make the connection, 1 to also CONNECT (e.g. "telnet").
+*/
+int
+setlin(xx, zz, fc)
+ int xx, zz, fc;
+{
+ extern char pwbuf[], * g_pswd;
+ extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
+ int wait;
+ /* int tn_wait_sv; */
+ int mynet;
+ int _local = -1;
+ int c, i, haveswitch = 0;
+ int haveuser = 0;
+ int getval = 0;
+ int wild = 0; /* Filespec has wildcards */
+ int cx = 0; /* Connect after */
+ int sx = 0; /* Become server after */
+ int a_type = -1; /* Authentication type */
+ int e_type = -1; /* Telnet /ENCRYPT type */
+#ifdef CK_ENCRYPTION
+ int encrypt = 0; /* Encrypted? */
+#endif /* CK_ENCRYPTION */
+ int shr = 0; /* Share serial device */
+ int confirmed = 0; /* Command has been entered */
+ struct FDB sw, tx, nx;
+#ifdef OS2
+ struct FDB fl;
+#endif /* OS2 */
+
+ char * ss;
+#ifdef TCPSOCKET
+ int rawflg = 0;
+#endif /* TCPSOCKET */
+
+ char srvbuf[SRVBUFSIZ+1];
+
+#ifdef OS2
+#ifdef NT
+ int xxtapi = 0;
+#else
+ int xxslip = 0, xxppp = 0;
+#endif /* NT */
+#endif /* OS2 */
+
+ int dossh = 0;
+
+ debug(F101,"setlin fc","",fc);
+ debug(F101,"setlin zz","",zz);
+ debug(F101,"setlin xx","",xx);
+
+#ifdef SSHCMD
+ if (xx == XXSSH) { /* SSH becomes PTY SSH ... */
+ dossh = 1;
+ xx = XYHOST;
+ }
+#endif /* SSHCMD */
+
+#ifdef TNCODE
+ /* tn_wait_sv = tn_wait_flg; */
+ wait = tn_wait_flg;
+#else
+ /* tn_wait_sv = 0; */
+ wait = 0;
+#endif /* TNCODE */
+
+ mynet = nettype;
+
+ if (nolocal) {
+ makestr(&slmsg,"Making connections is disabled");
+ printf("?Sorry, making connections is disabled\n");
+ return(-9);
+ }
+ if (netsave > -1)
+ nettype = netsave;
+
+ if (fc != 0 || zz == 0) /* Preset /CONNECT switch */
+ cx = 1;
+
+ debug(F101,"setlin cx","",cx);
+
+ *srvbuf = NUL;
+
+ line[0] = NUL;
+ s = line;
+
+#ifdef NETCONN
+#ifdef CK_SECURITY
+ if (tmpstring)
+ makestr(&tmpstring,NULL);
+#endif /* CK_SECURITY */
+ if (tmpusrid)
+ makestr(&tmpusrid,NULL);
+#endif /* NETCONN */
+
+ autoflow = 1; /* Enable automatic flow setting */
+
+ if (xx == XYHOST) { /* SET HOST <hostname> */
+#ifndef NETCONN
+ makestr(&slmsg,"Network connections not supported");
+ printf("?%s\n",slmsg);
+ return(-9);
+#else /* NETCONN */
+#ifndef NOPUSH
+ if ((mynet == NET_CMD || mynet == NET_PTY || dossh) && nopush) {
+ makestr(&slmsg,"Access to external commands is disabled");
+ printf("?Sorry, access to external commands is disabled\n");
+ return(-9);
+ }
+#endif /* NOPUSH */
+
+#ifdef SSHCMD
+ if (dossh) { /* SSH connection via pty */
+ int k;
+ k = ckstrncpy(line, sshcmd ? sshcmd : defsshcmd, LINBUFSIZ);
+ debug(F111,"setlin sshcmd 1",line,k);
+ if ((x = cmtxt("Optional switches and hostname","",&s,xxstring))<0)
+ return(x);
+ if (!*s) {
+ printf("?SSH to where?\n");
+ return(-9);
+ }
+ if (k < LINBUFSIZ) {
+ line[k++] = SP;
+ line[k] = NUL;
+ debug(F111,"setlin sshcmd 2",line,k);
+ } if (k < LINBUFSIZ) {
+ ckstrncpy(&line[k],s,LINBUFSIZ-k);
+ debug(F111,"setlin sshcmd 3",line,k);
+ } else {
+ printf("?Too long\n");
+ return(-9);
+ }
+ x = cx_net( NET_PTY, /* network type */
+ 0, /* protocol (not used) */
+ line, /* host */
+ NULL, /* service (not used) */
+ NULL, /* username (not used) */
+ NULL, /* password (not used) */
+ NULL, /* command (not used) */
+ -1,-1,-1, /* params 1-3 (not used) */
+ 1, /* connect immediately */
+ sx, /* server? */
+ zz, /* close current? */
+ 0); /* not gui */
+ debug(F111,"setlin cx_net",line,x);
+ return(x);
+ }
+#endif /* SSHCMD */
+
+/*
+ Here we parse optional switches and then the hostname or whatever,
+ which depends on the network type. The tricky part is, the network type
+ can be set by a switch.
+*/
+#ifndef NOSPL
+ makestr(&g_pswd,pwbuf); /* Save global pwbuf */
+ g_pflg = pwflg; /* and flag */
+ g_pcpt = pwcrypt;
+#endif /* NOSPL */
+
+ confirmed = 0;
+ haveswitch = 0;
+#ifdef NETFILE
+ if (mynet != NET_FILE) {
+#endif /* NETFILE */
+ ss = (mynet == NET_CMD || mynet == NET_PTY) ?
+ "Command, or switch" :
+ (mynet == NET_TCPA || mynet == NET_TCPB
+ || mynet == NET_SSH) ?
+ "Hostname, ip-address, or switch" :
+ "Host or switch";
+ if (fc) {
+ if (mynet == NET_TCPB &&
+ (ttnproto == NP_TELNET || ttnproto == NP_KERMIT)) {
+ if (nshteltab) {
+ haveswitch++;
+ cmfdbi(&sw,_CMKEY,ss,"","",nshteltab,4,xxstring,
+ shteltab,&nx);
+ }
+ }
+#ifdef RLOGCODE
+ else if (mynet == NET_TCPB && ttnproto == NP_RLOGIN) {
+ if (nshrlgtab) {
+ haveswitch++;
+ cmfdbi(&sw,_CMKEY,ss,"","",nshrlgtab,4,xxstring,
+ shrlgtab,&nx);
+ }
+ }
+#endif /* RLOGCODE */
+ } else {
+ haveswitch++;
+ cmfdbi(&sw,_CMKEY,ss,"","",nshtab,4,xxstring,shtab,&nx);
+ }
+#ifdef NETFILE
+ }
+#endif /* NETFILE */
+ if (mynet == NET_TCPB || mynet == NET_SLAT ||
+ mynet == NET_SSH || mynet == NET_DEC) {
+ cmfdbi(&nx,_CMFLD,"Host","","",0,0,xxstring,NULL,NULL);
+#ifdef NETFILE
+ } else if (mynet == NET_FILE) {
+ cmfdbi(&nx,_CMIFI,"Filename","","",0,0,xxstring,NULL,NULL);
+#endif /* NETFILE */
+#ifdef PTYORPIPE
+ } else if (mynet == NET_CMD || mynet == NET_PTY) {
+ cmfdbi(&nx,_CMTXT,"Command","","",0,0,xxstring,NULL,NULL);
+#endif /* PTYORPIPE */
+ } else {
+ cmfdbi(&nx,_CMTXT,"Host","","",0,0,xxstring,NULL,NULL);
+ }
+ while (1) {
+ x = cmfdb(haveswitch ? &sw : &nx);
+ debug(F101,"setlin cmfdb","",x);
+ if (x < 0)
+ if (x != -3)
+ return(x);
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) {
+ return(x);
+ } else {
+ confirmed = 1;
+ break;
+ }
+ }
+ if (cmresult.fcode != _CMKEY) { /* Not a switch */
+ ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Save the data */
+ s = line; /* that was parsed... */
+ if (cmresult.fcode == _CMIFI) {
+ wild = cmresult.nresult;
+ } else if (cmresult.fcode == _CMTXT) {
+ confirmed = 1;
+ }
+ break; /* and break out of this loop */
+ }
+ c = cmgbrk(); /* Have switch - get break character */
+ getval = (c == ':' || c == '='); /* Must parse an agument? */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) { /* It's a switch.. */
+ case SL_CNX: /* /CONNECT */
+ cx = 1;
+ sx = 0;
+ break;
+ case SL_SRV: /* /SERVER */
+ cx = 0;
+ sx = 1;
+ break;
+#ifdef NETCMD
+ case SL_CMD: /* /COMMAND */
+ netsave = mynet;
+ mynet = NET_CMD;
+ break;
+#endif /* NETCMD */
+#ifdef NETPTY
+ case SL_PTY: /* /PTY */
+ netsave = mynet;
+ mynet = NET_PTY;
+ break;
+#endif /* NETPTY */
+ case SL_NET: /* /NETWORK-TYPE */
+ if ((x = cmkey(netcmd,nnets,"","",xxstring)) < 0)
+ return(x);
+ mynet = x;
+ break;
+
+#ifdef CK_SECURITY
+ case SL_PSW: /* /PASSWORD: */
+ if (!getval)
+ break;
+ debok = 0;
+ if ((x = cmfld("Password","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&tmpstring,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&tmpstring,s);
+ }
+ break;
+#endif /* CK_SECURITY */
+
+ case SL_UID: /* /USERID: */
+ if (!getval)
+ break;
+ if ((x = cmfld("Userid","",&s,xxstring)) < 0) {
+ if (x == -3) {
+ makestr(&tmpusrid,"");
+ } else {
+ return(x);
+ }
+ } else {
+ s = brstrip(s);
+ if ((x = (int)strlen(s)) > 63) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",63);
+ return(-9);
+ }
+ makestr(&tmpusrid,s);
+ haveuser = 1;
+ }
+ break;
+
+#ifdef CK_AUTHENTICATION
+#ifdef CK_SRP
+ case SL_SRP:
+ a_type = AUTHTYPE_SRP;
+ break;
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ case SL_SSL:
+ a_type = AUTHTYPE_SSL;
+ break;
+#endif /* CK_SSL */
+#ifdef NT
+ case SL_NTLM:
+ a_type = AUTHTYPE_NTLM;
+ break;
+#endif /* NT */
+#ifdef CK_KERBEROS
+ case SL_KRB4:
+ a_type = AUTHTYPE_KERBEROS_V4;
+ if (ttnproto == NP_RLOGIN)
+ ttnproto =
+#ifdef CK_ENCRYPTION
+ encrypt ? NP_EK4LOGIN :
+#endif /* CK_ENCRYPTION */
+ NP_K4LOGIN;
+ else if (ttnproto == NP_K5LOGIN)
+ ttnproto = NP_K4LOGIN;
+#ifdef CK_ENCRYPTION
+ else if (ttnproto == NP_EK5LOGIN)
+ ttnproto = NP_EK4LOGIN;
+#endif /* CK_ENCRYPTION */
+ break;
+ case SL_KRB5:
+ a_type = AUTHTYPE_KERBEROS_V5;
+ if (ttnproto == NP_RLOGIN)
+ ttnproto =
+#ifdef CK_ENCRYPTION
+ encrypt ? NP_EK5LOGIN :
+#endif /* CK_ENCRYPTION */
+ NP_K5LOGIN;
+ else if (ttnproto == NP_K4LOGIN)
+ ttnproto = NP_K5LOGIN;
+#ifdef CK_ENCRYPTION
+ else if (ttnproto == NP_EK4LOGIN)
+ ttnproto = NP_EK5LOGIN;
+#endif /* CK_ENCRYPTION */
+ break;
+#endif /* CK_KERBEROS */
+ case SL_AUTH: {
+ extern struct keytab autyptab[];
+ extern int nautyp;
+ if ((x = cmkey(autyptab,nautyp,"type of authentication",
+ "automatic",xxstring)) < 0)
+ return(x);
+ a_type = x;
+ break;
+ }
+#endif /* CK_AUTHENTICATION */
+#ifdef CK_ENCRYPTION
+ case SL_ENC:
+ switch (ttnproto) {
+ case NP_K4LOGIN:
+ ttnproto = NP_EK4LOGIN;
+ encrypt = 1;
+ break;
+ case NP_K5LOGIN:
+ ttnproto = NP_EK5LOGIN;
+ encrypt = 1;
+ break;
+ case NP_KERMIT:
+ case NP_TELNET: {
+ static struct keytab * tnetbl = NULL;
+ static int ntnetbl = 0;
+ x = ck_get_crypt_table(&tnetbl,&ntnetbl);
+ debug(F101,"ck_get_crypt_table x","",x);
+ debug(F101,"ck_get_crypt_table n","",ntnetbl);
+ if (x < 1 || !tnetbl || ntnetbl < 1) /* Didn't get it */
+ x = 0;
+ if (!x) {
+ makestr(&slmsg,"Internal error");
+ printf("?Oops, types not loaded\n");
+ return(-9);
+ }
+ if ((x = cmkey(tnetbl,ntnetbl,"type of encryption",
+ "automatic",xxstring)) < 0)
+ return(x);
+ e_type = x;
+ break;
+ }
+ }
+ break;
+#endif /* CK_ENCRYPTION */
+ case SL_WAIT:
+ wait = 1;
+ break;
+ case SL_NOWAIT:
+ wait = 0;
+ break;
+ }
+ }
+
+#ifdef NETFILE
+ if (mynet == NET_FILE) { /* Parsed by cmifi() */
+ if ((x = cmcfm()) < 0) /* Needs confirmation */
+ return(x);
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* NETFILE */
+
+#ifdef NETCMD
+ if (mynet == NET_CMD || mynet == NET_PTY) {
+ char *p = NULL;
+ if (!confirmed) {
+ if ((x = cmtxt("Rest of command","",&s,xxstring)) < 0)
+ return(x);
+ if (*s) {
+ strncat(line," ",LINBUFSIZ);
+ strncat(line,s,LINBUFSIZ);
+ }
+ s = line;
+ }
+ /* s == line - so we must protect the line buffer */
+ s = brstrip(s);
+ makestr(&p,s);
+ ckstrncpy(line,p,LINBUFSIZ);
+ makestr(&p,NULL);
+
+ x = cx_net( mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* NETCMD */
+
+#ifdef NPIPE /* Named pipe */
+ if (mynet == NET_PIPE) { /* Needs backslash twiddling */
+ if (line[0]) {
+ if (strcmp(line,"*")) { /* If remote, begin with */
+ char * p = NULL;
+ makestr(&p,line);
+ ckstrncpy(line,"\\\\",LINBUFSIZ); /* server name */
+ ckstrncat(line,p,LINBUFSIZ);
+ makestr(&p,NULL);
+ } else {
+ line[0]='\0';
+ }
+ ckstrncat(line,"\\pipe\\", LINBUFSIZ); /* Make pipe name */
+ ckstrncat(line,pipename, LINBUFSIZ); /* Add name of pipe */
+
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+ }
+#endif /* NPIPE */
+
+#ifdef SUPERLAT
+ if (mynet == NET_SLAT) { /* Needs password, etc. */
+ slat_pwd[0] = NUL; /* Erase any previous password */
+ debok = 0;
+ if (*line) { /* If they gave a host name... */
+ if ((x = cmfld(
+ "password,\n or carriage return if no password required",
+ "",
+ &s,
+ xxstring
+ )) < 0 && x != -3)
+ return(x);
+ ckstrncpy(slat_pwd,s,18); /* Set the password, if any */
+ }
+ if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
+
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* SUPERLAT */
+
+#ifdef DECNET
+ if (mynet == NET_DEC) {
+ if (!line[0]) { /* If they gave a host name... */
+ printf("?hostname required\n");
+ return(-3);
+ }
+ if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
+
+ x = cx_net(mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ "", /* port */
+ NULL, /* alternate username */
+ NULL, /* password */
+ NULL, /* command to execute */
+ 0, /* param1 */
+ 0, /* param2 */
+ 0, /* param3 */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* DECNET */
+
+#ifdef SSHBUILTIN
+ if (mynet == NET_SSH) { /* SSH connection */
+ int k, havehost = 0, trips = 0;
+ int tmpver = -1, tmpxfw = -1, tmpssh_cas;
+#ifndef SSHTEST
+ extern int sl_ssh_xfw, sl_ssh_xfw_saved;
+ extern int sl_ssh_ver, sl_ssh_ver_saved;
+#endif /* SSHTEST */
+ extern struct keytab sshopnsw[];
+ extern int nsshopnsw;
+ extern char *ssh_tmpcmd, *ssh_tmpport;
+ struct FDB sw, kw, fl;
+
+ debug(F110,"setlin SSH service 0",srvbuf,0);
+ debug(F110,"setlin SSH host s 2",s,0);
+ if (*s) { /* If they gave a host name... */
+ debug(F110,"setlin SSH host s 1",s,0);
+ if (*s == '*') {
+ makestr(&slmsg,"Incoming connections not supported");
+ printf(
+ "?Sorry, incoming connections not supported for SSH.\n"
+ );
+ return(-9);
+ }
+ ckstrncpy(line,s,LINBUFSIZ);
+ } else {
+ printf("?hostname required\n");
+ return(-3);
+ }
+
+ /* Parse [ port ] [ switches ] */
+ cmfdbi(&kw, /* Switches */
+ _CMKEY,
+ "Port number or service name,\nor switch",
+ "",
+ "",
+ nsshopnsw,
+ 4,
+ xxstring,
+ sshopnsw,
+ &fl
+ );
+ cmfdbi(&fl, /* Port number or service name */
+ _CMFLD,
+ "",
+ "",
+ "",
+ 0,
+ 0,
+ xxstring,
+ NULL,
+ NULL
+ );
+ trips = 0; /* Explained below */
+ while (1) { /* Parse port and switches */
+ y = cmfdb(&kw); /* Get a field */
+ if (y == -3) /* User typed CR so quit from loop */
+ break;
+ if (y < 0) /* Other parse error, pass it back */
+ return(y);
+ switch (cmresult.fcode) { /* Field or Keyword? */
+ case _CMFLD: /* Field */
+ ckstrncpy(srvbuf,cmresult.sresult,SRVBUFSIZ);
+ break;
+ case _CMKEY: /* Keyword */
+ switch (cmresult.nresult) { /* Which one? */
+ case SSHSW_PWD:
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ debok = 0;
+ if ((y = cmfld("Password","",&s,xxstring)) < 0) {
+ if (y == -3) {
+ makestr(&tmpstring,"");
+ } else {
+ return(y);
+ }
+ } else {
+ s = brstrip(s);
+ if ((y = (int)strlen(s)) > PWBUFL) {
+ makestr(&slmsg,"Internal error");
+ printf("?Sorry, too long - max = %d\n",PWBUFL);
+ return(-9);
+ }
+ makestr(&tmpstring,s);
+ }
+ break;
+ case SSHSW_USR: /* /USER: */
+ if (!cmgbrk()) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ if ((y = cmfld("Username","",&s,xxstring)) < 0)
+ return(y);
+ s = brstrip(s);
+ makestr(&tmpusrid,s);
+ break;
+ case SSHSW_VER:
+ if ((y = cmnum("Number","",10,&z,xxstring)) < 0)
+ return(y);
+ if (z < 1 || z > 2) {
+ printf("?Out of range: %d\n",z);
+ return(-9);
+ }
+ tmpver = z;
+ break;
+ case SSHSW_CMD:
+ case SSHSW_SUB:
+ if ((y = cmfld("Text","",&s,xxstring)) < 0)
+ return(y);
+ makestr(&ssh_tmpcmd,s);
+ tmpssh_cas = (cmresult.nresult == SSHSW_SUB);
+ break;
+ case SSHSW_X11:
+ if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
+ return(y);
+ tmpxfw = y;
+ break;
+ default:
+ return(-2);
+ }
+ }
+ if (trips++ == 0) { /* After first time through */
+ cmfdbi(&kw, /* only parse switches, not port. */
+ _CMKEY,
+ "Switch",
+ "",
+ "",
+ nsshopnsw,
+ 4,
+ xxstring,
+ sshopnsw,
+ NULL
+ );
+ }
+ }
+ if ((y = cmcfm()) < 0) /* Get confirmation */
+ return(y);
+
+ debug(F110,"setlin pre-cx_net line",line,0);
+ debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0);
+ x = cx_net( mynet, /* nettype */
+ 0, /* protocol (not used) */
+ line, /* host */
+ srvbuf, /* port */
+ tmpusrid, /* alternate username */
+ tmpstring, /* password */
+ ssh_tmpcmd, /* command to execute */
+ tmpver, /* param1 - ssh version */
+ tmpssh_cas, /* param2 - ssh cas */
+ tmpxfw, /* param3 - ssh x11fwd */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ if (tmpusrid)
+ makestr(&tmpusrid,NULL);
+ if (ssh_tmpcmd)
+ makestr(&ssh_tmpcmd,NULL);
+ }
+#endif /* SSHBUILTIN */
+
+#ifdef TCPSOCKET
+ if (mynet == NET_TCPB) { /* TCP/IP connection */
+ debug(F110,"setlin service 0",srvbuf,0);
+ debug(F110,"setlin host s 2",s,0);
+ if (*s) { /* If they gave a host name... */
+ debug(F110,"setlin host s 1",s,0);
+#ifdef NOLISTEN
+ if (*s == '*') {
+ makestr(&slmsg,"Incoming connections not supported");
+ printf(
+ "?Sorry, incoming connections not supported in this version of Kermit.\n"
+ );
+ return(-9);
+ }
+#endif /* NOLISTEN */
+#ifdef RLOGCODE
+ /* Allow a username if rlogin is requested */
+ if (mynet == NET_TCPB &&
+ (ttnproto == NP_RLOGIN || ttnproto == NP_K5LOGIN ||
+ ttnproto == NP_EK5LOGIN || ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_EK4LOGIN
+ )) {
+ int y;
+ uidflag = 0;
+ /* Check for "host:service" */
+ for ( ; (*s != '\0') && (*s != ':'); s++) ;
+ if (*s) { /* Service, save it */
+ *s = NUL;
+ ckstrncpy(srvbuf,++s,SRVBUFSIZ);
+ } else { /* No :service, then use default. */
+#ifdef VMS
+ switch (ttnproto) {
+ case NP_RLOGIN:
+ ckstrncpy(srvbuf,"513",SRVBUFSIZ); /* "login" */
+ break;
+ case NP_K4LOGIN:
+ case NP_K5LOGIN:
+ ckstrncpy(srvbuf,"543",SRVBUFSIZ); /* "klogin" */
+ break;
+ case NP_EK4LOGIN:
+ case NP_EK5LOGIN:
+ ckstrncpy(srvbuf,"2105",SRVBUFSIZ); /* "eklogin" */
+ break;
+ }
+#else /* VMS */
+ switch (ttnproto) {
+ case NP_RLOGIN:
+ ckstrncpy(srvbuf,"login",SRVBUFSIZ);
+ break;
+ case NP_K4LOGIN:
+ case NP_K5LOGIN:
+ ckstrncpy(srvbuf,"klogin",SRVBUFSIZ);
+ break;
+ case NP_EK4LOGIN:
+ case NP_EK5LOGIN:
+ ckstrncpy(srvbuf,"eklogin",SRVBUFSIZ);
+ break;
+ }
+#endif /* VMS */
+ }
+ if (!confirmed) {
+ y = cmfld("Userid on remote system",
+ uidbuf,&s,xxstring);
+ if (y < 0 && y != -3)
+ return(y);
+ if ((int)strlen(s) > 63) {
+ makestr(&slmsg,"Internal error");
+ printf("Sorry, too long\n");
+ return(-9);
+ }
+ makestr(&tmpusrid,s);
+ }
+ } else { /* TELNET or SET HOST */
+#endif /* RLOGCODE */
+ /* Check for "host:service" */
+ for ( ; (*s != '\0') && (*s != ':'); s++) ;
+ if (*s) { /* Service, save it */
+ *s = NUL;
+ ckstrncpy(srvbuf,++s,SRVBUFSIZ);
+ } else if (!confirmed) {
+ /* No :service, let them type one. */
+ if (*line != '*') { /* Not incoming */
+ if (mynet == NET_TCPB && ttnproto == NP_KERMIT) {
+ if ((x = cmfld(
+ "TCP service name or number",
+ "kermit",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+#ifdef RLOGCODE
+ } else if (mynet == NET_TCPB &&
+ ttnproto == NP_RLOGIN) {
+ if ((x = cmfld(
+ "TCP service name or number,\n or carriage return for rlogin (513)",
+ "login",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+#ifdef CK_AUTHENTICATION
+#ifdef CK_KERBEROS
+ } else if (mynet == NET_TCPB &&
+ (ttnproto == NP_K4LOGIN ||
+ ttnproto == NP_K5LOGIN)) {
+ if ((x = cmfld(
+ "TCP service name or number,\n or carriage return for klogin (543)",
+ "klogin",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+ } else if (mynet == NET_TCPB &&
+ (ttnproto == NP_EK4LOGIN ||
+ ttnproto == NP_EK5LOGIN)) {
+ if ((x = cmfld(
+ "TCP service name or number,\n or carriage return for eklogin (2105)",
+ "eklogin",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+#endif /* CK_KERBEROS */
+#endif /* CK_AUTHENTICATION */
+#endif /* RLOGCODE */
+ } else {
+ /* Do not set a default value in this call */
+ /* If you do then it will prevent entries */
+ /* in the network directory from accessing */
+ /* alternate ports. */
+
+ if ((x = cmfld(
+ "TCP service name or number",
+ "",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+ }
+ } else { /* Incoming connection */
+ if ((x = cmfld("TCP service name or number",
+ "",&s,xxstring)
+ ) < 0 && x != -3)
+ return(x);
+ }
+ if (*s) /* If they gave a service, */
+ ckstrncpy(srvbuf,s,SRVBUFSIZ); /* copy it */
+ debug(F110,"setlin service 0.5",srvbuf,0);
+ }
+#ifdef RLOGCODE
+ }
+#endif /* RLOGCODE */
+ if (!confirmed) {
+ char * defproto;
+ switch (ttnproto) {
+ case NP_RLOGIN:
+ defproto = "/rlogin";
+ break;
+ case NP_K4LOGIN:
+ defproto = "/k4login";
+ break;
+ case NP_K5LOGIN:
+ defproto = "/k5login";
+ break;
+ case NP_EK4LOGIN:
+ defproto = "/ek4login";
+ break;
+ case NP_EK5LOGIN:
+ defproto = "/ek5login";
+ break;
+ case NP_KERMIT:
+ case NP_TELNET:
+ defproto = "/telnet";
+ break;
+ default:
+ defproto = "/default";
+ }
+ if ((x = cmkey(tcprawtab,ntcpraw,"Switch",defproto,
+ xxstring)) < 0) {
+ if (x != -3)
+ return(x);
+ else if ((x = cmcfm()) < 0)
+ return(x);
+ } else {
+ rawflg = x;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ }
+ }
+ }
+ debug(F110,"setlin pre-cx_net line",line,0);
+ debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0);
+ x = cx_net( mynet, /* nettype */
+ rawflg /* protocol */,
+ line, /* host */
+ srvbuf, /* port */
+ tmpusrid, /* alternate username */
+ tmpstring, /* password */
+ NULL, /* command to execute */
+ a_type, /* param1 - telnet authtype */
+ e_type, /* param2 - telnet enctype */
+ wait, /* param3 - telnet wait */
+ cx, /* enter CONNECT mode */
+ sx, /* enter SERVER mode */
+ zz, /* close connection if open */
+ 0 /* gui */
+ );
+ }
+#endif /* TCPSOCKET */
+
+#ifdef CK_SECURITY
+ if (tmpstring)
+ makestr(&tmpstring,NULL);
+#endif /* CK_SECURITY */
+ if (tmpusrid)
+ makestr(&tmpusrid,NULL);
+ debug(F111,"setlin cx_net",line,x);
+ return(x);
+#endif /* NETCONN */
+ }
+
+/* Serial tty device, possibly modem, connection... */
+
+#ifdef OS2
+/*
+ User can type:
+ COM1..COM8 = Regular COM port
+ 1..8 = Synonym for COM1..COM8, is translated to COM1..COM8
+ _n = (n is a number) = open file handle
+ string = any text string = name of some other kind of device,
+ taken literally, as given.
+*/
+ s = "Communication device name";
+
+#ifdef CK_TAPI
+ if (TAPIAvail)
+ cktapiBuildLineTable(&tapilinetab, &_tapilinetab, &ntapiline);
+ if (!(tapilinetab && _tapilinetab && ntapiline > 0) &&
+ xx == XYTAPI_LIN ) {
+ makestr(&slmsg,"TAPI device not configured");
+ printf("\nNo TAPI Line Devices are configured for this system\n");
+ return(-9);
+ }
+ if (xx == XYTAPI_LIN) { /* Default (first) TAPI line */
+ s = "tapi"; /* (whatever it is) */
+ } else { /* Query the user */
+#endif /* CK_TAPI */
+
+/* Now parse optional switches and then device name */
+
+ confirmed = 0;
+ cmfdbi(&sw,_CMKEY,"Device name, or switch",
+ "","",npsltab,4,xxstring,psltab,&fl);
+ cmfdbi(&fl,_CMFLD,"",dftty,"",0,0,xxstring,NULL,NULL);
+ while (1) {
+ x = cmfdb(&sw);
+ debug(F101,"setlin cmfdb","",x);
+ if (x < 0)
+ if (x != -3)
+ return(x);
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) {
+ return(x);
+ } else {
+ confirmed = 1;
+ break;
+ }
+ }
+ if (cmresult.fcode == _CMFLD) {
+ s = cmresult.sresult;
+ break;
+ } else if (cmresult.fcode == _CMKEY) {
+ switch (cmresult.nresult) {
+ case SL_CNX: /* /CONNECT */
+ cx = 1;
+ sx = 0;
+ break;
+ case SL_SRV: /* /SERVER */
+ cx = 0;
+ sx = 1;
+ break;
+ case SL_SHR: /* /SHARE */
+ shr = 1;
+ break;
+ case SL_NSH: /* /NOSHARE */
+ shr = 0;
+ break;
+ }
+ }
+ }
+#ifdef CK_TAPI
+ }
+#endif /* CK_TAPI */
+
+ debug(F110,"OS2 SET PORT s",s,0);
+ y = lookup(os2devtab,s,nos2dev,&x); /* Look up in keyword table */
+ debug(F101,"OS2 SET PORT x","",x);
+ debug(F101,"OS2 SET PORT y","",y);
+ if ((y > -1) && (x >= 0 && x < 8)) { /* User typed a digit 1..8 */
+ s = os2devtab[x+8].kwd; /* Substitite its real name */
+#ifdef NT
+ xxtapi = 0;
+#else /* NT */
+ xxslip = xxppp = 0;
+#endif /* NT */
+ debug(F110,"OS2 SET PORT subst s",s,"");
+#ifndef NT
+ } else if ((y >-1) && (x >= 16 && x < 24)) { /* SLIP access */
+ s = os2devtab[x-8].kwd; /* Substitite its real name */
+ debug(F110,"OS2 SET PORT SLIP subst s",s,"");
+ xxslip = 1;
+ xxppp = 0;
+ } else if ((y >-1) && (x >= 24 && x < 32)) { /* PPP access */
+ s = os2devtab[x-16].kwd; /* Substitite its real name */
+ debug(F110,"OS2 SET PORT PPP subst s",s,"");
+ xxppp = 1;
+ xxslip = 0;
+ if ((y = cmkey(os2ppptab,
+ nos2ppp,
+ "PPP driver interface",
+ "ppp0",
+ xxstring)
+ ) < 0)
+ return(y);
+ debug(F101,"OS2 SET PORT PPP INTERFACE y","",y);
+ xxppp = (y % 10) + 1;
+#endif /* NT */
+ } else if (*s == '_') { /* User used "_" prefix */
+ s++; /* Remove it */
+ /* Rest must be numeric */
+ debug(F110,"OS2 SET PORT HANDLE _subst s",s,0);
+ if (!rdigits(s)) {
+ makestr(&slmsg,"Invalid file handle");
+ printf("?Invalid format for file handle\n");
+ return(-9);
+ }
+#ifdef NT
+ xxtapi = 0;
+#else /* NT */
+ xxslip = xxppp = 0;
+#endif /* NT */
+ } else { /* A normal COMx port or a string */
+ s = brstrip(s); /* Strip braces if any */
+#ifdef NT
+#ifdef CK_TAPI
+ /* Windows TAPI support - Look up in keyword table */
+ if (tapilinetab && _tapilinetab && ntapiline > 0) {
+ if (!ckstrcmp(s,"tapi",4,0)) {
+
+ /* Find out what the lowest numbered TAPI device is */
+ /* and use it as the default. */
+ int j = 9999, k = -1;
+ for (i = 0; i < ntapiline; i++) {
+ if (tapilinetab[i].kwval < j) {
+ j = tapilinetab[i].kwval;
+ k = i;
+ }
+ }
+ if (k >= 0)
+ s = _tapilinetab[k].kwd;
+ else
+ s = "";
+
+ if ((y = cmkey(_tapilinetab,ntapiline,
+ "TAPI device name",s,xxstring)) < 0)
+ return(y);
+
+ xxtapi = 1;
+
+ /* Get the non Underscored string */
+ for (i = 0; i < ntapiline; i++ ) {
+ if (tapilinetab[i].kwval == y) {
+ s = tapilinetab[i].kwd;
+ break;
+ }
+ }
+ } else
+ xxtapi = 0;
+ }
+#endif /* CK_TAPI */
+#else /* NT */
+ /* not OS/2 SLIP or PPP */
+ xxslip = xxppp = 0;
+#endif /* NT */
+ }
+ ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Copy to a safe place */
+ s = tmpbuf;
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#else /* !OS2 */
+
+ cmfdbi(&sw,_CMKEY,"Device name, or switch",
+ "","",npsltab,4,xxstring,psltab,&tx);
+ cmfdbi(&tx,_CMTXT,"",dftty,"",0,0,xxstring,NULL,NULL);
+ while (!confirmed) {
+ x = cmfdb(&sw);
+ debug(F101,"setlin cmfdb","",x);
+ if (x < 0)
+ if (x != -3)
+ return(x);
+ if (x == -3) {
+ if ((x = cmcfm()) < 0) {
+ return(x);
+ } else {
+ confirmed = 1;
+ break;
+ }
+ }
+ switch (cmresult.fcode) {
+ case _CMTXT:
+ ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
+ s = tmpbuf;
+ debug(F110,"setlin CMTXT",tmpbuf,0);
+ confirmed = 1;
+ break;
+ case _CMKEY: /* Switch */
+ debug(F101,"setlin CMKEY",tmpbuf,cmresult.nresult);
+ switch (cmresult.nresult) {
+ case SL_CNX: /* /CONNECT */
+ cx = 1;
+ sx = 0;
+ break;
+ case SL_SRV: /* /SERVER */
+ cx = 0;
+ sx = 1;
+ break;
+#ifdef VMS
+ case SL_SHR: /* /SHARE */
+ shr = 1;
+ break;
+ case SL_NSH: /* /NOSHARE */
+ shr = 0;
+ break;
+#endif /* VMS */
+ }
+ continue;
+ default:
+ debug(F101,"setlin bad cmfdb result","",cmresult.fcode);
+ makestr(&slmsg,"Internal error");
+ printf("?Internal parsing error\n");
+ return(-9);
+ }
+ }
+#endif /* OS2 */
+ if (!confirmed)
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ debug(F110,"setlin pre-cx_serial s",s,0);
+ debug(F110,"setlin pre-cx_serial line",line,0);
+ x = cx_serial(s,cx,sx,shr,zz,0,
+#ifdef OS2
+#ifdef NT
+ (xxtapi ? CX_TAPI : 0)
+#else
+ (xxslip ? CX_SLIP : 0) | (xxppp ? CX_PPP : 0)
+#endif /* NT */
+#else /* OS2 */
+ 0
+#endif /* OS2 */
+ );
+ debug(F111,"setlin cx_serial",line,x);
+ return(x);
+}
+#endif /* NOLOCAL */
+
+#ifdef CKCHANNELIO
+/*
+ C-Library based file-i/o package for scripts. This should be portable to
+ all C-Kermit versions since it uses the same APIs we have always used for
+ processing command files. The entire channel i/o package is contained
+ herein, apart from some keyword table entries in the main keyword table
+ and the help text in the HELP command module.
+
+ On platforms like VMS and VOS, this package handles only UNIX-style
+ stream files. If desired, it can be replaced for those platforms by
+ <#>ifdef'ing out this code and adding the equivalent replacement routines
+ to the ck?fio.c module, e.g. for RMS-based file i/o in ckvfio.c.
+*/
+
+/* Define NOSTAT if the <#>include causes trouble. */
+
+#ifndef NOSTAT
+#ifdef VMS
+#ifdef VAXC /* As it does in VAX C */
+#define NOSTAT
+#endif /* VAXC */
+#endif /* VMS */
+#endif /* NOSTAT */
+
+#ifndef NOSTAT
+#include <sys/stat.h>
+#endif /* NOSTAT */
+
+#ifdef NLCHAR
+static int z_lt = 1; /* Length of line terminator */
+#else
+static int z_lt = 2;
+#endif /* NLCHAR */
+
+struct ckz_file { /* C-Kermit file struct */
+ FILE * z_fp; /* Includes the C-Lib file struct */
+ unsigned int z_flags; /* Plus C-Kermit mode flags, */
+ long z_nline; /* current line number if known, */
+ char z_name[CKMAXPATH+2]; /* and the file's name. */
+};
+static struct ckz_file * z_file = NULL; /* Array of C-Kermit file structs */
+static int z_inited = 0; /* Flag for array initialized */
+int z_maxchan = Z_MAXCHAN; /* Max number of C-Kermit channels */
+int z_openmax = CKMAXOPEN; /* Max number of open files overall */
+int z_nopen = 0; /* How many channels presently open */
+int z_error = 0; /* Most recent error */
+int z_filcount = -1; /* Most recent FILE COUNT result */
+
+#define RD_LINE 0 /* FILE READ options */
+#define RD_CHAR 1
+#define RD_SIZE 2
+#define RD_TRIM 8 /* Like Snobol &TRIM = 1 */
+#define RD_UNTA 9 /* Untabify */
+
+#define WR_LINE RD_LINE /* FILE WRITE options */
+#define WR_CHAR RD_CHAR
+#define WR_SIZE RD_SIZE
+#define WR_STRI 3
+#define WR_LPAD 4
+#define WR_RPAD 5
+
+#ifdef UNIX
+extern int ckmaxfiles; /* Filled in by sysinit(). */
+#endif /* UNIX */
+
+/* See ckcker.h for error numbers */
+/* See ckcdeb.h for Z_MAXCHAN and CKMAXOPEN definitions */
+/* NOTE: For VMS we might be able to fill in ckmaxfiles */
+/* from FILLM and CHANNELCNT -- find out about these... */
+
+static char * fopnargs[] = { /* Mode combinations for fopen() */
+#ifdef COMMENT
+ /* All combinations of rwa */
+ "", "r", "w", "rw", "a", "ra", "wa", "rwa", /* Text mode */
+ "b", "rb", "wb", "rwb", "ab", "rab", "wab", "rwab" /* Binary mode */
+#else
+ /* Combinations and syntax permitted by C libraries... */
+ "", "r", "w", "r+", "a", "", "a", "", /* Text mode */
+#ifdef OS2
+ "", "rb", "wb", "r+b", "ab", "", "ab", "" /* Binary modes for K95 */
+#else
+#ifdef VMS
+ "", "rb", "wb", "r+b", "ab", "", "ab", "" /* Binary modes for VMS */
+#else
+ "", "r", "w", "r+", "a", "", "a", "" /* Binary modes for UNIX */
+#endif /* VMS */
+#endif /* OS2 */
+#endif /* COMMENT */
+};
+static int nfopnargs = sizeof(fopnargs) / sizeof(char *);
+
+char * /* Error messages */
+ckferror(n) int n; {
+ switch (n) {
+ case FX_NER: return("No error");
+ case FX_SYS: return(ck_errstr());
+ case FX_EOF: return("End of file");
+ case FX_NOP: return("File not open");
+ case FX_CHN: return("Channel out of range");
+ case FX_RNG: return("Parameter out of range");
+ case FX_NMF: return("Too many files open");
+ case FX_FOP: return("Operation conflicts with OPEN mode");
+ case FX_NYI: return("OPEN mode not supported");
+ case FX_BOM: return("Illegal combination of OPEN modes");
+ case FX_ACC: return("Access denied");
+ case FX_FNF: return("File not found");
+ case FX_OFL: return("Buffer overflow");
+ case FX_LNU: return("Current line number unknown");
+ case FX_ROO: return("Off limits");
+ case FX_UNK: return("Operation fails - reason unknown");
+ default: return("Error number out of range");
+ }
+}
+
+/*
+ Z _ O P E N -- Open a file for the requested type of access.
+
+ Call with:
+ name: Name of file to be opened.
+ flags: Any combination of FM_xxx values except FM_EOF (ckcker.h).
+ Returns:
+ >= 0 on success: The assigned channel number
+ < 0 on failure: A negative FX_xxx error code (ckcker.h).
+*/
+int
+z_open(name, flags) char * name; int flags; {
+ int i, n;
+ FILE * t;
+ char * mode;
+ debug(F111,"z_open",name,flags);
+ if (!name) name = ""; /* Check name argument */
+ if (!name[0])
+ return(z_error = FX_BFN);
+ if (flags & FM_CMD) /* Opening pipes not implemented yet */
+ return(z_error = FX_NYI); /* (and not portable either) */
+ debug(F101,"z_open nfopnargs","",nfopnargs);
+ if (flags < 0 || flags >= nfopnargs) /* Range check flags */
+ return(z_error = FX_RNG);
+ mode = fopnargs[flags]; /* Get fopen() arg */
+ debug(F111,"z_open fopen args",mode,flags);
+ if (!mode[0]) /* Check for illegal combinations */
+ return(z_error = FX_BOM);
+ if (!z_inited) { /* If file structs not inited */
+ debug(F101,"z_open z_maxchan 1","",z_maxchan);
+#ifdef UNIX
+ debug(F101,"z_open ckmaxfiles","",ckmaxfiles);
+ if (ckmaxfiles > 0) { /* Set in ck?tio.c: sysinit() */
+ int x;
+ x = ckmaxfiles - ZNFILS - 5;
+ if (x > z_maxchan) /* sysconf() value greater than */
+ z_maxchan = x; /* value from header files. */
+ debug(F101,"z_open z_maxchan 2","",z_maxchan);
+ }
+#endif /* UNIX */
+ if (z_maxchan < Z_MINCHAN) /* Allocate at least this many. */
+ z_maxchan = Z_MINCHAN;
+ debug(F101,"z_open z_maxchan 3","",z_maxchan);
+ /* Note: This could be a pretty big chunk of memory */
+ /* if z_maxchan is a big number. If this becomes a problem */
+ /* we'll need to malloc and free each element at open/close time */
+ if (!(z_file = (struct ckz_file *)
+ malloc(sizeof(struct ckz_file) * (z_maxchan + 1))))
+ return(z_error = FX_NMF);
+ for (i = 0; i < z_maxchan; i++) {
+ z_file[i].z_fp = NULL;
+ z_file[i].z_flags = 0;
+ z_file[i].z_nline = 0;
+ *(z_file[i].z_name) = '\0';
+ }
+ z_inited = 1; /* Remember we did */
+ }
+ for (n = -1, i = 0; i < z_maxchan; i++) {
+ if (!z_file[i].z_fp) {
+ n = i;
+ break;
+ }
+ }
+ if (n < 0 || n >= z_maxchan) /* Any free channels? */
+ return(z_error = FX_NMF); /* No, fail. */
+ errno = 0;
+
+ z_file[n].z_flags = 0; /* In case of failure... */
+
+ t = fopen(name, mode); /* Try to open the file. */
+ if (!t) { /* Failed... */
+ debug(F111,"z_open error",name,errno);
+#ifdef EMFILE
+ if (errno == EMFILE)
+ return(z_error = FX_NMF);
+#endif /* EMFILE */
+ return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error code */
+ }
+#ifdef NT
+#ifdef O_SEQUENTIAL
+ if (t) /* Caching hint for NT */
+ _setmode(_fileno(t),O_SEQUENTIAL);
+#endif /* O_SEQUENTIAL */
+#endif /* NT */
+ z_nopen++; /* Open, count it. */
+ z_file[n].z_fp = t; /* Stash the file pointer */
+ z_file[n].z_flags = flags; /* and the flags */
+ z_error = 0;
+ zfnqfp(name,CKMAXPATH,z_file[n].z_name); /* and the file's full name */
+ return(n); /* Return the channel number */
+}
+
+int
+z_close(channel) int channel; { /* Close file on given channel */
+ int x;
+ FILE * t;
+ if (!z_inited) /* Called before any files are open? */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan) /* Channel out of range? */
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp)) /* Channel wasn't open? */
+ return(z_error = FX_NOP);
+ errno = 0; /* Set errno 0 to get a good reading */
+ x = fclose(t); /* Try to close */
+ if (x == EOF) /* On failure */
+ return(z_error = FX_SYS); /* indicate system error. */
+ z_nopen--; /* Closed OK, decrement open count */
+ z_file[channel].z_fp = NULL; /* Set file pointer to NULL */
+ z_file[channel].z_nline = 0; /* Current line number is 0 */
+ z_file[channel].z_flags = 0; /* Set flags to 0 */
+ *(z_file[channel].z_name) = '\0'; /* Clear name */
+ return(z_error = 0);
+}
+
+/*
+ Z _ O U T -- Output string to channel.
+
+ Call with:
+ channel: Channel number to write to.
+ s: String to write.
+ length > -1: How many characters of s to write.
+ length < 0: Write entire NUL-terminated string.
+ flags == 0: Supply line termination.
+ flags > 0: Don't supply line termination.
+ flags < 0: Write 'length' NUL characters.
+ Special case:
+ If flags > -1 and s is empty or NULL and length == 1, write 1 NUL.
+ Returns:
+ Number of characters written to channel on success, or
+ negative FX_xxx error code on failure.
+*/
+int
+z_out(channel,s,length,flags) int channel, flags, length; char * s; {
+ FILE * t;
+ int x, n;
+ char c = '\0';
+
+ if (!s) s = ""; /* Guard against null pointer */
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"z_out",s,channel);
+ debug(F101,"z_out length","",length);
+ debug(F101,"z_out flags","",flags);
+ }
+#endif /* DEBUG */
+ if (!z_inited) /* File i/o inited? */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan) /* Channel in range? */
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp)) /* File open? */
+ return(z_error = FX_NOP);
+ if (!((z_file[channel].z_flags) & (FM_WRI|FM_APP))) /* In write mode? */
+ return(z_error = FX_FOP);
+ n = length; /* Length of string to write */
+ if (n < 0) { /* Negative means get it ourselves */
+ if (flags < 0) /* Except when told to write NULs in */
+ return(z_error = FX_RNG); /* which case args are inconsistent */
+ n = strlen(s); /* Get length of string arg */
+ }
+ errno = 0; /* Reset errno */
+ debug(F101,"z_out n","",n);
+ if (flags < 0) { /* Writing NULs... */
+ int i;
+ for (i = 0; i < n; i++) {
+ x = fwrite(&c,1,1,t);
+ if (x < 1)
+ return(z_error = (errno ? FX_SYS : FX_UNK));
+ }
+ z_file[channel].z_nline = -1; /* Current line no longer known */
+ z_error = 0;
+ return(i);
+ } else { /* Writing string arg */
+ if (n == 1 && !s[0]) /* Writing one char but it's NUL */
+ x = fwrite(&c,1,1,t);
+ else /* Writing non-NUL char or string */
+ x = fwrite(s,1,n,t);
+ debug(F101,"z_out fwrite",ckitoa(x),errno);
+ if (x < n) /* Failure to write requested amount */
+ return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error */
+ if (flags == 0) { /* If supplying line termination */
+ if (fwrite("\n",1,1,t)) /* do that */
+ x += z_lt; /* count the terminator */
+ if (z_file[channel].z_nline > -1) /* count this line */
+ z_file[channel].z_nline++;
+ } else {
+ z_file[channel].z_nline = -1; /* Current line no longer known */
+ }
+ }
+ z_error = 0;
+ return(x);
+}
+
+#define Z_INBUFLEN 64
+
+/*
+ Z _ I N -- Multichannel i/o file input function.
+
+ Call with:
+ channel number to read from.
+ s = address of destination buffer.
+ buflen = destination buffer length.
+ length = Number of bytes to read, must be < buflen.
+ flags: 0 = read a line; nonzero = read the given number of bytes.
+ Returns:
+ Number of bytes read into buffer or a negative error code.
+ A terminating NUL is deposited after the last byte that was read.
+*/
+int
+z_in(channel,s,buflen,length,flags)
+ int channel, buflen, length, flags; char * s;
+/* z_in */ {
+ int i, j, x;
+ FILE * t;
+ char * p;
+
+ if (!z_inited) /* Check everything... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ if (!((z_file[channel].z_flags) & FM_REA))
+ return(z_error = FX_FOP);
+ if (!s) /* Check destination */
+ return(z_error = FX_RNG);
+ s[0] = NUL;
+ if (length == 0) /* Read 0 bytes - easy. */
+ return(z_error = 0);
+ debug(F101,"z_in channel","",channel);
+ debug(F101,"z_in buflen","",buflen);
+ debug(F101,"z_in length","",length);
+ debug(F101,"z_in flags","",flags);
+ if (length < 0 || buflen < 0) /* Check length args */
+ return(z_error = FX_RNG);
+ if (buflen <= length)
+ return(z_error = FX_RNG);
+ errno = 0; /* Reset errno */
+ if (flags) { /* Read block or byte */
+ i = fread(s,1,length,t);
+#ifdef DEBUG
+ if (deblog) {
+ debug(F111,"z_in block",s,i);
+ debug(F101,"z_in block errno","",errno);
+ debug(F101,"z_in block ferror","",ferror(t));
+ debug(F101,"z_in block feof","",feof(t));
+ }
+#endif /* DEBUG */
+ z_file[channel].z_nline = -1; /* Current line no longer known */
+ } else { /* Read line */
+#ifndef COMMENT
+ /* This method is used because it's simpler than the others */
+ /* and also marginally faster. */
+ debug(F101,"z_in getc loop","",ftell(t));
+ for (i = 0; i < length; i++) {
+ if ((x = getc(t)) == EOF) {
+ debug(F101,"z_in getc error","",ftell(t));
+ s[i] = '\0';
+ break;
+ }
+ s[i] = x;
+ if (s[i] == '\n') {
+ s[i] = '\0';
+ break;
+ }
+ }
+ debug(F111,"z_in line byte loop",ckitoa(errno),i);
+ debug(F111,"z_in line got",s,z_file[channel].z_nline);
+ if (z_file[channel].z_nline > -1)
+ z_file[channel].z_nline++;
+#else
+#ifdef COMMENT2
+ /* Straightforward but strlen() slows it down. */
+ s[0] = '\0';
+ i = 0;
+ if (fgets(s,length,t)) {
+ i = strlen(s);
+ if (i > 0 && s[i-1] == '\n') i--;
+ }
+ debug(F111,"z_in line fgets",ckitoa(errno),i);
+ if (z_file[channel].z_nline > -1)
+ z_file[channel].z_nline++;
+#else
+ /* This is a do-it-yourself fgets() with its own readahead and */
+ /* putback. It's a bit faster than real fgets() but not enough */
+ /* to justify the added complexity or the risk of the ftell() and */
+ /* fseek() calls failing. */
+ int k, flag = 0;
+ long pos;
+ for (i = 0; !flag && i <= (length - Z_INBUFLEN); i += Z_INBUFLEN) {
+ k = ((length - i) < Z_INBUFLEN) ? length - i : Z_INBUFLEN;
+ if ((x = fread(s+i,1,k,t)) < 1)
+ break;
+ s[i+x] = '\0';
+ for (j = 0; j < x; j++) {
+ if (s[i+j] == '\n') {
+ s[i+j] = '\0';
+ flag ++;
+ pos = ftell(t);
+ if (pos > -1) {
+ pos -= (x - j - 1);
+ x = fseek(t, pos, 0);
+ i += j;
+ break;
+ } else
+ return(z_error = FX_SYS);
+ }
+ }
+ }
+ if (z_file[channel].z_nline > -1)
+ z_file[channel].z_nline++;
+ debug(F111,"z_in line chunk loop",ckitoa(errno),i);
+#endif /* COMMENT2 */
+#endif /* COMMENT */
+ }
+ debug(F111,"z_in i",ckitoa(errno),i);
+ if (i < 0) i = 0; /* NUL-terminate result */
+ s[i] = '\0';
+ if (i > 0) {
+ z_error = 0;
+ return(i);
+ }
+ if (i == 0 && feof(t)) /* EOF on reading? */
+ return(z_error = FX_EOF); /* Return EOF code */
+ return(errno ? (z_error = -1) : i); /* Return length or system error */
+}
+
+int
+z_flush(channel) int channel; { /* Flush output channel */
+ FILE * t;
+ int x;
+ if (!z_inited) /* Regular checks */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ if (!((z_file[channel].z_flags) & (FM_WRI|FM_APP))) /* Write access? */
+ return(z_error = FX_FOP);
+ errno = 0; /* Reset errno */
+ x = fflush(t); /* Try to flush */
+ return(x ? (z_error = FX_SYS) : 0); /* Return system error or 0 if OK */
+}
+
+int
+#ifdef CK_ANSIC
+z_seek(int channel, long pos) /* Move file pointer to byte */
+#else
+z_seek(channel,pos) int channel; long pos; /* (seek to given position) */
+#endif /* CK_ANSIC */
+{
+ int i, x = 0, rc;
+ FILE * t;
+ if (!z_inited) /* Check... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ if (pos < 0L) {
+ x = 2;
+ pos = (pos == -2) ? -1L : 0L;
+ }
+ errno = 0;
+ rc = fseek(t,pos,x); /* Try to seek */
+ debug(F111,"z_seek",ckitoa(errno),rc);
+ if (rc < 0) /* OK? */
+ return(z_error = FX_SYS); /* No. */
+ z_file[channel].z_nline = ((pos || x) ? -1 : 0);
+ return(z_error = 0);
+}
+
+int
+#ifdef CK_ANSIC
+z_line(int channel, long pos) /* Move file pointer to line */
+#else
+z_line(channel,pos) int channel; long pos; /* (seek to given position) */
+#endif /* CK_ANSIC */
+{
+ int i, len, x = 0;
+ long current = 0L, prev = -1L, old = -1L;
+ FILE * t;
+ char tmpbuf[256];
+ if (!z_inited) /* Check... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ debug(F101,"z_line pos","",pos);
+ if (pos < 0L) { /* EOF wanted */
+ long n;
+ n = z_file[channel].z_nline;
+ debug(F101,"z_line n","",n);
+ if (n < 0 || pos < 0) {
+ rewind(t);
+ n = 0;
+ }
+ while (1) { /* This could take a while... */
+ if ((x = getc(t)) == EOF)
+ break;
+ if (x == '\n') {
+ n++;
+ if (pos == -2) {
+ old = prev;
+ prev = ftell(t);
+ }
+ }
+ }
+ debug(F101,"z_line old","",old);
+ debug(F101,"z_line prev","",prev);
+ if (pos == -2) {
+ if ((x = z_seek(channel,old)) < 0)
+ return(z_error = x);
+ else
+ n--;
+ }
+ z_file[channel].z_nline = n;
+ return(z_error = 0);
+ }
+ if (pos == 0L) { /* Rewind wanted */
+ z_file[channel].z_nline = 0L;
+ rewind(t);
+ debug(F100,"z_line rewind","",0);
+ return(0L);
+ }
+ tmpbuf[255] = NUL; /* Make sure buf is NUL terminated */
+ current = z_file[channel].z_nline; /* Current line */
+ /*
+ If necessary the following could be optimized, e.g. for positioning
+ to a previous line in a large file without starting over.
+ */
+ if (current < 0 || pos < current) { /* Not known or behind us... */
+ debug(F101,"z_line rewinding","",pos);
+ if ((x = z_seek(channel, 0L)) < 0) /* Rewind */
+ return(z_error = x);
+ if (pos == 0) /* If 0th line wanted we're done */
+ return(z_error = 0);
+ current = 0;
+ }
+ while (current < pos) { /* Search for specified line */
+ if (fgets(tmpbuf,255,t)) {
+ len = strlen(tmpbuf);
+ if (len > 0 && tmpbuf[len-1] == '\n') {
+ current++;
+ debug(F111,"z_line read",ckitoa(len),current);
+ } else if (len == 0) {
+ return(z_error = FX_UNK);
+ }
+ } else {
+ z_file[channel].z_nline = -1L;
+ debug(F101,"z_line premature EOF","",current);
+ return(z_error = FX_EOF);
+ }
+ }
+ z_file[channel].z_nline = current;
+ debug(F101,"z_line result","",current);
+ z_error = 0;
+ return(current);
+}
+
+char *
+z_getname(channel) int channel; { /* Return name of file on channel */
+ FILE * t;
+ if (!z_inited) {
+ z_error = FX_NOP;
+ return(NULL);
+ }
+ if (channel >= z_maxchan) {
+ z_error = FX_CHN;
+ return(NULL);
+ }
+ if (!(t = z_file[channel].z_fp)) {
+ z_error = FX_NOP;
+ return(NULL);
+ }
+ return((char *)(z_file[channel].z_name));
+}
+
+int
+z_getmode(channel) int channel; { /* Return OPEN modes of channel */
+ FILE * t; /* 0 if file not open */
+#ifndef NOSTAT
+#ifdef NT
+ struct _stat statbuf;
+#else /* NT */
+ struct stat statbuf;
+#endif /* NT */
+#endif /* NOSTAT */
+ int x;
+ if (!z_inited)
+ return(0);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(0);
+ x = z_file[channel].z_flags;
+ if (feof(t)) { /* This might not work for */
+ x |= FM_EOF; /* output files */
+#ifndef NOSTAT
+ /* But this does if we can use it. */
+ } else if (stat(z_file[channel].z_name,&statbuf) > -1) {
+ if (ftell(t) == statbuf.st_size)
+ x |= FM_EOF;
+#endif /* NOSTAT */
+ }
+ return(x);
+}
+
+long
+z_getpos(channel) int channel; { /* Get file pointer position */
+ FILE * t; /* on this channel */
+ long x;
+ if (!z_inited)
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ x = ftell(t);
+ return((x < 0L) ? (z_error = FX_SYS) : x);
+}
+
+long
+z_getline(channel) int channel; { /* Get current line number */
+ FILE * t; /* in file on this channel */
+ long rc;
+ if (!z_inited)
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ debug(F101,"z_getline","",z_file[channel].z_nline);
+ rc = z_file[channel].z_nline;
+ return((rc < 0) ? (z_error = FX_LNU) : rc);
+}
+
+int
+z_getfnum(channel) int channel; { /* Get file number / handle */
+ FILE * t; /* for file on this channel */
+ if (!z_inited)
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ z_error = 0;
+ return(fileno(t));
+}
+
+/*
+ Line-oriented counts and seeks are as dumb as they can be at the moment.
+ Later we can speed them up by building little indexes.
+*/
+long
+z_count(channel, what) int channel, what; { /* Count bytes or lines in file */
+ FILE * t;
+ int i, x;
+ long pos, count = 0L;
+ if (!z_inited) /* Check stuff... */
+ return(z_error = FX_NOP);
+ if (channel >= z_maxchan)
+ return(z_error = FX_CHN);
+ if (!(t = z_file[channel].z_fp))
+ return(z_error = FX_NOP);
+ pos = ftell(t); /* Save current file pointer */
+ errno = 0;
+ z_error = 0;
+ if (what == RD_CHAR) { /* Size in bytes requested */
+ if (!fseek(t,0L,2)) { /* Seek to end */
+ count = ftell(t); /* Get file pointer */
+ fseek(t,pos,0); /* Restore file file pointer */
+ return(count);
+ } else /* Fallback in case seek fails */
+ return(zgetfs(z_file[channel].z_name));
+ }
+ rewind(t); /* Line count requested - rewind. */
+ while (1) { /* Count lines. */
+ if ((x = getc(t)) == EOF) /* Stupid byte loop */
+ break; /* but it works as well as anything */
+ if (x == '\n') /* else... */
+ count++;
+ }
+ x = fseek(t,pos,0); /* Restore file pointer */
+ return(count);
+}
+
+/* User interface for generalized channel-oriented file i/o */
+
+struct keytab fctab[] = { /* FILE subcommands */
+ { "close", FIL_CLS, 0 },
+ { "count", FIL_COU, 0 },
+ { "flush", FIL_FLU, 0 },
+ { "list", FIL_LIS, 0 },
+ { "open", FIL_OPN, 0 },
+ { "read", FIL_REA, 0 },
+ { "rewind", FIL_REW, 0 },
+ { "seek", FIL_SEE, 0 },
+ { "status", FIL_STA, 0 },
+ { "write", FIL_WRI, 0 }
+};
+int nfctab = (sizeof (fctab) / sizeof (struct keytab));
+
+static struct keytab fcswtab[] = { /* OPEN modes */
+ { "/append", FM_APP, 0 },
+ { "/binary", FM_BIN, 0 },
+#ifdef COMMENT
+ { "/command", FM_CMD, 0 }, /* Not implemented */
+#endif /* COMMENT */
+ { "/read", FM_REA, 0 },
+ { "/write", FM_WRI, 0 }
+};
+static int nfcswtab = (sizeof (fcswtab) / sizeof (struct keytab));
+
+static struct keytab fclkwtab[] = { /* CLOSE options */
+ { "all", 1, 0 }
+};
+
+static struct keytab fsekwtab[] = { /* SEEK symbols */
+ { "eof", 1, 0 },
+ { "last", 2, 0 }
+};
+static int nfsekwtab = (sizeof (fsekwtab) / sizeof (struct keytab));
+
+#define SEE_LINE RD_LINE /* SEEK options */
+#define SEE_CHAR RD_CHAR
+#define SEE_REL 3
+#define SEE_ABS 4
+
+static struct keytab fskswtab[] = {
+ { "/absolute", SEE_ABS, 0 },
+ { "/byte", SEE_CHAR, 0 },
+ { "/character", SEE_CHAR, CM_INV },
+ { "/line", SEE_LINE, 0 },
+ { "/relative", SEE_REL, 0 }
+};
+static int nfskswtab = (sizeof (fskswtab) / sizeof (struct keytab));
+
+#define COU_LINE RD_LINE /* COUNT options */
+#define COU_CHAR RD_CHAR
+#define COU_LIS 3
+#define COU_NOL 4
+
+static struct keytab fcoswtab[] = {
+ { "/bytes", COU_CHAR, 0 },
+ { "/characters",COU_CHAR, CM_INV },
+ { "/lines", COU_LINE, 0 },
+ { "/list", COU_LIS, 0 },
+ { "/nolist", COU_NOL, 0 },
+ { "/quiet", COU_NOL, CM_INV }
+};
+static int nfcoswtab = (sizeof (fcoswtab) / sizeof (struct keytab));
+
+static struct keytab frdtab[] = { /* READ types */
+ { "/block", RD_SIZE, CM_INV|CM_ARG },
+ { "/byte", RD_CHAR, CM_INV },
+ { "/character", RD_CHAR, 0 },
+ { "/line", RD_LINE, 0 },
+ { "/size", RD_SIZE, CM_ARG },
+ { "/trim", RD_TRIM, 0 },
+ { "/untabify", RD_UNTA, 0 }
+};
+static int nfrdtab = (sizeof (frdtab) / sizeof (struct keytab));
+
+static struct keytab fwrtab[] = { /* WRITE types */
+ { "/block", WR_SIZE, CM_INV|CM_ARG },
+ { "/byte", WR_CHAR, CM_INV },
+ { "/character", WR_CHAR, 0 },
+ { "/line", WR_LINE, 0 },
+ { "/lpad", WR_LPAD, CM_ARG },
+ { "/rpad", WR_RPAD, CM_ARG },
+ { "/size", WR_SIZE, CM_ARG },
+ { "/string", WR_STRI, 0 }
+};
+static int nfwrtab = (sizeof (fwrtab) / sizeof (struct keytab));
+
+static char blanks[] = "\040\040\040\040"; /* Some blanks for formatting */
+
+int
+dofile(op) int op; { /* Do the FILE command */
+ char vnambuf[VNAML]; /* Buffer for variable names */
+ char *vnp = NULL; /* Pointer to same */
+ char zfilnam[CKMAXPATH+2];
+ char * p;
+ struct FDB fl, sw, nu;
+ long z;
+ int rsize, filmode = 0, relative = -1, eofflg = 0;
+ int rc, x, y, cx, n, getval, dummy, confirmed, listing = -1;
+ int charflag = 0, sizeflag = 0;
+ int pad = 32, wr_lpad = 0, wr_rpad = 0, rd_trim = 0, rd_untab = 0;
+
+ if (op == XXFILE) { /* FILE command was given */
+ /* Get subcommand */
+ if ((cx = cmkey(fctab,nfctab,"Operation","",xxstring)) < 0) {
+ if (cx == -3) {
+ printf("?File operation required\n");
+ x = -9;
+ }
+ return(cx);
+ }
+ } else { /* Shorthand command was given */
+ switch (op) {
+ case XXF_CL: cx = FIL_CLS; break; /* FCLOSE */
+ case XXF_FL: cx = FIL_FLU; break; /* FFLUSH */
+ case XXF_LI: cx = FIL_LIS; break; /* FLIST */
+ case XXF_OP: cx = FIL_OPN; break; /* etc... */
+ case XXF_RE: cx = FIL_REA; break;
+ case XXF_RW: cx = FIL_REW; break;
+ case XXF_SE: cx = FIL_SEE; break;
+ case XXF_ST: cx = FIL_STA; break;
+ case XXF_WR: cx = FIL_WRI; break;
+ case XXF_CO: cx = FIL_COU; break;
+ default: return(-2);
+ }
+ }
+ switch (cx) { /* Do requested subcommand */
+ case FIL_OPN: /* OPEN */
+ cmfdbi(&sw, /* Switches */
+ _CMKEY, /* fcode */
+ "Variable or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ nfcswtab, /* addtl numeric data 1: tbl size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ fcswtab, /* Keyword table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* Anything that doesn't match */
+ _CMFLD, /* fcode */
+ "Variable", /* hlpmsg */
+ "",
+ "",
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+ while (1) {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Variable name and file name required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMFLD)
+ break;
+ else if (cmresult.fcode == _CMKEY) {
+ char c;
+ c = cmgbrk();
+ if ((getval =
+ (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+#ifdef COMMENT
+ /* Uncomment if we add any switches ere that take args */
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9); /* (none do...) */
+ }
+#endif /* COMMENT */
+ filmode |= cmresult.nresult; /* OR in the file mode */
+ } else
+ return(-2);
+ }
+ /* Not a switch - get the string */
+ ckstrncpy(vnambuf,cmresult.sresult,VNAML);
+ if (!vnambuf[0] || chknum(vnambuf)) { /* (if there is one...) */
+ printf("?Variable name required\n");
+ return(-9);
+ }
+ vnp = vnambuf; /* Check variable-name syntax */
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&dummy)) < 0) {
+ printf("?Syntax error in variable name\n");
+ return(-9);
+ }
+ }
+ if (!(filmode & FM_RWA)) /* If no access mode specified */
+ filmode |= FM_REA; /* default to /READ. */
+
+ y = 0; /* Now parse the filename */
+ if ((filmode & FM_RWA) == FM_WRI)
+ x = cmofi("Name of new file","",&s,xxstring);
+ else if ((filmode & FM_RWA) == FM_REA)
+ x = cmifi("Name of existing file","",&s,&y,xxstring);
+ else {
+ x = cmiofi("Filename","",&s,&y,xxstring);
+ debug(F101,"fopen /append x","",x);
+ }
+ if (x == -9) {
+ if (zchko(s) < 0) {
+ printf("Can't create \"%s\"\n",s);
+ return(x);
+ }
+ } else if (x < 0) {
+ if (x == -3) {
+ printf("?Filename required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (y) { /* No wildcards */
+ printf("?Wildcards not allowed here\n");
+ return(-9);
+ }
+ if (filmode & (FM_APP|FM_WRI)) { /* Check output access */
+#ifndef VMS
+ if (zchko(s) < 0) { /* and set error code if denied */
+ z_error = FX_ACC;
+ printf("?Write access denied - \"%s\"\n",s);
+ return(-9);
+ }
+#endif /* VMS */
+ }
+ ckstrncpy(zfilnam,s,CKMAXPATH); /* Is OK - make safe copy */
+ if ((x = cmcfm()) < 0) /* Get confirmation of command */
+ return(x);
+ if ((n = z_open(zfilnam,filmode)) < 0) {
+ printf("?OPEN failed - %s: %s\n",zfilnam,ckferror(n));
+ return(-9);
+ }
+ addmac(vnambuf,ckitoa(n)); /* Assign channel number to variable */
+ return(success = 1);
+
+ case FIL_REW: /* REWIND */
+ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if ((rc = z_seek(n,0L)) < 0) {
+ printf("?REWIND failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ return(success = 1);
+
+ case FIL_CLS: /* CLOSE */
+ cmfdbi(&sw, /* Second FDB - switches */
+ _CMKEY, /* fcode */
+ "Channel number; or keyword",
+ "",
+ "", /* addtl string data */
+ 1, /* addtl numeric data 1: tbl size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ fclkwtab, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* First FDB - command switches */
+ _CMNUM, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ ); /* */
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number or ALL required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM)
+ n = cmresult.nresult;
+ else if (cmresult.fcode == _CMKEY)
+ n = -1;
+ if ((x = cmcfm()) < 0)
+ return(x);
+ rc = 1;
+ if (n < 0) {
+ int count = 0;
+ int i;
+ for (i = 0; i < z_maxchan; i++) {
+ x = z_close(i);
+ if (x == FX_SYS) {
+ printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x));
+ rc = 0;
+ } else if (x > -1)
+ count++;
+ }
+ debug(F101,"FILE CLOSE ALL","",count);
+ } else if ((x = z_close(n)) < 0) {
+ printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x));
+ return(-9);
+ }
+ return(success = rc);
+
+ case FIL_REA: /* READ */
+ case FIL_WRI: /* WRITE */
+ rsize = 0;
+ cmfdbi(&sw, /* Switches */
+ _CMKEY, /* fcode */
+ "Channel or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ (cx == FIL_REA) ? nfrdtab : nfwrtab,
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ (cx == FIL_REA) ? frdtab : fwrtab, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* Channel number */
+ _CMNUM, /* fcode */
+ "Channel",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ do {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM) /* Channel number */
+ break;
+ else if (cmresult.fcode == _CMKEY) { /* Switch */
+ char c;
+ c = cmgbrk();
+ if ((getval =
+ (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ switch (cmresult.nresult) {
+ case WR_LINE:
+ charflag = 0;
+ sizeflag = 0;
+ rsize = 0;
+ break;
+ case WR_CHAR:
+ rsize = 1;
+ charflag = 1;
+ sizeflag = 1;
+ break;
+ case WR_SIZE:
+ if ((x = cmnum("Bytes","",10,&rsize, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ charflag = 0;
+ sizeflag = 1;
+ break;
+ case WR_STRI:
+ rsize = 1;
+ charflag = 0;
+ sizeflag = 0;
+ break;
+ case WR_LPAD:
+ case WR_RPAD:
+ if ((x = cmnum("Numeric ASCII character value",
+ "32",10,&pad, xxstring)) < 0)
+ return(x);
+ if (cmresult.nresult == WR_LPAD)
+ wr_lpad = 1;
+ else
+ wr_rpad = 1;
+ break;
+ case RD_TRIM:
+ rd_trim = 1;
+ break;
+ case RD_UNTA:
+ rd_untab = 1;
+ break;
+ }
+ debug(F101,"FILE READ rsize 2","",rsize);
+ } else
+ return(-2);
+ } while
+ (cmresult.fcode == _CMKEY);
+
+ n = cmresult.nresult; /* Channel */
+ debug(F101,"FILE READ/WRITE channel","",n);
+
+ if (cx == FIL_WRI) { /* WRITE */
+ int len = 0;
+ if ((x = cmtxt("Text","",&s,xxstring)) < 0)
+ return(x);
+ ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */
+ s = line;
+ s = brstrip(s); /* Strip braces */
+ if (charflag) { /* Write one char */
+ len = 1; /* So length = 1 */
+ rsize = 1; /* Don't supply terminator */
+ } else if (!sizeflag) { /* Write a string */
+ len = -1; /* So length is unspecified */
+ } else { /* Write a block of given size */
+ int i, k, xx;
+ if (rsize > TMPBUFSIZ) {
+ z_error = FX_OFL;
+ printf("?Buffer overflow\n");
+ return(-9);
+ }
+ len = rsize; /* rsize is really length */
+ rsize = 1; /* Don't supply a terminator */
+ xx = strlen(s); /* Size of given string */
+ if (xx >= len) { /* Bigger or equal */
+ s[len] = NUL;
+ } else if (wr_lpad) { /* Smaller, left-padding requested */
+ for (i = 0; i < len - xx; i++) /* Must make a copy */
+ tmpbuf[i] = pad;
+ ckstrncpy(tmpbuf+i,s,TMPBUFSIZ-i);
+ tmpbuf[len] = NUL;
+ s = tmpbuf; /* Redirect write source */
+ } else if (wr_rpad) { /* Smaller with right-padding */
+ for (i = xx; i < len; i++)
+ s[i] = pad;
+ s[len] = NUL;
+ }
+ }
+ if ((rc = z_out(n,s,len,rsize)) < 0) { /* Try to write */
+ printf("?Channel %d WRITE error: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ } else { /* FIL_REA READ */
+ confirmed = 0;
+ vnambuf[0] = NUL;
+ x = cmfld("Variable name","",&s,NULL);
+ debug(F111,"FILE READ cmfld",s,x);
+ if (x < 0) {
+ if (x == -3 || !*s) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ else
+ confirmed++;
+ } else
+ return(x);
+ }
+ ckstrncpy(vnambuf,s,VNAML);
+ debug(F111,"FILE READ vnambuf",vnambuf,confirmed);
+ if (vnambuf[0]) { /* Variable name given, check it */
+ if (!confirmed) {
+ x = cmcfm();
+ if (x < 0)
+ return(x);
+ else
+ confirmed++;
+ }
+ vnp = vnambuf;
+ if (vnambuf[0] == CMDQ &&
+ (vnambuf[1] == '%' || vnambuf[1] == '&'))
+ vnp++;
+ y = 0;
+ if (*vnp == '%' || *vnp == '&') {
+ if ((y = parsevar(vnp,&x,&dummy)) < 0) {
+ printf("?Syntax error in variable name\n");
+ return(-9);
+ }
+ }
+ }
+ debug(F111,"FILE READ variable",vnambuf,confirmed);
+
+ if (!confirmed)
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+ line[0] = NUL; /* Clear destination buffer */
+ if (rsize >= LINBUFSIZ) /* Don't overrun it */
+ rsize = LINBUFSIZ - 1;
+
+ if (rsize == 0) { /* Read a line */
+ rc = z_in(n,line,LINBUFSIZ,LINBUFSIZ-1,0);
+ } else {
+ rc = z_in(n,line,LINBUFSIZ,rsize,1); /* Read a block */
+ }
+ if (rc < 0) { /* Error... */
+ debug(F101,"FILE READ error","",rc);
+ debug(F101,"FILE READ errno","",errno);
+ if (rc == FX_EOF) { /* EOF - fail but no error message */
+ return(success = 0);
+ } else { /* Other error - fail and print msg */
+ printf("?READ error: %s\n",ckferror(rc));
+ return(-9);
+ }
+ }
+ if (rsize == 0) { /* FREAD /LINE postprocessing */
+ if (rd_trim) { /* Trim */
+ int i, k;
+ k = strlen(line);
+ if (k > 0) {
+ for (i = k-1; i > 0; i--) {
+ if (line[i] == SP || line[i] == '\t')
+ line[i] = NUL;
+ else
+ break;
+ }
+ }
+ }
+ if (rd_untab) { /* Untabify */
+ if (untabify(line,tmpbuf,TMPBUFSIZ) > -1)
+ ckstrncpy(line,tmpbuf,LINBUFSIZ);
+ }
+ }
+ debug(F110,"FILE READ data",line,0);
+ if (vnambuf[0]) /* Read OK - If variable name given */
+ addmac(vnambuf,line); /* Assign result to variable */
+ else /* otherwise */
+ printf("%s\n",line); /* just print it */
+ }
+ return(success = 1);
+
+ case FIL_SEE: /* SEEK */
+ case FIL_COU: /* COUNT */
+ rsize = RD_CHAR; /* Defaults to /BYTE */
+ cmfdbi(&sw, /* Switches */
+ _CMKEY, /* fcode */
+ "Channel or switch", /* hlpmsg */
+ "", /* default */
+ "", /* addtl string data */
+ ((cx == FIL_SEE) ? nfskswtab : nfcoswtab),
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ ((cx == FIL_SEE) ? fskswtab : fcoswtab),
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* Channel number */
+ _CMNUM, /* fcode */
+ "Channel",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ do {
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM) /* Channel number */
+ break;
+ else if (cmresult.fcode == _CMKEY) { /* Switch */
+ char c;
+ c = cmgbrk();
+ if ((getval =
+ (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
+ printf("?This switch does not take an argument\n");
+ return(-9);
+ }
+ if (cx == FIL_SEE) {
+ switch (cmresult.nresult) {
+ case SEE_REL: relative = 1; break;
+ case SEE_ABS: relative = 0; break;
+ default: rsize = cmresult.nresult;
+ }
+ } else if (cx == FIL_COU) {
+ switch (cmresult.nresult) {
+ case COU_LIS: listing = 1; break;
+ case COU_NOL: listing = 0; break;
+ default: rsize = cmresult.nresult;
+ }
+ }
+ }
+ } while
+ (cmresult.fcode == _CMKEY);
+
+ n = cmresult.nresult; /* Channel */
+ debug(F101,"FILE SEEK/COUNT channel","",n);
+ if (cx == FIL_COU) {
+ if ((x = cmcfm()) < 0)
+ return(x);
+ z_filcount = z_count(n,rsize);
+ if (z_filcount < 0) {
+ rc = z_filcount;
+ printf("?COUNT error: %s\n",ckferror(rc));
+ return(-9);
+ }
+ if (listing < 0)
+ listing = !xcmdsrc;
+ if (listing)
+ printf(" %ld %s%s\n",
+ z_filcount,
+ ((rsize == RD_CHAR) ? "byte" : "line"),
+ ((z_filcount == 1L) ? "" : "s")
+ );
+ return(success = (z_filcount > -1) ? 1 : 0);
+ }
+ cmfdbi(&sw, /* SEEK symbolic targets (EOF) */
+ _CMKEY, /* fcode */
+ "Channel number;\n or keyword",
+ "",
+ "", /* addtl string data */
+ nfsekwtab, /* addtl numeric data 1: table size */
+ 0, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ fsekwtab, /* Keyword table */
+ &nu /* Pointer to next FDB */
+ );
+ cmfdbi(&nu, /* Channel number */
+ _CMNUM, /* fcode */
+ "",
+ "", /* default */
+ "", /* addtl string data */
+ 10, /* addtl numeric data 1: radix */
+ 0, /* addtl numeric data 2: 0 */
+ xxstring, /* Processing function */
+ NULL, /* Keyword table */
+ NULL /* Pointer to next FDB */
+ );
+ x = cmfdb(&sw); /* Parse something */
+ if (x < 0) {
+ if (x == -3) {
+ printf("?Channel number or EOF required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if (cmresult.fcode == _CMNUM) {
+ y = cmresult.nresult;
+ debug(F110,"FILE SEEK atmbuf",atmbuf,0);
+ if (relative < 0) {
+ if (cx == FIL_SEE && (atmbuf[0] == '+' || atmbuf[0] == '-'))
+ relative = 1;
+ else
+ relative = 0;
+ }
+ } else if (cmresult.fcode == _CMKEY) {
+ eofflg = cmresult.nresult;
+ relative = 0;
+ y = 0 - eofflg;
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ z = y; /* Convert to long */
+ y = 1; /* Recycle this */
+ z_flush(n);
+ debug(F101,"FILE SEEK relative","",relative);
+ debug(F101,"FILE SEEK rsize","",rsize);
+
+ if (rsize == RD_CHAR) { /* Seek to byte position */
+ if (relative > 0) {
+ long pos;
+ pos = z_getpos(n);
+ if (pos < 0L) {
+ rc = pos;
+ printf("?Relative SEEK failed: %s\n",ckferror(rc));
+ return(-9);
+ }
+ z += pos;
+ } else {
+ if (z < 0 && !eofflg) { /* Negative arg but not relative */
+ y = 0; /* Remember this was bad */
+ z = 0; /* but substitute 0 */
+ }
+ }
+ debug(F101,"FILE SEEK /CHAR z","",z);
+ if (z < 0 && !eofflg) {
+ z_error = FX_RNG;
+ return(success = 0);
+ }
+ if ((rc = z_seek(n,z)) < 0) {
+ if (rc == FX_EOF) return(success = 0);
+ printf("?SEEK /BYTE failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ } else { /* Seek to line */
+ if (relative > 0) {
+ long pos;
+ pos = z_getline(n);
+ debug(F101,"FILE SEEK /LINE pos","",pos);
+ if (pos < 0L) {
+ rc = pos;
+ printf("?Relative SEEK failed: %s\n",ckferror(rc));
+ return(-9);
+ }
+ z += pos;
+ }
+ debug(F101,"FILE SEEK /LINE z","",z);
+ debug(F101,"FILE SEEK /LINE eofflg","",eofflg);
+ if (z < 0 && !eofflg) {
+ z_error = FX_RNG;
+ return(success = 0);
+ }
+ if ((rc = z_line(n,z)) < 0) {
+ if (rc == FX_EOF) return(success = 0);
+ printf("?SEEK /LINE failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ }
+ return(success = y);
+
+ case FIL_LIS: { /* LIST open files */
+#ifdef CK_TTGWSIZ
+ extern int cmd_rows, cmd_cols;
+#endif /* CK_TTGWSIZ */
+ extern int xaskmore;
+ int i, x, n = 0, paging = 0;
+ char * s;
+
+ if ((x = cmcfm()) < 0)
+ return(x);
+
+#ifdef CK_TTGWSIZ
+ if (cmd_rows > 0 && cmd_cols > 0)
+#endif /* CK_TTGWSIZ */
+ paging = xaskmore;
+
+ printf("System open file limit: %4d\n", z_openmax);
+ printf("Maximum for FILE OPEN: %4d\n", z_maxchan);
+ printf("Files currently open: %4d\n\n", z_nopen);
+ n = 4;
+ for (i = 0; i < z_maxchan; i++) {
+ s = z_getname(i); /* Got one? */
+ if (s) { /* Yes */
+ char m[8];
+ m[0] = NUL;
+ printf("%2d. %s",i,s); /* Print name */
+ n++; /* Count it */
+ x = z_getmode(i); /* Get modes & print them */
+ if (x > -1) {
+ if (x & FM_REA) ckstrncat(m,"R",8);
+ if (x & FM_WRI) ckstrncat(m,"W",8);
+ if (x & FM_APP) ckstrncat(m,"A",8);
+ if (x & FM_BIN) ckstrncat(m,"B",8);
+ if (m[0])
+ printf(" (%s)",m);
+ if (x & FM_EOF)
+ printf(" [EOF]");
+ else
+ printf(" %ld",z_getpos(i)); /* And file position too */
+ }
+ printf("\n");
+#ifdef CK_TTGWSIZ
+ if (paging > 0) { /* Pause at end of screen */
+ if (n > cmd_rows - 3) {
+ if (!askmore())
+ break;
+ else
+ n = 0;
+ }
+ }
+#endif /* CK_TTGWSIZ */
+ }
+ }
+ return(success = 1);
+ }
+
+ case FIL_FLU: /* FLUSH */
+ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ if ((rc = z_flush(n)) < 0) {
+ printf("?FLUSH failed - Channel %d: %s\n",n,ckferror(rc));
+ return(-9);
+ }
+ return(success = 1);
+
+ case FIL_STA: /* STATUS */
+ if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
+ if (x == -3) {
+ printf("?Channel number required\n");
+ x = -9;
+ }
+ return(x);
+ }
+ if ((x = cmcfm()) < 0)
+ return(x);
+ p = blanks + 3; /* Tricky formatting... */
+ if (n < 1000) p--;
+ if (n < 100) p--;
+ if (n < 10) p--;
+ if ((rc = z_getmode(n)) < 0) {
+ printf("Channel %d:%s%s\n",n,p,ckferror(rc));
+ return(success = 0);
+ } else if (!rc) {
+ printf("Channel %d:%sNot open\n",n,p);
+ return(success = 0);
+ } else {
+ long xx;
+ s = z_getname(n);
+ if (!s) s = "(name unknown)";
+ printf("Channel %d:%sOpen\n",n,p);
+ printf(" File: %s\n Modes: ",s);
+ if (rc & FM_REA) printf(" /READ");
+ if (rc & FM_WRI) printf(" /WRITE");
+ if (rc & FM_APP) printf(" /APPEND");
+ if (rc & FM_BIN) printf(" /BINARY");
+ if (rc & FM_CMD) printf(" /COMMAND");
+ if (rc & FM_EOF) printf(" [EOF]");
+ printf("\n Size: %ld\n",z_count(n,RD_CHAR));
+ printf(" At byte: %ld\n",z_getpos(n));
+ xx = z_getline(n);
+ if (xx > -1)
+ printf(" At line: %ld\n",xx);
+ return(success = 1);
+ }
+ default:
+ return(-2);
+ }
+}
+#endif /* CKCHANNELIO */
+
+#ifndef NOSETKEY
+/* Save Key maps and in OS/2 Mouse maps */
+int
+savkeys(name,disp) char * name; int disp; {
+ char *tp;
+ static struct filinfo xx;
+ int savfil, i, j, k;
+ char buf[1024];
+
+ zclose(ZMFILE);
+
+ if (disp) {
+ xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
+ xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
+ xx.lblopts = 0;
+ savfil = zopeno(ZMFILE,name,NULL,&xx);
+ } else savfil = zopeno(ZMFILE,name,NULL,NULL);
+
+ if (savfil) {
+#ifdef OS2
+ ztime(&tp);
+ zsout(ZMFILE, "; Kermit 95 SAVE KEYMAP file: ");
+ zsoutl(ZMFILE,tp);
+ if (mskkeys) {
+ zsoutl(ZMFILE,
+ "if eq \"\\v(program)\" \"C-Kermit\" set mskermit keycodes on");
+ } else {
+ zsoutl(ZMFILE,
+ "if NOT eq \"\\v(program)\" \"C-Kermit\" stop 1 C-Kermit required.");
+ zsoutl(ZMFILE,"set mskermit keycodes off");
+ }
+ zsoutl(ZMFILE,"");
+#else /* OS2 */
+ ztime(&tp);
+ zsout(ZMFILE, "; C-Kermit SAVE KEYMAP file: ");
+ zsoutl(ZMFILE,tp);
+#endif /* OS2 */
+
+ zsoutl(ZMFILE,"; Clear previous keyboard mappings ");
+ zsoutl(ZMFILE,"set key clear");
+#ifdef OS2
+ for (k = 0; k < nttkey; k++) {
+ if (!ttkeytab[k].flgs) {
+ ckmakmsg(buf,1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " clear",
+ NULL
+ );
+ zsoutl(ZMFILE,buf);
+ }
+ }
+#endif /* OS2 */
+ zsoutl(ZMFILE,"");
+
+ for (i = 0; i < KMSIZE; i++) {
+ if (macrotab[i]) {
+ int len = strlen((char *)macrotab[i]);
+#ifdef OS2
+ ckmakmsg(buf,
+ 1024,
+ "set key \\",
+ ckitoa(mskkeys ? cktomsk(i) : i),
+ " ",
+ NULL
+ );
+#else /* OS2 */
+ ckmakmsg(buf,
+ 1024,
+ "set key \\",
+ ckitoa(i),
+ NULL,NULL
+ );
+#endif /* OS2 */
+ zsout(ZMFILE,buf);
+
+ for (j = 0; j < len; j++) {
+ char ch = macrotab[i][j];
+ if (ch <= SP || ch >= DEL ||
+ ch == '-' || ch == ',' ||
+ ch == '{' || ch == '}' ||
+ ch == ';' || ch == '?' ||
+ ch == '.' || ch == '\'' ||
+ ch == '\\' || ch == '/' ||
+ ch == '#') {
+ ckmakmsg(buf,1024,"\\{",ckitoa((int)ch),"}",NULL);
+ zsout(ZMFILE,buf);
+ } else {
+ ckmakmsg(buf,1024,ckctoa((char)ch),NULL,NULL,NULL);
+ zsout(ZMFILE,buf);
+ }
+ }
+#ifdef OS2
+ ckmakmsg(buf,1024,"\t; ",keyname(i),NULL,NULL);
+ zsoutl(ZMFILE,buf);
+#else
+ zsoutl(ZMFILE,"");
+#endif /* OS2 */
+ } else if ( keymap[i] != i ) {
+#ifndef NOKVERBS
+ if (IS_KVERB(keymap[i])) {
+ for (j = 0; j < nkverbs; j++)
+ if (kverbs[j].kwval == (keymap[i] & ~F_KVERB))
+ break;
+ if (j != nkverbs) {
+#ifdef OS2
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\K%s\t; %s",
+ mskkeys ? cktomsk(i) : i,
+ kverbs[j].kwd, keyname(i)
+ );
+#else
+ ckmakxmsg(buf, /* 12 string args */
+ 1024,
+ "set key \\",
+ ckitoa(mskkeys ? cktomsk(i) : i),
+ " \\K",
+ kverbs[j].kwd,
+ "\t; ",
+ keyname(i),
+ NULL, NULL, NULL, NULL, NULL, NULL);
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#else
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\K%s", i, kverbs[j].kwd);
+#else
+ ckmakmsg(buf,1024,
+ "set key \\",
+ ckitoa(i),
+ " \\K",
+ kverbs[j].kwd
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#endif
+ }
+ } else
+#endif /* NOKVERBS */
+ {
+#ifdef OS2
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\{%d}\t; %s",
+ mskkeys ? cktomsk(i) : i,
+ keymap[i],
+ keyname(i)
+ );
+#else
+ ckmakxmsg(buf, /* 8 string args */
+ 1024,
+ "set key \\",
+ ckitoa(mskkeys ? cktomsk(i) : i),
+ " \\{",
+ ckitoa(keymap[i]),
+ "}\t; ",
+ keyname(i),
+ NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#else
+#ifdef COMMENT
+ sprintf(buf, "set key \\%d \\{%d}", i, keymap[i]);
+#else
+ ckmakxmsg(buf,1024,
+ "set key \\",
+ ckitoa(i),
+ " \\{",
+ ckitoa(keymap[i]),
+ "}",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+#endif /* OS2 */
+ }
+ }
+ }
+#ifdef OS2
+ /* OS/2 also has the SET TERMINAL KEY <termtype> defines */
+ for (k = 0; k < nttkey; k++) {
+ extern struct keynode * ttkeymap[];
+ struct keynode * pnode = NULL;
+
+ if (ttkeytab[k].flgs) /* Don't process CM_INV or CM_ABR */
+ continue;
+
+ zsoutl(ZMFILE,"");
+ ckmakmsg(buf,1024,"; SET TERMINAL KEY ",ttkeytab[k].kwd,NULL,NULL);
+ zsoutl(ZMFILE,buf);
+
+ for (pnode = ttkeymap[ttkeytab[k].kwval];
+ pnode;
+ pnode = pnode->next
+ ) {
+ switch (pnode->def.type) {
+ case key:
+#ifdef COMMENT
+ sprintf(buf, "set terminal key %s \\%d \\{%d}\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ pnode->def.key.scancode,
+ keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\{",
+ ckitoa(pnode->def.key.scancode),
+ "}\t; ",
+ keyname(pnode->key),
+ NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ break;
+ case kverb:
+ for (j = 0; j < nkverbs; j++)
+ if (kverbs[j].kwval == (pnode->def.kverb.id & ~F_KVERB))
+ break;
+ if (j != nkverbs) {
+#ifdef COMMENT
+ sprintf(buf, "set terminal key %s \\%d \\K%s\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ kverbs[j].kwd, keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\K",
+ kverbs[j].kwd,
+ "\t; ",
+ keyname(pnode->key),
+ NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ }
+ break;
+ case macro: {
+ int len = strlen((char *)pnode->def.macro.string);
+#ifdef COMMENT
+ sprintf(buf,"set terminal key %s \\%d ",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key);
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsout(ZMFILE,buf);
+
+ for (j = 0; j < len; j++) {
+ char ch = pnode->def.macro.string[j];
+ if (ch <= SP || ch >= DEL ||
+ ch == '-' || ch == ',' ||
+ ch == '{' || ch == '}' ||
+ ch == ';' || ch == '?' ||
+ ch == '.' || ch == '\'' ||
+ ch == '\\' || ch == '/' ||
+ ch == '#') {
+ ckmakmsg(buf,1024,
+ "\\{",ckitoa((int)ch),"}",NULL);
+ zsout(ZMFILE,buf);
+ } else {
+ ckmakmsg(buf,1024,
+ ckctoa((char)ch),NULL,NULL,NULL);
+ zsout(ZMFILE,buf);
+ }
+ }
+ ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL);
+ zsoutl(ZMFILE,buf);
+ break;
+ }
+ case literal: {
+ int len = strlen((char *)pnode->def.literal.string);
+#ifdef COMMENT
+ sprintf(buf,"set terminal key %s /literal \\%d ",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key);
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " /literal \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+#endif /* COMMENT */
+ zsout(ZMFILE,buf);
+
+ for (j = 0; j < len; j++) {
+ char ch = pnode->def.literal.string[j];
+ if (ch <= SP || ch >= DEL ||
+ ch == '-' || ch == ',' ||
+ ch == '{' || ch == '}' ||
+ ch == ';' || ch == '?' ||
+ ch == '.' || ch == '\'' ||
+ ch == '\\' || ch == '/' ||
+ ch == '#') {
+ ckmakmsg(buf,1024,
+ "\\{",ckitoa((int)ch),"}",NULL);
+ zsout(ZMFILE,buf);
+ } else {
+ ckmakmsg(buf,1024,
+ ckctoa((char)ch),NULL,NULL,NULL);
+ zsout(ZMFILE,buf);
+ }
+ }
+ ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL);
+ zsoutl(ZMFILE,buf);
+ break;
+ }
+ case esc:
+#ifdef COMMENT
+ sprintf(buf,
+ "set terminal key %s /literal \\%d \\{%d}\\{%d}\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ ISDG200(ttkeytab[k].kwval) ? 30 : 27,
+ pnode->def.esc.key & ~F_ESC,
+ keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " /literal \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\{",
+ ckitoa(ISDG200(ttkeytab[k].kwval) ? 30 : 27),
+ "}\\{",
+ ckitoa(pnode->def.esc.key & ~F_ESC),
+ "}\t; ",
+ keyname(pnode->key),
+ NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ break;
+ case csi:
+#ifdef COMMENT
+ sprintf(buf,
+ "set terminal key %s /literal \\%d \\{27}[\\{%d}\t; %s",
+ ttkeytab[k].kwd,
+ mskkeys ? cktomsk(pnode->key) : pnode->key,
+ pnode->def.csi.key & ~F_CSI,
+ keyname(pnode->key)
+ );
+#else
+ ckmakxmsg(buf,
+ 1024,
+ "set terminal key ",
+ ttkeytab[k].kwd,
+ " /literal \\",
+ ckitoa(mskkeys ?
+ cktomsk(pnode->key) :
+ pnode->key),
+ " \\{27}[\\{",
+ ckitoa(pnode->def.csi.key & ~F_CSI),
+ "}\t; ",
+ keyname(pnode->key),
+ NULL,NULL,NULL,NULL
+ );
+#endif /* COMMENT */
+ zsoutl(ZMFILE,buf);
+ break;
+ default:
+ continue;
+ }
+ }
+ }
+#endif /* OS2 */
+
+ zsoutl(ZMFILE,"");
+ zsoutl(ZMFILE,"; End");
+ zclose(ZMFILE);
+ return(success = 1);
+ } else {
+ return(success = 0);
+ }
+}
+#endif /* NOSETKEY */
+
+#define SV_SCRL 0
+#define SV_HIST 1
+
+#ifdef OS2
+#ifndef NOLOCAL
+static struct keytab trmtrmopt[] = {
+ { "scrollback", SV_SCRL, 0 }
+};
+#endif /* NOLOCAL */
+#endif /* OS2 */
+
+static struct keytab cmdtrmopt[] = {
+#ifdef CK_RECALL
+ { "history", SV_HIST, 0 },
+#endif /* CK_RECALL */
+#ifdef OS2
+#ifndef NOLOCAL
+ { "scrollback", SV_SCRL, 0 },
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ { "", 0, 0 }
+};
+static int ncmdtrmopt = (sizeof (cmdtrmopt) / sizeof (struct keytab)) - 1;
+
+#ifdef OS2
+#ifndef NOLOCAL
+_PROTOTYP(int savscrbk, (int, char *, int));
+#endif /* NOLOCAL */
+#endif /* OS2 */
+
+#ifdef CK_RECALL
+_PROTOTYP(int savhistory, (char *, int));
+#endif /* CK_RECALL */
+
+int
+dosave(xx) int xx; {
+ int x, y = 0, disp;
+ char * s = NULL;
+ extern struct keytab disptb[];
+#ifdef ZFNQFP
+ struct zfnfp * fnp;
+#endif /* ZFNQFP */
+
+#ifndef NOSETKEY
+ if (xx == XSKEY) { /* SAVE KEYMAP.. */
+ z = cmofi("Name of Kermit command file","keymap.ksc",&s,xxstring);
+ } else {
+#endif /* NOSETKEY */
+ switch (xx) {
+ case XSCMD: /* SAVE COMMAND.. */
+ if ((y = cmkey(cmdtrmopt, ncmdtrmopt, "What to save",
+#ifdef OS2
+ "scrollback",
+#else
+ "history",
+#endif /* OS2 */
+ xxstring)) < 0)
+ return(y);
+ break;
+#ifdef OS2
+#ifndef NOLOCAL
+ case XSTERM: /* SAVE TERMINAL.. */
+ if ((y = cmkey(trmtrmopt,1,
+ "What to save","scrollback",xxstring)) < 0)
+ return(y);
+ break;
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ }
+ z = cmofi("Filename",
+ ((y == SV_SCRL) ? "scrollbk.txt" : "history.txt"),
+ &s,
+ xxstring
+ );
+#ifndef NOSETKEY
+ }
+#endif /* NOSETKEY */
+ if (z < 0) /* Check output-file parse results */
+ return(z);
+ if (z == 2) {
+ printf("?Sorry, %s is a directory name\n",s);
+ return(-9);
+ }
+#ifdef ZFNQFP
+ if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {/* Convert to full pathname */
+ if (fnp->fpath)
+ if ((int) strlen(fnp->fpath) > 0)
+ s = fnp->fpath;
+ }
+#endif /* ZFNQFP */
+
+ ckstrncpy(line,s,LINBUFSIZ); /* Make safe copy of pathname */
+ s = line;
+#ifdef MAC
+ z = 0;
+#else
+ /* Get NEW/APPEND disposition */
+ if ((z = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
+ return(z);
+#endif /* MAC */
+ disp = z;
+ if ((x = cmcfm()) < 0) /* Get confirmation */
+ return(x);
+
+ switch (xx) { /* Do action.. */
+#ifndef NOSETKEY
+ case XSKEY: /* SAVE KEYMAP */
+ return (savkeys(s,disp));
+#endif /* NOSETKEY */
+
+ case XSCMD: /* SAVE COMMAND.. */
+#ifdef OS2
+#ifndef NOLOCAL
+ if (y == SV_SCRL) /* .. SCROLLBACK */
+ return(success = savscrbk(VCMD,s,disp));
+#endif /* NOLOCAL */
+#endif /* OS2 */
+#ifndef NORECALL
+ if (y == SV_HIST) /* .. HISTORY */
+ return(success = savhistory(s,disp));
+ break;
+#endif /* NORECALL */
+
+#ifdef OS2
+#ifndef NOLOCAL
+ case XSTERM: /* SAVE TERMINAL SCROLLBACK */
+ return(success = savscrbk(VTERM,s,disp));
+#endif /* NOLOCAL */
+#endif /* OS2 */
+ }
+ success = 0;
+ return(-2);
+}
+
+/*
+ R E A D T E X T
+
+ Read text with a custom prompt into given buffer using command parser but
+ with no echoing or entry into recall buffer.
+*/
+int
+readtext(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
+#ifdef CK_RECALL
+ extern int on_recall; /* Around Password prompting */
+#endif /* CK_RECALL */
+ int rc;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode;
+ extern int startflags;
+ int vmode_sav = vmode;
+
+ if (!prmpt) prmpt = "";
+
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ )
+ return(popup_readtext(vmode,NULL,prmpt,buffer,bufsiz,0));
+
+ if (vmode == VTERM) {
+ vmode = VCMD;
+ VscrnIsDirty(VTERM);
+ VscrnIsDirty(VCMD);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(1); /* and echo mode */
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (rc = -1; rc < 0; ) { /* Prompt till they answer */
+ rc = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ cmres(); /* Reset the parser again */
+ }
+ ckstrncpy(buffer,s,bufsiz);
+ cmsetp(psave); /* Restore original prompt */
+
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode != vmode_sav) {
+ vmode = VTERM;
+ VscrnIsDirty(VCMD);
+ VscrnIsDirty(VTERM);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+ return(0);
+}
+#endif /* NOICP */
+
+/* A general function to allow a Password or other information */
+/* to be read from the command prompt without it going into */
+/* the recall buffer or being echo'd. */
+
+int
+readpass(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
+ int x;
+#ifdef NOICP
+ if (!prmpt) prmpt = "";
+ printf("%s", prmpt);
+#ifdef COMMENT
+ /* Some linkers won't allow this because it's unsafe */
+ gets(buffer);
+#else /* COMMENT */
+ {
+ int c, i; char * p;
+ p = buffer;
+ for (i = 0; i < bufsiz-1; i++) {
+ if ((c = getchar()) == EOF)
+ break;
+ if (c < SP)
+ break;
+ buffer[i] = c;
+ }
+ buffer[i] = NUL;
+ }
+#endif /* COMMENT */
+ return(1);
+#else /* NOICP */
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ int rc;
+#ifndef NOLOCAL
+#ifdef OS2
+ extern int vmode;
+ extern int startflags;
+ int vmode_sav = vmode;
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CKSYSLOG
+ int savlog;
+#endif /* CKSYSLOG */
+ if (!prmpt) prmpt = "";
+#ifndef NOLOCAL
+ debok = 0; /* Don't log */
+#ifdef OS2
+ if (win95_popup && !(startflags & 96)
+#ifdef IKSD
+ && !inserver
+#endif /* IKSD */
+ ) {
+ x = popup_readpass(vmode,NULL,prmpt,buffer,bufsiz,0);
+ debok = 1;
+ return(x);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+
+#ifdef CKSYSLOG
+ savlog = ckxsyslog; /* Save and turn off syslogging */
+ ckxsyslog = 0;
+#endif /* CKSYSLOG */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode == VTERM) {
+ vmode = VCMD;
+ VscrnIsDirty(VTERM);
+ VscrnIsDirty(VCMD);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(0); /* and no-echo mode */
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (rc = -1; rc < 0; ) { /* Prompt till they answer */
+ rc = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ cmres(); /* Reset the parser again */
+ }
+ ckstrncpy(buffer,s,bufsiz);
+ printf("\r\n"); /* Echo a CRLF */
+ cmsetp(psave); /* Restore original prompt */
+ cmini(1); /* Restore echo mode */
+#ifndef NOLOCAL
+#ifdef OS2
+ if (vmode != vmode_sav) {
+ vmode = VTERM;
+ VscrnIsDirty(VCMD);
+ VscrnIsDirty(VTERM);
+ }
+#endif /* OS2 */
+#endif /* NOLOCAL */
+#ifdef CKSYSLOG
+ ckxsyslog = savlog; /* Restore syslogging */
+#endif /* CKSYSLOG */
+ debok = 1;
+ return(0);
+#endif /* NOICP */
+}
+
+#ifndef NOICP
+struct keytab authtab[] = { /* Available authentication types */
+#ifdef CK_KERBEROS
+ { "k4", AUTH_KRB4, CM_INV },
+ { "k5", AUTH_KRB5, CM_INV },
+ { "kerberos4", AUTH_KRB4, 0 },
+ { "kerberos5", AUTH_KRB5, 0 },
+ { "krb4", AUTH_KRB4, CM_INV },
+ { "krb5", AUTH_KRB5, CM_INV },
+#endif /* CK_KERBEROS */
+#ifdef NT
+ { "ntlm", AUTH_NTLM, 0 },
+#endif /* NT */
+#ifdef CK_SRP
+ { "srp", AUTH_SRP, 0 },
+#endif /* CK_SRP */
+#ifdef CK_SSL
+ { "ssl", AUTH_SSL, 0 },
+#endif /* CK_SSL */
+ { "", 0, 0 }
+};
+int authtabn = sizeof(authtab)/sizeof(struct keytab)-1;
+
+#ifdef CK_KERBEROS
+struct keytab kerbtab[] = { /* Kerberos authentication types */
+ { "k4", AUTH_KRB4, CM_INV },
+ { "k5", AUTH_KRB5, CM_INV },
+ { "kerberos4", AUTH_KRB4, 0 },
+ { "kerberos5", AUTH_KRB5, 0 },
+ { "krb4", AUTH_KRB4, CM_INV },
+ { "krb5", AUTH_KRB5, CM_INV }
+};
+int kerbtabn = sizeof(kerbtab)/sizeof(struct keytab);
+
+static struct keytab krb_s_tbl[] = { /* AUTHENTICATE command switches: */
+ { "/cache", KRB_S_CA, CM_ARG }
+};
+static int krb_s_n = sizeof(krb_s_tbl)/sizeof(struct keytab);
+
+static struct keytab krb_v_tbl[] = { /* KERBEROS version values: */
+ { "4", 4, 0 },
+ { "5", 5, 0 }, /* (add others as needed...) */
+ { "auto", 0, 0 } /* Note: 0 = auto */
+};
+static int krb_v_n = sizeof(krb_v_tbl)/sizeof(struct keytab);
+
+static struct keytab krb_a_tbl[] = { /* KERBEROS actions: */
+ { "destroy", KRB_A_DE, 0 },
+ { "initialize", KRB_A_IN, 0 },
+ { "list-credentials", KRB_A_LC, 0 }
+};
+static int krb_a_n = sizeof(krb_a_tbl)/sizeof(struct keytab);
+
+static struct keytab krb4_i_tbl[] = { /* KERBEROS 4 INITIALIZE switches: */
+ { "/brief", KRB_I_BR, 0 }, /* /BRIEF */
+ { "/instance", KRB_I_IN, CM_ARG }, /* /INSTANCE: */
+ { "/lifetime", KRB_I_LF, CM_ARG }, /* /LIFETIME: */
+ { "/not-preauth", KRB_I_NPA, 0 }, /* /NOT-PREAUTH */
+ { "/password", KRB_I_PW, CM_ARG }, /* /PASSWORD: */
+#ifdef OS2
+ { "/popup", KRB_I_POP, 0 }, /* /POPUP */
+#endif /* OS2 */
+ { "/preauth", KRB_I_PA, 0 }, /* /PREAUTH */
+ { "/realm", KRB_I_RL, CM_ARG }, /* /REALM: */
+ { "/verbose", KRB_I_VB, 0 }, /* /VERBOSE */
+ { "", 0, 0 }
+};
+static int krb4_i_n = sizeof(krb4_i_tbl)/sizeof(struct keytab) - 1;
+
+static struct keytab krb5_i_tbl[] = { /* KERBEROS 5 INITIALIZE switches: */
+ { "/addresses", KRB_I_ADR, CM_ARG },
+ { "/forwardable", KRB_I_FW, 0 }, /* /FORWARDABLE */
+ { "/instance", KRB_I_IN, CM_ARG }, /* /INSTANCE: */
+ { "/k4", KRB_I_K4, CM_INV }, /* /KERBEROS4 */
+ { "/kerberos4", KRB_I_K4, 0 }, /* /KERBEROS4 */
+ { "/krb4", KRB_I_K4, CM_INV }, /* /KERBEROS4 */
+ { "/lifetime", KRB_I_LF, CM_ARG }, /* /LIFETIME: */
+ { "/no-addresses", KRB_I_NAD, 0 }, /* /NO-ADDRESSES */
+ { "/no-k4", KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */
+ { "/no-kerberos4", KRB_I_NK4, 0 }, /* /NO-KERBEROS4 */
+ { "/no-krb4", KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */
+ { "/not-forwardable", KRB_I_NFW, 0 }, /* /NOT-FORWARDABLE */
+ { "/not-proxiable", KRB_I_NPR, 0 }, /* /NOT-PROXIABLE */
+ { "/password", KRB_I_PW, CM_ARG }, /* /PASSWORD: */
+#ifdef OS2
+ { "/popup", KRB_I_POP, 0 }, /* /POPUP */
+#endif /* OS2 */
+ { "/postdate", KRB_I_PD, CM_ARG }, /* /POSTDATE: */
+ { "/pr", KRB_I_PR, CM_INV|CM_ABR }, /* to allow for */
+ { "/pro", KRB_I_PR, CM_INV|CM_ABR }, /* different spellings */
+ { "/prox", KRB_I_PR, CM_INV|CM_ABR },
+ { "/proxiable", KRB_I_PR, 0 }, /* /PROXIABLE */
+ { "/proxyable", KRB_I_PR, CM_INV }, /* /PROXYABLE */
+ { "/realm", KRB_I_RL, CM_ARG }, /* /REALM: */
+ { "/renew", KRB_I_RN, 0 }, /* /RENEW */
+ { "/renewable", KRB_I_RB, CM_ARG }, /* /RENEWABLE: */
+ { "/service", KRB_I_SR, CM_ARG }, /* /SERVICE: */
+ { "/validate", KRB_I_VA, 0 }, /* /VALIDATE */
+ { "", 0, 0 }
+};
+static int krb5_i_n = sizeof(krb5_i_tbl)/sizeof(struct keytab) - 1;
+
+static struct keytab klctab[] = { /* List Credentials switches*/
+ { "/addresses", XYKLCAD, 0 },
+ { "/encryption", XYKLCEN, 0 },
+ { "/flags", XYKLCFL, 0 }
+};
+static int nklctab = sizeof(klctab)/sizeof(struct keytab);
+
+extern int krb_action;
+extern struct krb_op_data krb_op;
+
+extern struct krb5_list_cred_data krb5_lc;
+extern struct krb5_init_data krb5_init;
+extern char * krb5_d_principal; /* Default principal */
+extern char * krb5_d_instance;
+extern char * krb5_d_realm; /* Default realm */
+extern char * krb5_d_cc; /* Default credentials cache */
+extern char * krb5_d_srv; /* Default service name */
+extern int krb5_d_lifetime; /* Default lifetime */
+extern int krb5_d_forwardable;
+extern int krb5_d_proxiable;
+extern int krb5_d_renewable;
+extern int krb5_autoget;
+extern int krb5_autodel;
+extern int krb5_d_getk4;
+extern int krb5_d_no_addresses;
+extern int krb5_checkaddrs;
+extern char * krb5_d_addrs[];
+extern char * k5_keytab; /* Keytab file */
+
+extern struct krb4_init_data krb4_init;
+extern char * krb4_d_principal; /* Default principal */
+extern char * krb4_d_realm; /* Default realm */
+extern char * krb4_d_srv; /* Default service name */
+extern int krb4_d_lifetime; /* Default lifetime */
+extern int krb4_d_preauth;
+extern char * krb4_d_instance;
+extern int krb4_autoget;
+extern int krb4_autodel;
+extern int krb4_checkaddrs;
+extern char * k4_keytab; /* Keytab file */
+#endif /* CK_KERBEROS */
+
+#ifndef NOSHOW
+int
+sho_iks() {
+#ifdef IKSDCONF
+#ifdef CK_LOGIN
+ extern int ckxsyslog, ckxwtmp, ckxanon;
+#ifdef UNIX
+ extern int ckxpriv;
+#endif /* UNIX */
+#ifdef CK_PERMS
+ extern int ckxperms;
+#endif /* CK_PERMS */
+ extern char * anonfile, * userfile, * anonroot;
+#ifdef OS2
+ extern char * anonacct;
+#endif /* OS2 */
+#ifdef NT
+ extern char * iks_domain;
+#endif /* NT */
+#endif /* CK_LOGIN */
+#ifdef CKWTMP
+ extern char * wtmpfile;
+#endif /* CKWTMP */
+#ifdef IKSDB
+ extern char * dbfile;
+ extern int dbenabled;
+#endif /* IKSDB */
+#ifdef CK_LOGIN
+ extern int logintimo;
+#endif /* CK_LOGIN */
+ extern int srvcdmsg, success, iksdcf, noinit, arg_x;
+ extern char * cdmsgfile[], * cdmsgstr, *kermrc;
+ char * bannerfile = NULL;
+ char * helpfile = NULL;
+ extern int xferlog;
+ extern char * xferfile;
+ int i;
+
+ if (isguest) {
+ printf("?Command disabled\r\n");
+ return(success = 0);
+ }
+
+ printf("IKS Settings\r\n");
+#ifdef CK_LOGIN
+#ifdef OS2
+ printf(" Anonymous Account: %s\r\n",anonacct?anonacct:"<none>");
+#endif /* OS2 */
+ printf(" Anonymous Initfile: %s\r\n",anonfile?anonfile:"<none>");
+ printf(" Anonymous Login: %d\r\n",ckxanon);
+ printf(" Anonymous Root: %s\r\n",anonroot?anonroot:"<none>");
+#endif /* CK_LOGIN */
+ printf(" Bannerfile: %s\r\n",bannerfile?bannerfile:"<none>");
+ printf(" CDfile: %s\r\n",cdmsgfile[0]?cdmsgfile[0]:"<none>");
+ for ( i=1;i<16 && cdmsgfile[i];i++ )
+ printf(" CDfile: %s\r\n",cdmsgfile[i]);
+ printf(" CDMessage: %d\r\n",srvcdmsg);
+#ifdef IKSDB
+ printf(" DBfile: %s\r\n",dbfile?dbfile:"<none>");
+ printf(" DBenabled: %d\r\n",dbenabled);
+#endif /* IKSDB */
+#ifdef CK_LOGIN
+#ifdef NT
+ printf(" Default-domain: %s\r\n",iks_domain?iks_domain:".");
+#endif /* NT */
+#endif /* CK_LOGIN */
+ printf(" Helpfile: %s\r\n",helpfile?helpfile:"<none>");
+ printf(" Initfile: %s\r\n",kermrc?kermrc:"<none>");
+ printf(" No-Initfile: %d\r\n",noinit);
+#ifdef CK_LOGIN
+#ifdef CK_PERM
+ printf(" Permission code: %0d\r\n",ckxperms);
+#endif /* CK_PERM */
+#ifdef UNIX
+ printf(" Privileged Login: %d\r\n",ckxpriv);
+#endif /* UNIX */
+#endif /* CK_LOGIN */
+ printf(" Server-only: %d\r\n",arg_x);
+ printf(" Syslog: %d\r\n",ckxsyslog);
+ printf(" Timeout (seconds): %d\r\n",logintimo);
+ printf(" Userfile: %s\r\n",userfile?userfile:"<none>");
+#ifdef CK_LOGIN
+#ifdef CKWTMP
+ printf(" Wtmplog: %d\r\n",ckxwtmp);
+ printf(" Wtmpfile: %s\r\n",wtmpfile?wtmpfile:"<none>");
+#endif /* CKWTMP */
+#endif /* CK_LOGIN */
+ printf(" Xferfile: %s\r\n",xferfile?xferfile:"<none>");
+ printf(" Xferlog: %d\r\n",xferlog);
+#else /* IKSDCONF */
+ printf("?Nothing to show.\r\n");
+#endif /* IKSDCONF */
+ return(success = 1);
+}
+
+#ifdef CK_AUTHENTICATION
+int
+sho_auth(cx) int cx; {
+ extern int auth_type_user[], cmd_rows;
+ int i;
+ char * p;
+ int kv = 0, all = 0, n = 0;
+
+#ifdef IKSD
+ if (inserver && isguest) {
+ printf("?Sorry, command disabled.\r\n");
+ return(success = 0);
+ }
+#endif /* IKSD */
+ if (cx) {
+ kv = cx;
+ } else if (auth_type_user[0] != AUTHTYPE_AUTO) {
+ kv = auth_type_user[0];
+ } else {
+ all = 1;
+ kv = AUTHTYPE_KERBEROS_V4;
+ }
+ while (kv) {
+ switch (kv) {
+ case AUTHTYPE_KERBEROS_V4:
+ kv = all ? AUTHTYPE_KERBEROS_V5 : 0;
+ if (ck_krb4_is_installed()) {
+ printf(" Authentication: Kerberos 4\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: Kerberos 4 (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+#ifdef CK_KERBEROS
+ printf(" Keytab file: %s\n",
+ k4_keytab ? k4_keytab : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (krb_action < 0) {
+ p = "(none)";
+ } else {
+ for (p = "", i = 0; i < krb_a_n; i++) {
+ if (krb_action == krb_a_tbl[i].kwval) {
+ p = krb_a_tbl[i].kwd;
+ break;
+ }
+ }
+ }
+ printf(" Action: %s\n", p);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default lifetime %d\n",krb4_d_lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Lifetime: %d (minutes)\n",krb4_init.lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default preauth: %d\n",krb4_d_preauth);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Preauth: %d\n",krb4_init.preauth);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default principal: \"%s\"\n",
+ krb4_d_principal ? krb4_d_principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Principal: \"%s\"\n",
+ krb4_init.principal ? krb4_init.principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default realm: \"%s\"\n",
+ krb4_d_realm ? krb4_d_realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Realm: \"%s\"\n",
+ krb4_init.realm ? krb4_init.realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default instance: \"%s\"\n",
+ krb4_d_instance ? krb4_d_instance : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Instance: \"%s\"\n",
+ krb4_init.instance ? krb4_init.instance : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Get TGTs: %d\n",krb4_autoget);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Destroy TGTs: %s\n",
+ krb4_autodel==KRB_DEL_NO?"never":
+ krb4_autodel==KRB_DEL_CL?"on-close":"on-exit");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Check IP Addresses: %d\n",krb4_checkaddrs);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#ifdef COMMENT
+ printf(" Password: \"%s\"\n",
+ krb4_init.password ? krb4_init.password : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* COMMENT */
+#endif /* CK_KERBEROS */
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ case AUTHTYPE_KERBEROS_V5:
+ kv = all ? AUTHTYPE_SSL : 0;
+ if (ck_krb5_is_installed()) {
+ if (ck_gssapi_is_installed())
+ printf(" Authentication: Kerberos 5 plus GSSAPI\n");
+ else
+ printf(" Authentication: Kerberos 5\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: Kerberos 5 (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+
+#ifdef CK_KERBEROS
+ printf(" Cache file: %s\n",
+ krb_op.cache ? krb_op.cache : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default cache: %s\n",
+ krb5_d_cc ? krb5_d_cc : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Keytab file: %s\n",
+ k5_keytab ? k5_keytab : "(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (krb_action < 0) {
+ p = "(none)";
+ } else {
+ for (p = "", i = 0; i < krb_a_n; i++) {
+ if (krb_action == krb_a_tbl[i].kwval) {
+ p = krb_a_tbl[i].kwd;
+ break;
+ }
+ }
+ }
+ printf(" Action: %s\n", p);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+
+ printf(" Default forwardable %d\n",krb5_d_forwardable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Forwardable: %d\n",krb5_init.forwardable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default lifetime %d\n",krb5_d_lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Lifetime: %d (minutes)\n",krb5_init.lifetime);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Postdate: \"%s\"\n",
+ krb5_init.postdate ? krb5_init.postdate: "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default proxiable: %d\n",krb5_d_proxiable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Proxiable: %d\n",krb5_init.proxiable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Renew: %d\n",krb5_init.renew);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default renewable: %d (minutes)\n",krb5_d_renewable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Renewable: %d (minutes)\n",krb5_init.renewable);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Service: \"%s\"\n",
+ krb5_init.service ? krb5_init.service : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Validate: %d\n",krb5_init.validate);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default principal: \"%s\"\n",
+ krb5_d_principal ? krb5_d_principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Principal: \"%s\"\n",
+ krb5_init.principal ? krb5_init.principal : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default instance: \"%s\"\n",
+ krb5_d_instance ? krb5_d_instance : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default realm: \"%s\"\n",
+ krb5_d_realm ? krb5_d_realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Realm: \"%s\"\n",
+ krb5_init.realm ? krb5_init.realm : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Get TGTs: %d\n",krb5_autoget);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Auto-Destroy TGTs: %s\n",
+ krb5_autodel==KRB_DEL_NO?"never":
+ krb5_autodel==KRB_DEL_CL?"on-close":"on-exit");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Default get K4 TGTs: %d\n",krb5_d_getk4);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Get K4 TGTs: %d\n",krb5_init.getk4);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Check IP Addresses: %d\n",krb5_checkaddrs);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" No IP Addresses: %d\n",krb5_d_no_addresses);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" IP-Addresses: ");
+ if (krb5_init.addrs && krb5_init.addrs[0]) {
+ for (i = 0; krb5_init.addrs[i]; i++) {
+ if (i)
+ printf(",");
+ printf("%s",krb5_init.addrs[i]);
+ }
+ } else if (krb5_d_addrs[0]) {
+ for (i = 0;i < KRB5_NUM_OF_ADDRS && krb5_d_addrs[i];i++) {
+ if (i)
+ printf(",");
+ printf("%s",krb5_d_addrs[i]);
+ }
+ } else {
+ printf("(use default)");
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#ifdef COMMENT
+ printf(" Password: \"%s\"\n",
+ krb5_init.password ? krb5_init.password : "");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* COMMENT */
+#endif /* CK_KERBEROS */
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ case AUTHTYPE_SSL:
+ kv = all ? AUTHTYPE_SRP : 0;
+ if (ck_ssleay_is_installed()) {
+ printf(" Authentication: SSL/TLS (%s)\n",
+ SSLeay_version(SSLEAY_VERSION));
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: SSL/TLS (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+
+#ifdef CK_SSL
+ printf(" RSA Certs file: %s\n",ssl_rsa_cert_file?
+ ssl_rsa_cert_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" RSA Certs Chain file: %s\n",ssl_rsa_cert_chain_file?
+ ssl_rsa_cert_chain_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" RSA Key file: %s\n",ssl_rsa_key_file?
+ ssl_rsa_key_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DSA Certs file: %s\n",ssl_dsa_cert_file?
+ ssl_dsa_cert_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DSA Certs Chain file: %s\n",ssl_dsa_cert_chain_file?
+ ssl_dsa_cert_chain_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DH Key file: %s\n",ssl_dh_key_file?
+ ssl_dh_key_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" DH Param file: %s\n",ssl_dh_param_file?
+ ssl_dh_param_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" CRL file: %s\n",ssl_crl_file?
+ ssl_crl_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" CRL dir: %s\n",ssl_crl_dir?
+ ssl_crl_dir:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Random file: %s\n",ssl_rnd_file?
+ ssl_rnd_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verify file: %s\n",ssl_verify_file?
+ ssl_verify_file:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verify dir: %s\n",ssl_verify_dir?
+ ssl_verify_dir:"(none)");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Cipher list: %s\n",ssl_cipher_list ? ssl_cipher_list :
+ DEFAULT_CIPHER_LIST);
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ if (ssl_con == NULL) {
+ SSL_library_init();
+ ssl_ctx = (SSL_CTX *)
+ SSL_CTX_new((SSL_METHOD *)TLSv1_method());
+ if (ssl_ctx != NULL)
+ ssl_con= (SSL *) SSL_new(ssl_ctx);
+ }
+ if (ssl_con != NULL) {
+ CHAR * p = NULL;
+ int i;
+
+ for (i = 0; ; i++) {
+ p = (CHAR *) SSL_get_cipher_list(ssl_con,i);
+ if (p == NULL)
+ break;
+ printf(" %s\n",p);
+ if (++n > cmd_rows - 3)
+ if (!askmore()) return(0); else n = 0;
+ }
+ }
+ printf(" Certs OK? %s\n",ssl_certsok_flag? "yes" : "no");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Debug mode: %s\n", ssl_debug_flag ? "on" : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verbose mode: %s\n", ssl_verbose_flag ? "on" : "off");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" Verify mode: %s\n",
+ ssl_verify_flag == SSL_VERIFY_NONE ? "none" :
+ ssl_verify_flag == SSL_VERIFY_PEER ? "peer-cert" :
+ "fail-if-no-peer-cert");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" SSL only? %s\n", ssl_only_flag ? "yes" : "no");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" TLS only? %s\n", tls_only_flag ? "yes" : "no");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+#endif /* CK_SSL */
+ break;
+ case AUTHTYPE_NTLM:
+ kv = 0;
+ if (ck_ntlm_is_installed()) {
+ printf(" Authentication: NTLM\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" No options\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: NTLM (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ case AUTHTYPE_SRP:
+ kv = all ? AUTHTYPE_NTLM : 0;
+ if (ck_srp_is_installed()) {
+ if (ck_krypto_is_installed())
+ printf(" Authentication: SRP plus Krypto API\n");
+ else
+ printf(" Authentication: SRP\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ printf(" No options\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ } else {
+ printf(" Authentication: SRP (not installed)\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ continue;
+ }
+ printf("\n");
+ if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
+ break;
+ }
+ }
+ return(success = 1);
+}
+#endif /* CK_AUTHENTICATION */
+#endif /* NOSHOW */
+
+#ifdef CK_KERBEROS
+
+/* C P _ A U T H -- AUTHENTICATE command parsing */
+
+int
+cp_auth() { /* Command_Parse AUTHENTICATE */
+ int c, i, n; /* Workers */
+ int rc = 0; /* Return code */
+ int getval; /* Parsing helpers */
+ int tmpauth = 0; /* Temporary authentication type */
+ int kv = 0; /* Temporary Kerberos version */
+ int tmp_action = -1; /* Temporary Kerberos action */
+ int tmp_klc = 0; /* Temporary list-credentials */
+ char tmphlp[256]; /* For building help message */
+ char * p;
+ char * tmppswd = NULL; /* Password */
+ char * tmpprinz = NULL; /* Principal */
+ char * tmprealm = NULL; /* Realm */
+ char * tmpcache = NULL; /* Cache file */
+ char * tmpinst = NULL; /* K4 Instance */
+ char * tmpaddrs[KRB5_NUM_OF_ADDRS];
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+ struct stringint { /* Temporary array for switch values */
+ char * sval; /* String value */
+ int ival; /* Integer value */
+ } pv[KRB_I_MAX+1]; /* This many */
+ struct FDB kw, sw, fl; /* FDBs for each parse function */
+
+ krb_action = -1; /* Initialize Kerberos action. */
+ tmp_action = -1; /* And our local copy. */
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++)
+ tmpaddrs[i] = NULL;
+
+ if ((y = cmkey(kerbtab,kerbtabn,"authentication type","",xxstring)) < 0)
+ {
+ if (y == -3)
+ printf("?Authentication type not specified - nothing happens\n");
+ return(y);
+ }
+ tmpauth = y;
+ debug(F101,"kerberos authentication","",tmpauth);
+ switch (tmpauth) {
+ case AUTH_KRB4: kv = 4; break; /* Don't assume values are the same */
+ case AUTH_KRB5: kv = 5; break;
+ default:
+ printf("?Authentication type not supported: \"%s\"\n",atmbuf);
+ return(-9);
+ }
+
+ /* From here down is Kerberos */
+ ini_kerb(); /* Reset Init data to defaults */
+
+ if (kv == 4) { /* Set K4 defaults */
+ if (krb4_d_realm)
+ makestr(&tmprealm,krb4_d_realm);
+ if (krb4_d_principal)
+ makestr(&tmpprinz,krb4_d_principal);
+ if (krb4_d_instance)
+ makestr(&tmpinst,krb4_d_instance);
+ } else if (kv == 5) { /* Set K5 defaults */
+ if (krb5_d_cc)
+ makestr(&tmpcache,krb5_d_cc);
+ if (krb5_d_realm)
+ makestr(&tmprealm,krb5_d_realm);
+ if (krb5_d_principal)
+ makestr(&tmpprinz,krb5_d_principal);
+ if (krb5_d_instance)
+ makestr(&tmpinst,krb5_d_instance);
+ }
+
+ for (i = 0; i <= KRB_I_MAX; i++) { /* Initialize switch values */
+ pv[i].sval = NULL; /* to null pointers */
+ pv[i].ival = 0; /* and 0 int values */
+ }
+
+ if (kv == 4) { /* Kerberos 4 */
+ pv[KRB_I_LF].ival = krb4_d_lifetime;
+ pv[KRB_I_PA].ival = krb4_d_preauth;
+
+ if ((n = cmkey(krb_a_tbl,krb_a_n,"Kerberos 4 action","",xxstring)) < 0)
+ {
+ if (n == -3)
+ printf("?Action not specified - nothing happens.\n");
+ return(n);
+ }
+ } else if (kv == 5) { /* Kerberos 5 */
+ pv[KRB_I_FW].ival = krb5_d_forwardable;
+ pv[KRB_I_PR].ival = krb5_d_proxiable;
+ pv[KRB_I_LF].ival = krb5_d_lifetime;
+ pv[KRB_I_RB].ival = krb5_d_renewable;
+ pv[KRB_I_K4].ival = krb5_d_getk4;
+ pv[KRB_I_NAD].ival = krb5_d_no_addresses;
+
+ /* Make help message that shows switches and action keywords */
+ ckstrncpy(tmphlp,"Kerberos 5 action, one of the following:\n ",256);
+ for (i = 0; i < krb_a_n; i++) {
+ ckstrncat(tmphlp,krb_a_tbl[i].kwd,sizeof(tmphlp));
+ if (i == krb_a_n - 1)
+ ckstrncat(tmphlp,"\nor switch",sizeof(tmphlp));
+ else
+ ckstrncat(tmphlp," ",sizeof(tmphlp));
+ }
+ /* Set up first set of chained FDB's */
+
+ cmfdbi(&sw, /* First FDB - command switches */
+ _CMKEY, /* fcode */
+ tmphlp, /* hlpmsg */
+ "", /* default (none) */
+ "", /* addtl string data */
+ krb_s_n, /* Switch table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ krb_s_tbl, /* Switch table */
+ &kw /* Pointer to next FDB */
+ );
+ cmfdbi(&kw, /* Second FDB - action keywords */
+ _CMKEY, /* fcode */
+ "Kerberos action", /* hlpmsg */
+ "", /* default (none) */
+ "", /* addtl string data */
+ krb_a_n, /* Switch table size */
+ 0, /* addtl num data (0 = NOT switch) */
+ xxstring, /* Processing function */
+ krb_a_tbl, /* Keyword table */
+ NULL /* Pointer to next FDB (none) */
+ );
+
+ /* Parse */
+
+ while (1) { /* Parse 0 or more switches */
+ rc = cmfdb(&sw); /* Parse something */
+ debug(F101,"kerberos cmfdb 1 rc","",rc);
+ if (rc < 0) { /* Error */
+ if (rc == -3)
+ printf("?Action not specified - nothing happens.\n");
+ return(rc); /* or reparse needed */
+ }
+ if (cmresult.fdbaddr != &sw) /* Break out if not a switch */
+ break;
+ c = cmgbrk(); /* Have switch - get break character */
+ getval = (c == ':' || c == '='); /* Must parse an agument? */
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9); /* OK because nothing malloc'd yet */
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ debug(F101,"kerberos command switch","",n);
+
+ switch (n) { /* Handle the switch */
+ case KRB_S_CA: /* /CACHE:<filename> */
+ p = krb5_d_cc ? krb5_d_cc : "";
+ if ((y = cmofi("Name of cache file",p,&s,xxstring)) < 0) {
+ if (y == -3)
+ s = NULL;
+ else
+ return(y);
+ }
+ makestr(&tmpcache,s);
+ break;
+ default:
+ printf("?Unexpected switch value - internal error\n");
+ return(-9); /* (if) nothing malloc'd yet. */
+ }
+ }
+ if (cmresult.fdbaddr != &kw) { /* Checking... */
+ printf("?Unexpected result - internal error\n");
+ return(-9); /* Nothing malloc'd yet. */
+ }
+ n = cmresult.nresult; /* Get keyword value */
+ } else {
+ printf("?Unexpected Kerberos version - Internal error\n");
+ return(-9);
+ }
+ debug(F101,"kerberos action","",n);
+ switch (n) {
+ case KRB_A_IN: /* INITIALIZE */
+ case KRB_A_DE: /* DESTROY */
+ case KRB_A_LC: /* LIST-CREDENTIALS */
+ tmp_action = n; /* OK, set */
+ break;
+ default: /* Not OK, punt. */
+ printf("?Unexpected action - internal error\n");
+ return(-9);
+ }
+ if (tmp_action == KRB_A_IN) { /* Action is INITIALIZE */
+ int x;
+ cmfdbi(&sw, /* INITIALIZE switches */
+ _CMKEY, /* fcode */
+ "Principal,\n or optional INITIALIZE switch(es)", /* hlpmsg */
+ "", /* default (none) */
+ "", /* addtl string data */
+ kv == 4 ? krb4_i_n : krb5_i_n, /* Switch table size */
+ 4, /* addtl numeric data 2: 4 = cmswi */
+ xxstring, /* Processing function */
+ kv == 4 ? krb4_i_tbl : krb5_i_tbl, /* Switch table */
+ &fl /* Pointer to next FDB */
+ );
+ cmfdbi(&fl, /* 3rd FDB - command to send from */
+ _CMFLD, /* fcode */
+ "Principal", /* hlpmsg */
+ kv == 4 ? krb4_d_principal : krb5_d_principal, /* principal */
+ "", /* addtl string data */
+ 0, /* addtl numeric data 1 */
+ 0, /* addtl numeric data 2 */
+ xxstring,
+ NULL,
+ NULL
+ );
+ while (1) { /* Parse INIT switches or principal */
+ rc = cmfdb(&sw);
+ debug(F101,"kerberos cmfdb 2 rc","",rc);
+ if (rc < 0) {
+ if (rc == -3)
+ printf("?Principal name required\n");
+ goto kerbx;
+ }
+ debug(F101,"kerberos cmfdb 2 fcode","",cmresult.fcode);
+ if (cmresult.fcode != _CMKEY) /* Not a switch, quit switch loop */
+ break;
+ c = cmgbrk(); /* Switch - get break character */
+ debug(F101,"kerberos cmfdb 2 cmgbrk","",c);
+ getval = (c == ':' || c == '=');
+ if (getval && !(cmresult.kflags & CM_ARG)) {
+ printf("?This switch does not take arguments\n");
+ return(-9); /* OK because nothing malloc'd yet */
+ }
+ if (!getval && (cmgkwflgs() & CM_ARG)) {
+ printf("?This switch requires an argument\n");
+ return(-9);
+ }
+ n = cmresult.nresult; /* Numeric result = switch value */
+ switch (n) {
+ /* These don't take args... */
+ case KRB_I_PA: /* /PREAUTH */
+ case KRB_I_FW: /* /FORWARDABLE */
+ case KRB_I_PR: /* /PROXIABLE */
+ case KRB_I_RN: /* /RENEW */
+ case KRB_I_VA: /* /VALIDATE */
+ case KRB_I_NPA: /* /NOT-PREAUTH */
+ case KRB_I_NFW: /* /NOT-FORWARDABLE */
+ case KRB_I_NPR: /* /NOT-PROXIABLE */
+ case KRB_I_VB: /* /VERBOSE */
+ case KRB_I_BR: /* /BRIEF */
+ case KRB_I_K4: /* /KERBEROS4 */
+ case KRB_I_NK4: /* /NO-KERBEROS4 */
+ case KRB_I_POP: /* /POPUP */
+ case KRB_I_NAD: /* /NO-ADDRESSES */
+ if (getval) {
+ printf("?This switch does not take a value\n");
+ rc = -9;
+ goto kerbx;
+ }
+ switch (n) {
+ case KRB_I_NPA:
+ pv[KRB_I_PA].ival = 0;
+ break;
+ case KRB_I_NFW:
+ pv[KRB_I_FW].ival = 0;
+ break;
+ case KRB_I_NPR:
+ pv[KRB_I_PR].ival = 0;
+ break;
+ case KRB_I_VB:
+ pv[KRB_I_BR].ival = 0;
+ break;
+ case KRB_I_NK4:
+ pv[KRB_I_K4].ival = 0;
+ break;
+ default:
+ pv[n].ival = 1;
+ }
+ break;
+
+ /* These do take arguments */
+
+ case KRB_I_RB: /* /RENEWABLE:<minutes> */
+ pv[n].ival = 0;
+ if (!getval) break;
+ if ((rc = cmnum("Minutes",ckitoa(krb5_init.renewable),
+ 10,&y, xxstring)) < 0)
+ goto kerbx;
+ pv[n].ival = y;
+ break;
+
+ case KRB_I_LF: /* /LIFETIME:<minutes> */
+ pv[n].ival = 0;
+ /* Default is previous value */
+ sprintf(tmpbuf,"%d", /* SAFE */
+ kv == 4 ?
+ krb4_init.lifetime :
+ krb5_init.lifetime
+ );
+ if (!getval) break;
+ if ((rc = cmnum("Minutes",tmpbuf,10,&y, xxstring)) < 0)
+ goto kerbx;
+ pv[n].ival = y;
+ break;
+
+ case KRB_I_PD: /* /POSTDATE:<timestamp> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmdate("date-time","",&s,0,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_SR: /* /SERVICE:<name> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmfld("Service-name","",&s,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_RL: /* /REALM:<name> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if (kv == 4)
+ p = krb4_d_realm ? krb4_d_realm : "";
+ else
+ p = krb5_d_realm ? krb5_d_realm : "";
+ if ((rc = cmfld("Realm",p,&s,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_IN: /* /INSTANCE:<name> */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if (kv == 4)
+ p = krb4_d_instance ? krb4_d_instance : "";
+ else
+ p = krb5_d_instance ? krb5_d_instance : "";
+ if ((rc = cmfld("Instance",p,&s,xxstring)) < 0)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_PW: /* /PASSWORD:<password> */
+ debok = 0;
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmfld("Password","",&s,xxstring)) < 0)
+ if (rc != -3)
+ goto kerbx;
+ makestr(&(pv[n].sval),s);
+ break;
+
+ case KRB_I_ADR: /* /ADDRESSES:{<address-list>} */
+ if (pv[n].sval) {
+ free(pv[n].sval);
+ pv[n].sval = NULL;
+ }
+ if (!getval) break;
+ if ((rc = cmfld("List of IP addresses","",&s,xxstring)) < 0)
+ goto kerbx;
+ makelist(s,tmpaddrs,KRB5_NUM_OF_ADDRS);
+ for (i = 0; i < KRB5_NUM_OF_ADDRS && tmpaddrs[i]; i++) {
+ if (inet_addr(tmpaddrs[i]) == 0xffffffff) {
+ printf("invalid ip address: %s\n",tmpaddrs[i]);
+ rc = -9;
+ goto kerbx;
+ }
+ }
+ pv[KRB_I_NAD].ival = 0;
+ break;
+
+ default:
+ printf("?Unexpected switch value - internal error\n");
+ rc = -9;
+ goto kerbx;
+ }
+ }
+ if (cmresult.fcode != _CMFLD) {
+ printf("?Unexected result - internal error\n");
+ rc = -9;
+ goto kerbx;
+ }
+ /* cmresult.sresult may be of the form PRINCIPAL@REALM */
+ i = ckindex("@",cmresult.sresult,0,0,0);
+ if (i != 0) {
+ makestr(&tmprealm,&cmresult.sresult[i]);
+ cmresult.sresult[i-1] = '\0';
+ }
+ makestr(&tmpprinz,cmresult.sresult); /* Principal (user) */
+
+ if ((rc = cmcfm()) < 0) { /* Now get confirmation */
+ if (rc == -3) {
+ printf("?Principal name required\n");
+ }
+ goto kerbx;
+ }
+ if (!tmpprinz || !tmpprinz[0]) {
+ printf("?Principal name required\n");
+ goto kerbx;
+ }
+ if (!pv[KRB_I_RN].ival && !pv[KRB_I_VA].ival) {
+ /* Don't use a password if Validating or Renewing */
+ if (pv[KRB_I_PW].sval) { /* If they gave a /PASSWORD switch */
+ makestr(&tmppswd,pv[KRB_I_PW].sval); /* use this value */
+ }
+#ifdef COMMENT
+ /* Password prompting has been moved to ck_krb[45]_initTGT() */
+ else { /* Otherwise must prompt for it */
+ char prmpt[80];
+ if (pv[KRB_I_RL].sval)
+ sprintf(prmpt,"%s@%s's Password: ",
+ tmpprinz,pv[KRB_I_RL].sval);
+ else if (tmprealm)
+ sprintf(prmpt,"%s@%s's Password: ",
+ tmpprinz,tmprealm);
+ else
+ sprintf(prmpt,"%s's Password: ",tmpprinz);
+#ifdef OS2
+ if (pv[KRB_I_POP].ival) {
+ char passwd[80]="";
+ readpass(prmpt,passwd,80);
+ makestr(&tmppswd,passwd);
+ memset(passwd,0,80);
+ } else
+#endif /* OS2 */
+ {
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(0); /* and no-echo mode */
+ /* Issue prompt if at top level */
+ if (pflag) prompt(xxstring);
+ cmres(); /* Reset the parser */
+ for (rc = -1; rc < 0; ) { /* Prompt till they answer */
+ /* Get a literal line of text */
+ rc = cmtxt("","",&s,NULL);
+ cmres(); /* Reset the parser again */
+ }
+ makestr(&tmppswd,s);
+ printf("\n"); /* Echo a CRLF */
+ cmsetp(psave); /* Restore original prompt */
+ }
+ }
+ x = 0; /* Check for password */
+ if (tmppswd)
+ if (*tmppswd)
+ x = 1;
+ if (!x) {
+ printf("?Password required\n");
+ goto kerbx;
+ }
+#endif /* COMMENT */
+ }
+ } else if (kv == 5 && tmp_action == KRB_A_LC) { /* LIST-CREDENTIALS */
+ tmp_klc = 0;
+ while (1) {
+ if ((x = cmkey(klctab,nklctab,"Switch","",xxstring)) < 0) {
+ if (x == -3) {
+ if ((rc = cmcfm()) < 0)
+ goto kerbx;
+ else
+ break;
+ } else {
+ rc = x;
+ goto kerbx;
+ }
+ }
+ tmp_klc |= x;
+ }
+ } else if ((rc = cmcfm()) < 0) /* DESTROY, just confirm */
+ goto kerbx;
+
+/* Done - Move confirmed data to final locations */
+
+ krb_action = tmp_action; /* Action requested */
+ krb_op.version = kv; /* Kerberos version */
+ krb_op.cache = tmpcache; /* Cache file */
+ tmpcache = NULL; /* So we don't free it */
+
+ switch (krb_action) {
+ case KRB_A_IN: /* INITIALIZE */
+ if (kv == 5) {
+ krb5_init.forwardable = pv[KRB_I_FW].ival;
+ krb5_init.proxiable = pv[KRB_I_PR].ival;
+ krb5_init.lifetime = pv[KRB_I_LF].ival;
+ krb5_init.renew = pv[KRB_I_RN].ival;
+ krb5_init.renewable = pv[KRB_I_RB].ival;
+ krb5_init.validate = pv[KRB_I_VA].ival;
+
+ /* Here we just reassign the pointers and then set them to NULL */
+ /* so they won't be freed below. */
+
+ krb5_init.postdate = pv[KRB_I_PD].sval; pv[KRB_I_PD].sval = NULL;
+ krb5_init.service = pv[KRB_I_SR].sval; pv[KRB_I_SR].sval = NULL;
+ if (pv[KRB_I_RL].sval) {
+ krb5_init.realm = pv[KRB_I_RL].sval; pv[KRB_I_RL].sval = NULL;
+ } else if (tmprealm) {
+ krb5_init.realm = tmprealm; tmprealm = NULL;
+ }
+ if (pv[KRB_I_IN].sval) {
+ krb5_init.instance = pv[KRB_I_IN].sval;
+ pv[KRB_I_IN].sval = NULL;
+ } else if ( tmpinst ) {
+ krb5_init.instance = tmpinst;
+ tmpinst = NULL;
+ }
+ if (tmpprinz) {
+ krb5_init.principal = tmpprinz;
+ tmpprinz = NULL;
+ }
+ krb5_init.password = tmppswd;
+ tmppswd = NULL;
+
+ krb5_init.getk4 = pv[KRB_I_K4].ival;
+ if (krb5_init.getk4) {
+ krb4_init.lifetime = pv[KRB_I_LF].ival;
+ if (krb5_init.realm)
+ makestr(&krb4_init.realm,krb5_init.realm);
+ krb4_init.preauth = krb4_d_preauth;
+ krb4_init.verbose = pv[KRB_I_BR].ival ? 0 : 1;
+ if (krb5_init.principal)
+ makestr(&krb4_init.principal,krb5_init.principal);
+ if (krb5_init.principal)
+ makestr(&krb4_init.password,krb5_init.password);
+ }
+ krb5_init.no_addresses = pv[KRB_I_NAD].ival;
+ if (tmpaddrs[0]) {
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
+ if (krb5_init.addrs[i]) {
+ free(krb5_init.addrs[i]);
+ krb5_init.addrs[i] = NULL;
+ }
+ krb5_init.addrs[i] = tmpaddrs[i];
+ tmpaddrs[i] = NULL;
+ }
+ }
+ } else if (kv == 4) { /* Same deal for Kerberos 4 */
+ krb4_init.lifetime = pv[KRB_I_LF].ival;
+ if (pv[KRB_I_RL].sval) {
+ krb4_init.realm = pv[KRB_I_RL].sval;
+ pv[KRB_I_RL].sval = NULL;
+ } else if ( tmprealm ) {
+ krb4_init.realm = tmprealm;
+ tmprealm = NULL;
+ }
+ if (pv[KRB_I_IN].sval) {
+ krb4_init.instance = pv[KRB_I_IN].sval;
+ pv[KRB_I_IN].sval = NULL;
+ } else if ( tmpinst ) {
+ krb4_init.instance = tmpinst;
+ tmpinst = NULL;
+ }
+ krb4_init.preauth = pv[KRB_I_PA].ival;
+ krb4_init.verbose = pv[KRB_I_BR].ival ? 0 : 1;
+
+ if (tmpprinz) {
+ krb4_init.principal = tmpprinz;
+ tmpprinz = NULL;
+ }
+ krb4_init.password = tmppswd;
+ tmppswd = NULL;
+ }
+ break;
+ case KRB_A_LC: /* List Credentials */
+ krb5_lc.encryption = tmp_klc & XYKLCEN;
+ krb5_lc.flags = tmp_klc & XYKLCFL;
+ krb5_lc.addr = tmp_klc & XYKLCAD;
+ break;
+ }
+
+/* Common exit - Free temporary storage */
+
+ kerbx:
+ for (i = 0; i <= KRB_I_MAX; i++) { /* Free malloc'd switch data */
+ if (pv[i].sval)
+ free(pv[i].sval);
+ }
+ for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
+ if (tmpaddrs[i])
+ free(tmpaddrs[i]);
+ }
+ if (tmpprinz) free(tmpprinz); /* And these too. */
+ if (tmppswd) free(tmppswd);
+ if (tmpcache) free(tmpcache);
+ if (tmprealm) free(tmprealm);
+ if (tmpinst) free(tmpinst);
+
+ return(rc); /* Return the return code */
+}
+#endif /* CK_KERBEROS */
+
+#ifdef CK_LOGIN
+int
+#ifdef CK_ANSIC
+ckxlogin(CHAR * userid, CHAR * passwd, CHAR * acct, int promptok)
+#else /* CK_ANSIC */
+ckxlogin(userid, passwd, acct, promptok)
+ CHAR * userid; CHAR * passwd; CHAR * acct; int promptok;
+#endif /* CK_ANSIC */
+/* ckxlogin */ {
+#ifdef CK_RECALL
+ extern int on_recall; /* around Password prompting */
+#endif /* CK_RECALL */
+#ifdef CK_PAM
+ extern int guest;
+#endif /* CK_PAM */
+ int rprompt = 0; /* Restore prompt */
+#ifdef CKSYSLOG
+ int savlog;
+#endif /* CKSYSLOG */
+
+ extern int what, srvcdmsg;
+
+ int x = 0, ok = 0, rc = 0;
+ CHAR * _u = NULL, * _p = NULL, * _a = NULL;
+
+ debug(F111,"ckxlogin userid",userid,promptok);
+ debug(F110,"ckxlogin passwd",passwd,0);
+
+ isguest = 0; /* Global "anonymous" flag */
+
+ if (!userid) userid = (CHAR *)"";
+ if (!passwd) passwd = (CHAR *)"";
+
+ debug(F111,"ckxlogin userid",userid,what);
+
+#ifdef CK_RECALL
+ on_recall = 0;
+#endif /* CK_RECALL */
+
+#ifdef CKSYSLOG
+ savlog = ckxsyslog; /* Save and turn off syslogging */
+#endif /* CKSYSLOG */
+
+ if ((!*userid || !*passwd) && /* Need to prompt for missing info */
+ promptok) {
+ cmsavp(psave,PROMPTL); /* Save old prompt */
+ debug(F110,"ckxlogin saved",psave,0);
+ rprompt = 1;
+ }
+ if (!*userid) {
+ if (!promptok)
+ return(0);
+ cmsetp("Username: "); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ cmini(1);
+
+/* Flush typeahead */
+
+#ifdef IKS_OPTION
+ debug(F101,
+ "ckxlogin TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ "",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+#endif /* IKS_OPTION */
+
+ while (ttchk() > 0) {
+ x = ttinc(0);
+ debug(F101,"ckxlogin flush user x","",x);
+ if (x < 0)
+ doexit(GOOD_EXIT,0); /* Connection lost */
+#ifdef TNCODE
+ if (sstelnet) {
+ if (x == IAC) {
+ x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc);
+ debug(F101,"ckxlogin user tn_doop","",x);
+#ifdef IKS_OPTION
+ debug(F101,
+ "ckxlogin user TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ "",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+#endif /* IKS_OPTION */
+
+ if (x < 0)
+ goto XCKXLOG;
+ switch (x) {
+ case 1: ckxech = 1; break; /* Turn on echoing */
+ case 2: ckxech = 0; break; /* Turn off echoing */
+#ifdef IKS_OPTION
+ case 4: /* IKS event */
+ if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ break; /* else fall thru... */
+#endif /* IKS_OPTION */
+ case 6: /* Logout */
+ goto XCKXLOG;
+ }
+ }
+ }
+#endif /* TNCODE */
+ }
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (x = -1; x < 0;) { /* Prompt till they answer */
+ /* Get a literal line of text */
+ x=cmtxt("Your username, or \"ftp\", or \"anonymous\"","",&s,NULL);
+ if (x == -4 || x == -10) {
+ printf("\r\n%sLogin cancelled\n",
+ x == -10 ? "Timed out: " : "");
+#ifdef CKSYSLOG
+ ckxsyslog = savlog;
+#endif /* CKSYSLOG */
+ doexit(GOOD_EXIT,0);
+ }
+ if (sstate) /* Did a packet come instead? */
+ goto XCKXLOG;
+ cmres(); /* Reset the parser again */
+ }
+ if ((_u = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XCKXLOG;
+ } else {
+ strcpy((char *)_u,s); /* safe */
+ userid = _u;
+ }
+ }
+ ok = zvuser((char *)userid); /* Verify username */
+ debug(F111,"ckxlogin zvuser",userid,ok);
+
+ if (!*passwd && promptok
+#ifdef CK_PAM
+ && guest
+#endif /* CK_PAM */
+ ) {
+ char prmpt[80];
+
+#ifdef CKSYSLOG
+ savlog = ckxsyslog; /* Save and turn off syslogging */
+ ckxsyslog = 0;
+#endif /* CKSYSLOG */
+
+/* Flush typeahead again */
+
+ while (ttchk() > 0) {
+ x = ttinc(0);
+ debug(F101,"ckxlogin flush user x","",x);
+#ifdef TNCODE
+ if (sstelnet) {
+ if (x == IAC) {
+ x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc);
+ debug(F101,"ckxlogin pass tn_doop","",x);
+#ifdef IKS_OPTION
+ debug(F101,
+ "ckxlogin pass TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
+ "",
+ TELOPT_SB(TELOPT_KERMIT).kermit.me_start
+ );
+#endif /* IKS_OPTION */
+ if (x < 0)
+ goto XCKXLOG;
+ switch (x) {
+ case 1: ckxech = 1; break; /* Turn on echoing */
+ case 2: ckxech = 0; break; /* Turn off echoing */
+ case 4: /* IKS event */
+ if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
+ break; /* else fall thru... */
+ case 6: /* Logout */
+ goto XCKXLOG;
+ }
+ }
+ }
+#endif /* TNCODE */
+ }
+ if (!strcmp((char *)userid,"anonymous") ||
+ !strcmp((char *)userid,"ftp")) {
+ if (!ok)
+ goto XCKXLOG;
+ ckstrncpy(prmpt,"Enter e-mail address as Password: ",80);
+ } else if (*userid && strlen((char *)userid) < 60) {
+#ifdef NT
+ extern CHAR * pReferenceDomainName;
+ if (pReferenceDomainName)
+ ckmakxmsg(prmpt,
+ 80,
+ "Enter ",
+ pReferenceDomainName,
+ "\\\\",
+ userid,
+ "'s Password: ",
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL
+ );
+ else
+#endif /* NT */
+ ckmakmsg(prmpt,80,"Enter ",(char *)userid,"'s Password: ",NULL);
+ } else
+ ckstrncpy(prmpt,"Enter Password: ",80);
+ cmsetp(prmpt); /* Make new prompt */
+ concb((char)escape); /* Put console in cbreak mode */
+ if (strcmp((char *)userid,"anonymous") &&
+ strcmp((char *)userid,"ftp")) { /* and if not anonymous */
+ debok = 0;
+ cmini(0); /* and no-echo mode */
+ } else {
+ cmini(1);
+ }
+ if (pflag) prompt(xxstring); /* Issue prompt if at top level */
+ cmres(); /* Reset the parser */
+ for (x = -1; x < 0;) { /* Prompt till they answer */
+ x = cmtxt("","",&s,NULL); /* Get a literal line of text */
+ if (x == -4 || x == -10) {
+ printf("\r\n%sLogin cancelled\n",
+ x == -10 ? "Timed out: " : "");
+#ifdef CKSYSLOG
+ ckxsyslog = savlog;
+#endif /* CKSYSLOG */
+ doexit(GOOD_EXIT,0);
+ }
+ if (sstate) /* In case of a Kermit packet */
+ goto XCKXLOG;
+ cmres(); /* Reset the parser again */
+ }
+ printf("\r\n"); /* Echo a CRLF */
+ if ((_p = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) {
+ printf("?Internal error: malloc\n");
+ goto XCKXLOG;
+ } else {
+ strcpy((char *)_p,s); /* safe */
+ passwd = _p;
+ }
+ }
+#ifdef CK_PAM
+ else {
+ cmres(); /* Reset the parser */
+
+ /* We restore the prompt now because the PAM engine will call */
+ /* readpass() which will overwrite psave. */
+ if (rprompt) {
+ cmsetp(psave); /* Restore original prompt */
+ debug(F110,"ckxlogin restored",psave,0);
+ rprompt = 0;
+ }
+ }
+#endif /* CK_PAM */
+
+#ifdef CKSYSLOG
+ ckxsyslog = savlog;
+#endif /* CKSYSLOG */
+
+ if (ok) {
+ ok = zvpass((char *)passwd); /* Check password */
+ debug(F101,"ckxlogin zvpass","",ok);
+ }
+
+ if (ok > 0 && isguest) {
+#ifndef NOPUSH
+ nopush = 1;
+#endif /* NOPUSH */
+ srvcdmsg = 1;
+ }
+ rc = ok; /* Set the return code */
+ if ((char *)uidbuf != (char *)userid)
+ ckstrncpy(uidbuf,(char *)userid,UIDBUFLEN); /* Remember username */
+
+ XCKXLOG: /* Common exit */
+#ifdef CKSYSLOG
+ ckxsyslog = savlog; /* In case of GOTO above */
+#endif /* CKSYSLOG */
+ if (rprompt) {
+ cmsetp(psave); /* Restore original prompt */
+ debug(F110,"ckxlogin restored",psave,0);
+ }
+ if (_u || _p || _a) {
+ if (_u) free(_u);
+ if (_p) free(_p);
+ if (_a) free(_a);
+ }
+ return(rc);
+}
+
+int
+ckxlogout() {
+ doexit(GOOD_EXIT,0); /* doexit calls zvlogout */
+ return(0); /* not reached */
+}
+#endif /* CK_LOGIN */
+
+#endif /* NOICP */