popped all patches
[ckermit.git] / .pc / 040_pam-password-prompting.patch / ckufio.c
diff --git a/.pc/040_pam-password-prompting.patch/ckufio.c b/.pc/040_pam-password-prompting.patch/ckufio.c
deleted file mode 100644 (file)
index 298c48e..0000000
+++ /dev/null
@@ -1,8310 +0,0 @@
-/* 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 */