home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / ckofio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  272KB  |  8,553 lines

  1. #ifdef NT
  2. char *ckzv = "Win32 File support, 8.0.187, 18 July 2004";
  3. #else /* NT */
  4. char *ckzv = "OS/2 File support, 8.0.187, 18 July 2004";
  5. #endif /* NT */
  6.  
  7. /* C K O F I O  --  Kermit file system support for OS/2 */
  8.  
  9.  
  10. /*
  11.   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
  12.   compatible with C preprocessors that support only #ifdef, #else, #endif,
  13.   #define, and #undef.  Please do not use #if, logical operators, or other
  14.   preprocessor features in any of the portable C-Kermit modules.  You can,
  15.   of course, use these constructions in system-specific modules when you they
  16.   are supported.
  17. */
  18.  
  19. /*
  20.   Authors: Frank da Cruz (fdc@columbia.edu),
  21.              Columbia University Academic Information Systems, New York City,
  22.            Jeffrey E Altman <jaltman@secure-endpoints.com>
  23.              Secure Endpoints Inc., New York City
  24.   and others noted below.  Note: CUCCA = Previous name of Columbia University
  25.   Academic Information Systems.
  26.  
  27.   Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New
  28.   York.  All rights reserved.
  29. */
  30.  
  31. /* Include Files */
  32.  
  33. #include "ckcsym.h"
  34. #include "ckcdeb.h"
  35. #include "ckcasc.h"
  36. #ifndef NOCSETS
  37. #include "ckcxla.h"
  38. #endif /* NOCSETS */
  39. #include "ckuusr.h"
  40. #ifdef CK_LOGIN                         /* For AUTH_VALID, AUTHTYPE_xxx, ... */
  41. #include "ckctel.h"
  42. #ifdef CK_SSL
  43. #include "ck_ssl.h"
  44. #endif /* CK_SSL */
  45. #endif /* CK_LOGIN */
  46. #include <stdio.h>
  47. #include <errno.h>
  48. _PROTOTYP( int os2settitle, (char *, int) );
  49. extern int priority;
  50. #include <signal.h>
  51.  
  52. /*
  53.  
  54.   C-Kermit's OS/2 support originally by Chris Adie <C.Adie@uk.ac.edinburgh>
  55.   Edinburgh University Computing Service, Scotland, for C-Kermit 4F.  Adapted
  56.   to C-Kermit 5A and integrated into the UNIX support module by Kai Uwe Rommel
  57.   <rommel@informatik.tu-muenchen.de>, Muenchen, Germany, December 1991.
  58.  
  59.   And then split away from the Unix modules for C-Kermit 6.1 because the
  60.   amount of disparate code was just too great.
  61. */
  62.  
  63. /*
  64.   Directory Separator macros, to allow this module to work with both UNIX and
  65.   OS/2: Because of ambiguity with the command line editor escape \ character,
  66.   the directory separator is currently left as / for OS/2 too, because the
  67.   OS/2 kernel also accepts / as directory separator.  But this is subject to
  68.   change in future versions to conform to the normal OS/2 style.
  69.  
  70.   Win32 also allows the Directory Separator to be / when it is used for
  71.   local disk operations.  However, if a UNC is in use, then \ must be used.
  72.   So we have two choices, we can return UNC names with \ quoted which might
  73.   break if the command quoting is turned off, or we can performed the reverse
  74.   translation in all file i/o functions if the first two characters are "//"
  75.   indicating a UNC.
  76. */
  77. #ifndef DIRSEP
  78. #define DIRSEP       '/'
  79. #endif /* DIRSEP */
  80. #ifndef ISDIRSEP
  81. #define ISDIRSEP(c)  ((c)=='/'||(c)=='\\')
  82. #endif /* ISDIRSEP */
  83.  
  84. #ifdef SDIRENT
  85. #define DIRENT
  86. #endif /* SDIRENT */
  87.  
  88. #include "ckodir.h"
  89.  
  90. extern int binary;                      /* We need to know this for open() */
  91. #ifdef CK_CTRLZ
  92. extern int eofmethod;
  93. #endif /* CK_CTRLZ */
  94. extern int k95stdin,k95stdout;
  95.  
  96. #include <sys/utime.h>
  97. #include <stdlib.h>
  98. #include <process.h>
  99. #include <share.h>
  100. extern int fncact;                      /* Need this for zchkspa()         */
  101. extern int tlevel, cmdlvl;              /* Need this for external commands */
  102. #ifdef __IBMC__
  103. extern FILE *popen(char *, char *);
  104. extern int pclose(FILE *);
  105. #else
  106. #define popen    _popen
  107. #define pclose   _pclose
  108. #define fopen(n, m)  _fsopen(n, m, _SH_DENYWR)
  109. #endif /* __IBMC__ */
  110. #ifdef NT
  111. #include <io.h>
  112. #endif /* NT */
  113.  
  114. #define TIMESTAMP                       /* Can do file dates */
  115. #include <time.h>                       /* Need this */
  116. #include <sys/timeb.h>                  /* Need this too */
  117. #include <sys/stat.h>
  118. #include <sys/types.h>
  119.  
  120. #ifdef __IBMC__
  121. #ifdef system
  122. #undef system
  123. #endif
  124. #ifdef COMMENT
  125. #ifdef stat
  126. #undef stat
  127. #endif
  128. #define stat _stat
  129. #endif /* COMMENT */
  130. #endif
  131.  
  132. #ifdef NT
  133. #define timezone _timezone
  134. #define write _write
  135. #define fileno _fileno
  136. #define stricmp _stricmp
  137. #define setmode _setmode
  138. #define access _access
  139. #define unlink _unlink
  140. #define chdir  _chdir
  141. #define getcwd _getcwd
  142. #define utime  _utime
  143. #define rmdir  _rmdir
  144. #define utimbuf _utimbuf
  145. #define stat    _stat
  146. #ifndef SEM_INDEFINITE_WAIT
  147. #define SEM_INDEFINITE_WAIT INFINITE
  148. #endif /* SEM_INDEFINITE_WAIT */
  149. #endif /* NT */
  150.  
  151. /* Because standard stat has trouble with trailing /'s we have to wrap it */
  152. int os2stat(char *, struct stat *);
  153.  
  154. /* Is `y' a leap year? */
  155. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  156.  
  157. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  158. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  159.  
  160. #ifdef DEBUG
  161. extern int deblog;
  162. #else
  163. #define deblog 0
  164. #endif /* DEBUG */
  165. extern int xferlog;
  166. extern char * xferfile;
  167. int iklogopen = 0;
  168. static time_t timenow;
  169. static int logged_in = 0;
  170. static char iksdmsg[CKMAXPATH+512];
  171. extern char exedir[CKMAXPATH];
  172. #ifndef XFERFILE
  173. #define XFERFILE "iksd.log"
  174. #endif /* XFERFILE */
  175.  
  176. /*
  177.   Functions (n is one of the predefined file numbers from ckcker.h):
  178.  
  179.    zopeni(n,name)   -- Opens an existing file for input.
  180.    zopeno(n,name,attr,fcb) -- Opens a new file for output.
  181.    zclose(n)        -- Closes a file.
  182.    zchin(n,&c)      -- Gets the next character from an input file.
  183.    zsinl(n,&s,x)    -- Read a line from file n, max len x, into address s.
  184.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  185.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  186.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  187.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  188.    zchki(name)      -- Check if named file exists and is readable, return size.
  189.    zchko(name)      -- Check if named file can be created.
  190.    zchkspa(name,n)  -- Check if n bytes available to create new file, name.
  191.    znewn(name,s)    -- Make a new unique file name based on the given name.
  192.    zdelet(name)     -- Delete the named file.
  193.    nzxpand(string,flags) -- Expands the given wildcard string into a list of files.
  194.    znext(string)    -- Returns the next file from the list in "string".
  195.    zxcmd(n,cmd)     -- Execute the command in a lower fork on file number n.
  196.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  197.    zrtol(n1,n2)     -- Convert remote filename into local form.
  198.    zltor(n1,n2)     -- Convert local filename into remote form.
  199.    zchdir(dirnam)   -- Change working directory.
  200.    zhome()          -- Return pointer to home directory name string.
  201.    zkself()         -- Kill self, log out own job.
  202.    zsattr(struct zattr *) -- Return attributes for file which is being sent.
  203.    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
  204.    zrename(old, new) -- Rename a file.
  205.    zlink(source,destination) -- Link a file.
  206.    zcopy(source,destination) -- Copy a file.
  207.    zmkdir(path)       -- Create the directory path if possible
  208.    zfnqfp(fname,len,fullpath) - Determine full path for file name.
  209. */
  210.  
  211. /* Kermit-specific includes */
  212. /*
  213.   Definitions here supersede those from system include files.
  214.   ckcdeb.h is included above.
  215. */
  216. #include "ckcker.h"                     /* Kermit definitions */
  217. #include "ckucmd.h"                     /* For sys-dependent keyword tables */
  218. #include "ckuver.h"                     /* Version herald */
  219.  
  220. char *ckzsys = HERALD;
  221.  
  222. #include <fcntl.h>
  223.  
  224. /* Define macros for getting file type */
  225.  
  226. #ifdef ISDIRBUG                         /* Also allow this from command line */
  227. #ifdef S_ISREG
  228. #undef S_ISREG
  229. #endif /* S_ISREG */
  230. #ifdef S_ISDIR
  231. #undef S_ISDIR
  232. #endif /*  S_ISDIR */
  233. #endif /* ISDIRBUG */
  234.  
  235. #ifndef S_IFREG
  236. #ifdef  _S_IFREG
  237. #define S_IFREG _S_IFREG
  238. #endif
  239. #endif
  240.  
  241. #ifndef S_IFDIR
  242. #ifdef  _S_IFDIR
  243. #define S_IFDIR _S_IFDIR
  244. #endif
  245. #endif
  246.  
  247. #ifndef S_IFMT
  248. #ifdef _S_IFMT
  249. #define S_IFMT _S_IFMT
  250. #endif
  251. #endif
  252.  
  253. #ifndef S_ISREG
  254. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  255. #endif /* S_ISREG */
  256. #ifndef S_ISDIR
  257. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  258. #endif /* S_ISDIR */
  259.  
  260. /* More macros we might need */
  261. #ifndef _O_APPEND
  262. #define _O_APPEND  O_APPEND
  263. #endif
  264. #ifndef _O_WRONLY
  265. #define _O_WRONLY  O_WRONLY
  266. #endif
  267. #ifndef _O_CREAT
  268. #define _O_CREAT   O_CREAT
  269. #endif
  270. #ifndef _O_TEXT
  271. #define _O_TEXT    O_TEXT
  272. #endif
  273. #ifndef _SH_DENYNO
  274. #define _SH_DENYNO SH_DENYNO
  275. #endif
  276. #ifndef _O_BINARY
  277. #define _O_BINARY  O_BINARY
  278. #endif
  279.  
  280. /* Longest pathname ... */
  281. #ifdef MAXPATHLEN
  282. #ifdef MAXPATH
  283. #undef MAXPATH
  284. #endif /* MAXPATH */
  285. #define MAXPATH MAXPATHLEN
  286. #else
  287. #ifdef PATH_MAX
  288. #define MAXPATH PATH_MAX
  289. #else
  290. #define MAXPATH 255
  291. #endif /* PATH_MAX */
  292. #endif /* MAXPATHLEN */
  293.  
  294. #ifndef NOPUSH
  295. extern int nopush;
  296. #endif /* NOPUSH */
  297. _PROTOTYP( char * zdtstr, (time_t) );
  298. _PROTOTYP( time_t zstrdt, (char *, int) );
  299.  
  300. /* Some systems define these symbols in include files, others don't... */
  301.  
  302. #ifndef R_OK
  303. #define R_OK 4                          /* For access */
  304. #endif /* R_OK */
  305.  
  306. #ifndef W_OK
  307. #define W_OK 2
  308. #endif /* W_OK */
  309.  
  310. #ifndef O_RDONLY
  311. #define O_RDONLY 000
  312. #endif /* O_RDONLY */
  313.  
  314. #ifdef CKROOT
  315. static char ckroot[CKMAXPATH+1] = { NUL, NUL };
  316. static int ckrootset = 0;
  317. int ckrooterr = 0;
  318. #endif /* CKROOT */
  319.  
  320.     /* syslog and wtmp items for Internet Kermit Service */
  321. extern char * clienthost;               /* From ckcmai.c. */
  322. extern int ckxlogging;
  323. static char fullname[CKMAXPATH+1];
  324. static char tmp2[CKMAXPATH+1];
  325.  
  326. #ifdef CK_LOGIN
  327. int ckxanon = 0;                        /* Anonymous login not ok */
  328. char * anonacct = NULL;
  329. #ifdef NT
  330. char * iks_domain = NULL;               /* Default domain to use for logins */
  331. #endif /* NT */
  332. #ifdef CK_PERMS
  333. int ckxperms = 0040;
  334. #endif /* CK_PERMS */
  335. #ifdef UNIX
  336. int ckxpriv = 1;                        /* Allow Root logins? */
  337. #endif /* UNIX */
  338. #endif /* CK_LOGIN */
  339.  
  340. #ifndef CKWTMP
  341. int ckxwtmp = 0;
  342. #else
  343. int ckxwtmp = 1;
  344. #include <utmp.h>
  345. #define WTMPFILE "/usr/adm/wtmp"        /* I hope this is portable */
  346. char * wtmpfile = NULL;
  347.  
  348. static int wtmpfd = 0;
  349. static char cksysline[32] = { NUL, NUL };
  350.  
  351. VOID
  352. logwtmp(line, name, host) char *line, *name, *host; {
  353.     struct utmp ut;
  354.     struct stat buf;
  355.     time_t time();
  356.  
  357.     if (!ckxwtmp)
  358.       return;
  359.  
  360.     if (!wtmpfile)
  361.       makestr(&wtmpfile,WTMPFILE);
  362.  
  363.     if (!line) line = "";
  364.     if (!name) name = "";
  365.     if (!host) host = "";
  366.  
  367.     if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) {
  368.         ckxwtmp = 0;
  369.         debug(F110,"WTMP open failed",line,0);
  370.         return;
  371.     }
  372.     if (!fstat(wtmpfd, &buf)) {
  373.         ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
  374.         ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
  375.         ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
  376.         time(&ut.ut_time);
  377.         if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) !=
  378.             sizeof(struct utmp)) {
  379.             ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */
  380.             debug(F110,"WTMP write error",line,0);
  381.         } else {
  382.             debug(F110,"WTMP record OK",line,0);
  383.             return;
  384.         }
  385.     }
  386. }
  387. #endif /* CKWTMP */
  388.  
  389. /* Declarations */
  390.  
  391. int mskrename = 0;                      /* MS-Kermit file collision renaming off */
  392. int maxnam = MAXNAMLEN;                 /* Available to the outside */
  393. int maxpath = MAXPATH;
  394. int ck_znewn = -1;
  395. int pexitstat = -2;                     /* Process exit status */
  396.  
  397. FILE *fp[ZNFILS] = {                    /* File pointers */
  398.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  399.  
  400. /* Flags for each file indicating whether it was opened with popen() */
  401. int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  402.  
  403. /* Buffers and pointers used in buffered file input and output. */
  404. #ifdef DYNAMIC
  405. extern char *zinbuffer, *zoutbuffer;
  406. #else
  407. extern char zinbuffer[], zoutbuffer[];
  408. #endif /* DYNAMIC */
  409. extern char *zinptr, *zoutptr;
  410. extern int zincnt, zoutcnt;
  411.  
  412. static long iflen = -1L;                /* Input file length */
  413.  
  414. static PID_T pid = 0;                   /* pid of child fork */
  415. static int fcount[2] = {0,0};           /* Number of files left in search */
  416. static int fcntsav[2] = {0,0};
  417. static int fcountstream[2] = {0,0};
  418. static int fcntstreamsav[2] = {0,0};
  419. static char nambuf[MAXNAMLEN+4];        /* Buffer for a filename */
  420. static char UNCnam[MAXNAMLEN+1];        /* Scratch buffer for UNC names */
  421. #ifndef NOFRILLS
  422. static char zmbuf[200];                 /* For mail, remote print strings */
  423. #endif /* NOFRILLS */
  424.  
  425. #ifdef  OS2ONLY
  426. #define INCL_KBD
  427. #define INCL_DOSERRORS
  428. #define INCL_DOSFILEMGR
  429. #define INCL_DOSPROCESS
  430. #define INCL_DOSSEMAPHORES
  431. #include <os2.h>
  432. typedef unsigned short WORD;
  433. #undef COMMENT
  434.  
  435. /* Get/Set All Extended Attributes support */
  436.  
  437. #define FreeMem(p) DosFreeMem(p)
  438.  
  439. #define MAX_GEA            500L  /* Max size for a GEA List */
  440. #define MAXEACOUNT          128  /* Max number of EA's supported */
  441. #define Ref_ASCIIZ            1  /* Reference type for DosEnumAttribute */
  442.  
  443. /* Definition of level specifiers, required for File Info */
  444.  
  445. #define GetInfoLevel1         1            /* Get info from SFT */
  446. #define GetInfoLevel2         2            /* Get size of FEAlist */
  447. #define GetInfoLevel3         3            /* Get FEAlist given the GEAlist */
  448. #define GetInfoLevel4         4            /* Get whole FEAlist */
  449. #define GetInfoLevel5         5            /* Get FSDname */
  450.  
  451. #define SetInfoLevel1         1            /* Set info in SFT */
  452. #define SetInfoLevel2         2            /* Set FEAlist */
  453.  
  454. FEA2LIST *pFEAList = 0;  /* Pointer to buffer containing all EA information */
  455. ULONG os2attrs = FILE_NORMAL;
  456. extern unsigned int lf_opts;
  457. #endif /* OS2ONLY */
  458.  
  459. #ifdef NT
  460. #include <windows.h>
  461. #ifdef CK_LOGIN
  462. #define SECURITY_WIN32
  463. #include <security.h>
  464. #include <ntsecapi.h>
  465. #include <lmaccess.h>
  466. #include <lmapibuf.h>
  467. #include <lmerr.h>
  468. #endif /* CK_LOGIN */
  469. #endif /* NT */
  470. char os2filename[MAXPATH];
  471.  
  472. #ifdef IKSD
  473. extern int inserver, local;
  474. #endif /* IKSD */
  475.  
  476. extern int server, en_mkd, en_cwd, en_del;
  477.  
  478. extern char uidbuf[];           /* from ckcmai.c... */
  479. #ifdef CK_LOGIN
  480. #ifdef CKROOT
  481. extern char * anonroot;
  482. #endif /* CKROOT */
  483. extern int isguest;
  484. #define GUESTPASS_LEN 256
  485. static char guestpass[GUESTPASS_LEN] = "";
  486. #endif /* CK_LOGIN */
  487.  
  488. _PROTOTYP(char * whoami, (void));
  489.  
  490. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  491.  
  492. int
  493. zkself() {                              /* For "bye", but no guarantee! */
  494.     _exit(3);
  495.     return(0);
  496. }
  497.  
  498. /* Z C H K P I D -- Check to see if a PID is valid */
  499. /* returns 1 if pid is valid and active, 0 if not  */
  500.  
  501. int
  502. zchkpid(unsigned long pid) {
  503. #ifdef NT
  504.     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,0,pid);
  505.     if ( hProcess ) {
  506.         CloseHandle(hProcess);
  507.         return(1);
  508.     }
  509.     return(0);
  510. #else /* NT */
  511. #endif /* NT */
  512.     return(1);
  513. }
  514.  
  515. /*  D O I K L O G  --  Open Kermit-specific ftp-like transfer log. */
  516.  
  517. VOID                                    /* called in ckcmai.c */
  518. doiklog() {
  519.     if (iklogopen)                      /* Already open? */
  520.       return;
  521.     debug(F111,"doiklog",xferfile,xferlog);
  522.     if (xferlog) {                      /* Open iksd log if requested */
  523.         if (!xferfile) {                /* If no pathname given */
  524.           char buf[MAXPATH];
  525.           ckstrncpy(buf,exedir,MAXPATH);
  526.           ckstrncat(buf,XFERFILE,MAXPATH);
  527.           makestr(&xferfile,buf);       /* use this default */
  528.         }
  529.         if (*xferfile) {
  530.             xferlog = sopen(xferfile, _O_WRONLY | _O_APPEND | _O_CREAT | _O_TEXT,
  531.                              _SH_DENYNO, 666 );
  532.             debug(F111,"doiklog open()",xferfile,xferlog);
  533.             if (xferlog < 0) {
  534. #ifdef CKSYSLOG
  535.                 cksyslog(SYSLG_FC, 0, "xferlog open failure",xferfile,NULL);
  536. #endif /* CKSYSLOG */
  537.                 debug(F101,"doiklog open errno","",errno);
  538.                 xferlog = 0;
  539.             } else
  540.               iklogopen = 1;
  541.         } else
  542.           xferlog = 0;
  543. #ifdef CKSYSLOG
  544.         if (ckxlogging) {
  545.             if ( xferlog )
  546.                 cksyslog(SYSLG_FC, 1, "xferlog: open ok", xferfile, NULL);
  547.             else
  548.                 cksyslog(SYSLG_FC, 0, "xferlog: open failed", xferfile, NULL);
  549.         }
  550. #endif /* CKSYSLOG */
  551.     }
  552. }
  553.  
  554. static VOID
  555. getfullname(name) char * name; {
  556.     char *p = (char *)fullname;
  557.     int len = 0;
  558.     fullname[0] = '\0';
  559.     /* If necessary we could also chase down symlinks here... */
  560. #ifdef COMMENT
  561.     /* This works but is incompatible with wuftpd */
  562.     if (isguest && anonroot) {
  563.         ckstrncpy(fullname,anonroot,CKMAXPATH);
  564.         len = strlen(fullname);
  565.         if (len > 0)
  566.           if (fullname[len-1] == '/')
  567.             len--;
  568.     }
  569.     p += len;
  570. #endif /* COMMENT */
  571.     zfnqfp(name, CKMAXPATH - len, p);
  572.     while (*p) {
  573.         if (*p < '!') *p = '_';
  574.         p++;
  575.     }
  576. }
  577.  
  578. /*  Z O P E N I  --  Open an existing file for input. */
  579.  
  580. /* Returns 1 on success, 0 on failure */
  581.  
  582. int
  583. zopeni(n,name) int n; char *name; {
  584.     int x, y;
  585.  
  586.     debug(F111,"zopeni name",name,n);
  587.     debug(F101,"zopeni fp","", (unsigned) fp[n]);
  588.     if (chkfn(n) != 0) {
  589.         debug(F110,"zopeni chkfn()","file is open",0);
  590.         return(0);
  591.     }
  592.     zincnt = 0;                         /* Reset input buffer */
  593.     if (n == ZSYSFN) {                  /* Input from a system function? */
  594. /*** Note, this function should not be called with ZSYSFN ***/
  595. /*** Always call zxcmd() directly, and give it the real file number ***/
  596. /*** you want to use.  ***/
  597.         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
  598.         *nambuf = '\0';                 /* No filename. */
  599.         return(0);                      /* fail. */
  600. #ifdef COMMENT
  601.         return(zxcmd(n,name));          /* Try to fork the command */
  602. #endif
  603.     }
  604.     if (n == ZSTDIO) {                  /* Standard input? */
  605.         if (is_a_tty(0)) {
  606.             fprintf(stderr,"Terminal input not allowed");
  607.             debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  608.             return(0);
  609.         }
  610.         fp[ZIFILE] = stdin;
  611.         ispipe[ZIFILE] = 0;
  612.         setmode(fileno(stdin),_O_BINARY);
  613.         return(1);
  614.     }
  615.  
  616. #ifdef CKROOT
  617.     debug(F111,"zopeni setroot",ckroot,ckrootset);
  618.     if (ckrootset)
  619.         if (!zinroot(name)) {
  620.             debug(F110,"zopeni setroot violation",name,0);
  621.             return(0);
  622.         }
  623. #endif /* CKROOT */
  624.  
  625.     if (n == ZIFILE || n == ZRFILE) {
  626.         ckstrncpy( os2filename, name, MAXPATH ) ;
  627.         errno = 0;
  628. #ifdef NT
  629.         fp[n] = _fsopen(name,"rb",_SH_DENYWR);          /* Binary mode */
  630.         if (fp[n])
  631.             _setmode(_fileno(fp[n]),_O_SEQUENTIAL);
  632.         else {
  633.             debug(F111,"zopeni ZI/ZR _fsopen failed","GetLastError",GetLastError());
  634.         }
  635. #else
  636.         fp[n] = fopen(name,"rb");/* Binary mode */
  637. #endif /* NT */
  638.         ispipe[ZIFILE] = 0;
  639.         if (fp[ZIFILE]) {
  640.             x = ferror(fp[ZIFILE]);
  641. #ifdef ZDEBUG
  642.             printf("ZOPENI errno=%d\n",errno);
  643.             printf("ZOPENI ferror=%d\n",x);
  644. #endif /* ZDEBUG */
  645.         }
  646. #ifdef CK_LABELED
  647.         if (binary == XYFT_L) {
  648.             os2getattr(name);
  649.             os2geteas(name);
  650.         }
  651. #endif /* CK_LABELED */
  652.     } else {
  653. #ifdef NT
  654.         fp[n] = _fsopen(name,"rb",_SH_DENYWR); /* Real file, open it. */
  655.         if (fp[n])
  656.             _setmode(_fileno(fp[n]),_O_SEQUENTIAL);
  657.         else {
  658.             debug(F111,"zopeni _fsopen failed","GetLastError",GetLastError());
  659.         }
  660. #else
  661.         fp[n] = fopen(name,"rb");/* Real file, open it. */
  662. #endif /* NT */
  663.     }
  664.     debug(F111,"zopeni fopen", name, fp[n]);
  665. #ifdef ZDEBUG
  666.     printf("ZOPENI fp[%d]=%ld\n",n,fp[n]);
  667. #endif /* ZDEBUG */
  668.     ispipe[n] = 0;
  669.  
  670.     if (xferlog
  671. #ifdef CKSYSLOG
  672.         || ckxsyslog >= SYSLG_FA && ckxlogging
  673. #endif /* CKSYSLOG */
  674.         ) {
  675.         getfullname(name);
  676.         debug(F110,"zopeni fullname",fullname,0);
  677.     }
  678.  
  679.     if (fp[n] == NULL) {
  680. #ifdef CKSYSLOG
  681.         if (ckxsyslog >= SYSLG_FA && ckxlogging) {
  682.             char buf[1024];
  683.             sprintf(buf,"file[%d] %s: open failed",n,fullname);
  684.             cksyslog(SYSLG_FA, 0, buf,NULL,NULL);
  685.         }
  686.         perror(fullname);
  687. #else
  688.         perror(name);
  689. #endif /* CKSYSLOG */
  690.         return(0);
  691.     } else {
  692. #ifdef CKSYSLOG
  693.         if (ckxsyslog >= SYSLG_FA && ckxlogging) {
  694.           char buf[1024];
  695.           sprintf(buf,"file[%d] %s: open read ok", n, fullname);
  696.           cksyslog(SYSLG_FA, 1, buf, NULL, NULL);
  697.         }
  698. #endif /* CKSYSLOG */
  699.         clearerr(fp[n]);
  700.         return(1);
  701.     }
  702. }
  703.  
  704. /*  Z O P E N O  --  Open a new file for output.  */
  705.  
  706. int
  707. zopeno(n,name,zz,fcb)
  708. /* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
  709.  
  710.     char p[8];                          /* (===OS2 change===) */
  711.     int append = 0;
  712.  
  713. /* As of Version 5A, the attribute structure and the file information */
  714. /* structure are included in the arglist. */
  715.  
  716. #ifdef DEBUG
  717.     debug(F111,"zopeno",name,n);
  718.     if (fcb) {
  719.         debug(F101,"zopeno fcb disp","",fcb->dsp);
  720.         debug(F101,"zopeno fcb type","",fcb->typ);
  721.         debug(F101,"zopeno fcb char","",fcb->cs);
  722.     } else {
  723.         debug(F100,"zopeno fcb is NULL","",0);
  724.     }
  725. #endif /* DEBUG */
  726.  
  727.     if (chkfn(n) != 0)                  /* Already open? */
  728.       return(0);                        /* Nothing to do. */
  729.  
  730.     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
  731.         fp[ZOFILE] = stdout;
  732.         ispipe[ZOFILE] = 0;
  733. #ifdef DEBUG
  734.         if (n != ZDFILE)
  735.           debug(F101,"zopeno fp[n]=stdout","",fp[n]);
  736. #endif /* DEBUG */
  737.         zoutcnt = 0;
  738.         zoutptr = zoutbuffer;
  739.         return(1);
  740.     }
  741.  
  742. /* A real file.  Open it in desired mode (create or append). */
  743. #ifdef CKROOT
  744.     debug(F111,"zopeno setroot",ckroot,ckrootset);
  745.     if (ckrootset)
  746.         if (!zinroot(name)) {
  747.             debug(F110,"zopeno setroot violation",name,0);
  748.             return(0);
  749.         }
  750. #endif /* CKROOT */
  751.  
  752.     ckstrncpy(p,"w",8);                      /* Assume write/create mode */
  753.     if (fcb) {                          /* If called with an FCB... */
  754.         if (fcb->dsp == XYFZ_A) {       /* Does it say Append? */
  755.             ckstrncpy(p,"a",8);              /* Yes. */
  756.             debug(F100,"zopeno append","",0);
  757.             append = 1;
  758.         }
  759.     }
  760.     if (n == ZOFILE || n == ZSFILE) {   /* OS/2 binary mode */
  761.         ckstrncpy( os2filename, name, MAXPATH ) ;
  762.         ckstrncat(p,"b",8);
  763.     }
  764.  
  765.     if (xferlog
  766. #ifdef CKSYSLOG
  767.         || ckxsyslog >= SYSLG_FC && ckxlogging
  768. #endif /* CKSYSLOG */
  769.         ) {
  770.         getfullname(name);
  771.         debug(F110,"zopeno fullname",fullname,0);
  772.     }
  773.     debug(F110,"zopeno fopen arg",p,0);
  774.  
  775. #ifdef NT_COMMENT
  776.     /*
  777.     There is a good reason I never did this before.  And that is
  778.     because Windows 95 does not support Overlapped I/O for disk
  779.     files nor does the C Run Time Library.
  780.     */
  781.     if ( !isWin95() )
  782.     {
  783.         SECURITY_ATTRIBUTES security ;
  784.         HANDLE hFile = NULL;
  785.  
  786.         memset(&security, 0, sizeof(SECURITY_ATTRIBUTES));
  787.         security.nLength = sizeof(SECURITY_ATTRIBUTES);
  788.         security.lpSecurityDescriptor = NULL ;
  789.         security.bInheritHandle = FALSE ;
  790.  
  791.         hFile = CreateFile(name,
  792.                             GENERIC_WRITE | GENERIC_READ,
  793.                             FALSE, /* do not share */
  794.                             &security,
  795.                             OPEN_ALWAYS,
  796.                             FILE_ATTRIBUTE_NORMAL |
  797.                             /* FILE_FLAG_OVERLAPPED |*/
  798.                             FILE_FLAG_SEQUENTIAL_SCAN,
  799.                             NULL);
  800.         if (hFile == INVALID_HANDLE_VALUE) {
  801.             fp[n] = NULL;
  802.         }
  803.         else {
  804.             int fd = _open_osfhandle( (int) hFile,
  805.                                       (n == ZOFILE || n == ZSFILE) ?
  806.                                       _O_BINARY : _O_TEXT );
  807.             if ( fd == -1 )
  808.                 fp[n] = NULL;
  809.             else
  810.                 fp[n] = _fdopen(fd, p);
  811.         }
  812.     } else
  813. #endif /* NT_COMMENT */
  814.     {
  815.         fp[n] = fopen(name,p);          /* Try to open the file */
  816.     }
  817.     ispipe[ZIFILE] = 0;
  818.  
  819. #ifdef ZDEBUG
  820.     printf("ZOPENO fp[%d]=%ld\n",n,fp[n]);
  821. #endif /* ZDEBUG */
  822.  
  823.     if (fp[n] == NULL) {                /* Failed */
  824.         debug(F101,"zopeno failed errno","",errno);
  825. #ifdef CKSYSLOG
  826.         if (ckxsyslog >= SYSLG_FC && ckxlogging) {
  827.             char buf[1024];
  828.             sprintf(buf, "file[%d] %s: %s failed (%m)",
  829.                  n,
  830.                  fullname,
  831.                  append ? "append" : "create"
  832.                  );
  833.             cksyslog(SYSLG_FC, 0, buf, NULL, NULL);
  834.         }
  835. #endif /* CKSYSLOG */
  836.     } else {                            /* Succeeded */
  837. #ifdef NT
  838.         if ( n == ZOFILE )
  839.             _setmode(_fileno(fp[n]),_O_SEQUENTIAL);
  840. #endif /* NT */
  841.         if (n == ZDFILE ||              /* If it's the debug log */
  842.             n == ZTFILE )               /* or the transaction log */
  843.           setbuf(fp[n],NULL);           /* make it unbuffered */
  844. #ifdef CKSYSLOG
  845.         if (ckxsyslog >= SYSLG_FC && ckxlogging) {
  846.             char buf[1024];
  847.             sprintf(buf, "file[%d] %s: %s ok",
  848.                      n, fullname, append ? "append" : "create");
  849.             cksyslog(SYSLG_FC, 1, buf, NULL, NULL);
  850.         }
  851. #endif /* CKSYSLOG */
  852.         debug(F100, "zopeno ok", "", 0);
  853.     }
  854.     zoutcnt = 0;                        /* (PWP) reset output buffer */
  855.     zoutptr = zoutbuffer;
  856.     return((fp[n] != NULL) ? 1 : 0);
  857. }
  858.  
  859. /*  Z C L O S E  --  Close the given file.  */
  860.  
  861. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  862.  
  863. int
  864. zclose(n) int n; {
  865.     int x, x2;
  866.     extern long ffc;
  867.  
  868.     debug(F101,"zclose","",n);
  869.     if (chkfn(n) < 1) return(0);        /* Check range of n */
  870.     if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
  871.       x2 = zoutdump();
  872.     else
  873.       x2 = 0;
  874.  
  875.     x = 0;                              /* Initialize return code */
  876.     if (fp[ZSYSFN] || ispipe[n]) {      /* If file is really pipe */
  877.         x = zclosf(n);                  /* do it specially */
  878.         debug(F101,"zclose zclosf","",x);
  879.         debug(F101,"zclose zclosf fp[n]","",fp[n]);
  880.     } else {
  881.         if ((fp[n] != stdout) && (fp[n] != stdin))
  882.           x = fclose(fp[n]);
  883.         fp[n] = NULL;
  884. #ifdef CK_LABELED
  885.         if (binary == XYFT_L) {
  886.             debug(F111,"zclose LABELED","file number",n);
  887.             if (n == ZOFILE) {
  888.                 debug(F111,"zclose LABELED",
  889.                       "lf_opts && LBL_EXT",
  890.                       lf_opts && LBL_EXT
  891.                       );
  892.                 if (lf_opts && LBL_EXT)
  893.                   os2seteas(os2filename);
  894.                 os2setattr(os2filename);
  895.             } else if (n == ZIFILE && pFEAList) {
  896.                 FreeMem(pFEAList);
  897.                 pFEAList = 0;
  898.             }
  899.         }
  900. #endif /* CK_LABELED */
  901.     }
  902.     iflen = -1L;                        /* Invalidate file length */
  903.     if (x == EOF) {                     /* if we got a close error */
  904.         debug(F101,"zclose fclose fails","",x);
  905.         return(-1);
  906.     } else if (x2 < 0) {                /* or error flushing last buffer */
  907.         debug(F101,"zclose error flushing last buffer","",x2);
  908.         return(-1);                     /* then return an error */
  909.     } else {
  910.         /* Print log record compatible with wu-ftpd */
  911.         if (xferlog && (n == ZIFILE || n == ZOFILE)) {
  912.             char * s, *p;
  913.             extern char ttname[];
  914.             if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */
  915.             debug(F101,"zclose iklogopen","",iklogopen);
  916.             if (iklogopen) {
  917.                 int len;
  918.                 timenow = time(NULL);
  919. #ifdef CK_LOGIN
  920.                 if (logged_in)
  921.                   s = clienthost;
  922.                 else
  923. #endif /* CK_LOGIN */
  924.                   s = (char *)ttname;
  925.                 if (!s) s = "";
  926.                 if (!*s) s = "*";
  927. #ifdef CK_LOGIN
  928.                 if (logged_in) {
  929.                     p = guestpass;
  930.                     if (!*p) p = "*";
  931.                 } else
  932. #endif /* CK_LOGIN */
  933.                   p = whoami();
  934.  
  935.                 len = 24 + 12 + strlen(s) + 16
  936.                     + strlen(fullname) + 1 + 1 + 1 + 1
  937.                     + strlen(p) + 6 + 2 + 12;
  938.                 if ( len > sizeof(iksdmsg) )
  939.                     sprintf(iksdmsg, /* SAFE */
  940.                             "%.24s [BUFFER WOULD OVERFLOW]\n",
  941.                              ctime(&timenow));
  942.                 else
  943.                     sprintf(iksdmsg, /* SAFE */
  944.                         "%.24s %d %s %ld %s %c %s %c %c %s %s %d %s\n",
  945.                         ctime(&timenow),        /* date/time */
  946.                         gtimer(),               /* elapsed secs */
  947.                         s,                      /* peer name */
  948.                         ffc,                    /* byte count */
  949.                         fullname,               /* full pathname of file */
  950.                         (binary ? 'b' : 'a'),   /* binary or ascii */
  951.                         "_",                    /* options = none */
  952.                         n == ZIFILE ? 'o' : 'i', /* in/out */
  953. #ifdef CK_LOGIN
  954.                         (isguest ? 'a' : 'r'),  /* User type */
  955. #else
  956.                         'r',
  957. #endif /* CK_LOGIN */
  958.                         p,                      /* Username or guest passwd */
  959. #ifdef CK_LOGIN
  960.                         logged_in ? "iks" : "kermit", /* Record ID */
  961. #else
  962.                         "kermit",
  963. #endif /* CK_LOGIN */
  964.                         0,              /* User ID on client system unknown */
  965.                         "*"             /* Ditto */
  966.                         );
  967.                 debug(F110,"zclose iksdmsg",iksdmsg,0);
  968.                 write(xferlog, iksdmsg, (int)strlen(iksdmsg));
  969.             }
  970.         }
  971.         debug(F101,"zclose returns","",1);
  972.         return(1);
  973.     }
  974. }
  975.  
  976. /*  Z C H I N  --  Get a character from the input file.  */
  977.  
  978. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  979.  
  980. int
  981. zchin(n,c) int n; int *c; {
  982.     int a;
  983. #ifdef IKSD
  984.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  985.         a = coninc(0);
  986.         if (a < 0)
  987.             return(-1);
  988.     } else
  989. #endif /* IKSD */
  990.     /* (PWP) Just in case this gets called when it shouldn't. */
  991.     if (n == ZIFILE) {
  992.         a = zminchar();
  993.         if (a < 0)
  994.             return(-1);
  995.     } else {
  996.         a = getc(fp[n]);
  997.         if (a == EOF)
  998.             return(-1);
  999.     }
  1000. #ifdef CK_CTRLZ
  1001.     /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
  1002.     if (!binary && a == 0x1A && eofmethod == XYEOF_Z) {
  1003.         debug(F100,"zchin found Ctrl-Z","",0);
  1004.         return(-1);
  1005.     }
  1006. #endif /* CK_CTRLZ */
  1007.     *c = (CHAR) a & 0377;
  1008.     return(0);
  1009. }
  1010.  
  1011. /*  Z S I N L  --  Read a line from a file  */
  1012.  
  1013. /*
  1014.   Writes the line into the address provided by the caller.
  1015.   n is the Kermit "channel number".
  1016.   Writing terminates when newline is encountered, newline is not copied.
  1017.   Writing also terminates upon EOF or if length x is exhausted.
  1018.   Returns 0 on success, -1 on EOF or error.
  1019. */
  1020. int
  1021. zsinl(n,s,x) int n, x; char *s; {
  1022.     int a, z = 0;                       /* z is return code. */
  1023.     int count = 0;
  1024.     extern CHAR feol;                   /* Line terminator */
  1025.  
  1026.     if (!s || chkfn(n) < 1)             /* Make sure file is open, etc */
  1027.         return(-1);
  1028.     s[0] = '\0';                        /* Don't return junk */
  1029.  
  1030.     a = -1;                             /* Current character, none yet. */
  1031.     while (x--) {                       /* Up to given length */
  1032.         int old=0;
  1033.         if (feol)                       /* Previous character */
  1034.              old = a;
  1035.  
  1036.         if (zchin(n,&a) < 0) {          /* Read a character from the file */
  1037.             debug(F101,"zsinl zchin fail","",count);
  1038.             if (count == 0)
  1039.                 z = -1;                 /* EOF or other error */
  1040.             break;
  1041.         } else
  1042.             count++;
  1043.  
  1044.         if (feol) {                     /* Single-character line terminator */
  1045.             if (a == feol)
  1046.               break;
  1047.         } else {                        /* CRLF line terminator */
  1048.             if (a == '\015')            /* CR, get next character */
  1049.               continue;
  1050.             if (old == '\015') {        /* Previous character was CR */
  1051.                 if (a == '\012')        /* This one is LF, so we have a line */
  1052.                   break;
  1053.                 else                    /* Not LF, deposit CR */
  1054.                   *s++ = '\015';
  1055.             }
  1056.             if (a == '\012') break;     /* Here break on single LF too */
  1057.         }
  1058.         *s = a;                         /* Deposit character */
  1059.         s++;
  1060.     }
  1061.     *s = '\0';                          /* Terminate the string */
  1062.     return(z);
  1063. }
  1064.  
  1065. /*  Z X I N  --  Read x bytes from a file  */
  1066.  
  1067. /*
  1068.   Reads x bytes (or less) from channel n and writes them
  1069.   to the address provided by the caller.
  1070.   Returns number of bytes read on success, 0 on EOF or error.
  1071. */
  1072. int
  1073. zxin(n,s,x) int n, x; char *s; {
  1074. #ifdef IKSD
  1075.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1076.         int a, i;
  1077.         a = ttchk();
  1078.         for (i = 0 ;i < a && i < x; i++) {
  1079.             s[i] = coninc(0);
  1080.         }
  1081.         return(i);
  1082.     }
  1083. #endif /* IKSD */
  1084.     return(fread(s, sizeof (char), x, fp[n]));
  1085. }
  1086.  
  1087. int
  1088. ttwait(int fd, int secs) {
  1089. #ifdef NT
  1090.     DWORD  bytesAvail = 0;
  1091.     HANDLE hFile = (HANDLE)_get_osfhandle(fd);
  1092.     DWORD  type  = GetFileType(hFile);
  1093.     if (type != FILE_TYPE_PIPE)
  1094.         return(-1);
  1095.  
  1096.     do {
  1097.         if ( PeekNamedPipe(hFile,NULL,0,NULL,&bytesAvail,NULL) ) {
  1098.             if ( bytesAvail > 0 )
  1099.                 return(1);
  1100.             else
  1101.                 if ( secs-- > 0 )
  1102.                     sleep(1);
  1103.         }
  1104.         else {
  1105.             return(-1);
  1106.         }
  1107.     } while ( secs > 0 );
  1108.  
  1109.     return(0);
  1110. #else /* NT */
  1111.     return(-1);
  1112. #endif /* NT */
  1113. }
  1114.  
  1115. /*
  1116.   Z I N F I L L  --  Buffered file input.
  1117.  
  1118.   (re)fill the file input buffer with data.  All file input
  1119.   should go through this routine, usually by calling the zminchar()
  1120.   macro defined in ckcker.h.  Returns:
  1121.  
  1122.   Value 0..255 on success, the character that was read.
  1123.   -1 on end of file.
  1124.   -2 on any kind of error other than end of file.
  1125.   -3 timeout when reading from pipe (Kermit packet mode only).
  1126. */
  1127. int
  1128. zinfill() {
  1129.     int x;
  1130.     extern int kactive;
  1131.  
  1132.     errno = 0;
  1133.  
  1134. #ifdef ZDEBUG
  1135.     printf("ZINFILL fp[%d]=%ld\n",ZIFILE,fp[ZIFILE]);
  1136. #endif /* ZDEBUG */
  1137.  
  1138. #ifdef CK_LABELED
  1139.     debug(F101,"zinfill: binary","",binary);
  1140.     debug(F101,"zinfill: pFEAList","",pFEAList);
  1141.     if ( binary == XYFT_L && pFEAList ) {
  1142.         zinptr = zinbuffer ;
  1143.         do_label_send(os2filename) ;
  1144.         if (feof(fp[ZIFILE]))
  1145.           return(-1);
  1146.         clearerr(fp[ZIFILE]);
  1147.         zincnt += fread(zinptr, sizeof (char), INBUFSIZE - zincnt, fp[ZIFILE]);
  1148.     } else {
  1149. #endif /* CK_LABELED */
  1150.  
  1151. #ifdef IKSD
  1152.         if (inserver && !local && fp[ZIFILE] == stdin) {
  1153.             int a, i;
  1154.             a = ttchk();
  1155.             for (i = 0 ;i < a && i < INBUFSIZE; i++) {
  1156.                 zinbuffer[i] = coninc(0);
  1157.             }
  1158.             zincnt = i;
  1159.             zinptr = zinbuffer;    /* set pointer to beginning, (== &zinbuffer[0]) */
  1160.             if (zincnt == 0) return(-1);
  1161.             zincnt--;                           /* One less char in buffer */
  1162.             return((int)(*zinptr++) & 0377);    /* because we return the first */
  1163.         }
  1164. #endif /* IKSD */
  1165.  
  1166.         if (feof(fp[ZIFILE])) {
  1167.             debug(F100,"ZINFILL feof","",0);
  1168. #ifdef ZDEBUG
  1169.             printf("ZINFILL EOF\n");
  1170. #endif /* ZDEBUG */
  1171.             return(-1);
  1172.         }
  1173.         clearerr(fp[ZIFILE]);
  1174.         if (kactive && ispipe[ZIFILE]) {
  1175.             int secs, z = 0;
  1176.             secs = 1;
  1177.             debug(F101,"zinfill calling ttwait","",secs);
  1178.             if ((z = ttwait(fileno(fp[ZIFILE]),secs)) == 0) {
  1179.                 debug(F101,"zinfill ttwait","",z);
  1180.                 return(-3);
  1181.             }
  1182.         }
  1183.  
  1184.         zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  1185. #ifdef CK_CTRLZ
  1186.         /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
  1187.         if (!binary && eofmethod == XYEOF_Z) {
  1188.             int i;
  1189.             for ( i=0 ; i<zincnt ; i++ ) {
  1190.                 if (zinbuffer[i] == SUB) {
  1191.                     zincnt = i;         /* do not count Ctrl-Z */
  1192.  
  1193.                     if (i == 0) {
  1194.                         debug(F100,"ZINFILL Ctrl-Z first char in read","",0);
  1195.                         return(-1);
  1196.                     }
  1197.                     break;
  1198.                 }
  1199.             }
  1200.         }
  1201. #endif /* CK_CTRLZ */
  1202. #ifdef DEBUG
  1203.         if (deblog)
  1204.             debug(F101,"ZINFILL fread","",zincnt);
  1205. #endif /* DEBUG */
  1206. #ifdef ZDEBUG
  1207.         printf("FREAD=%d\n",zincnt);
  1208. #endif /* ZDEBUG */
  1209. #ifdef OS2
  1210. #ifdef CK_LABELED
  1211.     }
  1212. #endif /* CK_LABELED */
  1213. #endif /* OS2 */
  1214.  
  1215.     if (ferror(fp[ZIFILE])) {
  1216.         debug(F100,"ZINFILL ferror","",0);
  1217.         debug(F100,"ZINFILL errno","",errno);
  1218. #ifdef ZDEBUG
  1219.         printf("ZINFILL errno=%d\n",errno);
  1220. #endif /* ZDEBUG */
  1221.         return(-2);
  1222.     }
  1223.     /* In case feof() didn't work just above -- sometimes it doesn't... */
  1224.     if (zincnt == 0) {
  1225.        if (feof(fp[ZIFILE]) ) {
  1226.            debug(F100,"ZINFILL count 0 EOF return -1","",0);
  1227.            return (-1);
  1228.        } else {
  1229.            debug(F100,"ZINFILL count 0 not EOF return -2","",0);
  1230.            return(-2);
  1231.        }
  1232.     }
  1233.     zinptr = zinbuffer;    /* set pointer to beginning, (== &zinbuffer[0]) */
  1234.     zincnt--;                           /* One less char in buffer */
  1235.     return((int)(*zinptr++) & 0377);    /* because we return the first */
  1236. }
  1237.  
  1238. /*  Z S O U T  --  Write a string out to the given file, buffered.  */
  1239.  
  1240. int
  1241. zsout(n,s) int n; char *s; {
  1242.     int rc = 0;
  1243.     if (chkfn(n) < 1) return(-1);       /* Keep this, prevents memory faults */
  1244.     if (!s) return(0);                  /* Null pointer, do nothing, succeed */
  1245.     if (!*s) return(0);                 /* empty string, ditto */
  1246. #ifdef IKSD
  1247.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1248.         return(ttol(s,strlen(s))<0?-1:0);
  1249.     }
  1250. #endif /* IKSD */
  1251.  
  1252.     if (n == ZCTERM)
  1253.       return(Vscrnprintf("%s",s));
  1254.     if (n == ZSFILE)
  1255.       return(write(fileno(fp[n]),s,(int)strlen(s)));
  1256.     rc = fputs(s,fp[n]) == EOF ? -1 : 0;
  1257. #ifdef COMMENT
  1258.     /* Frank believes this can be commented out safely.
  1259.      * Doing so will prevent the file from being up to date
  1260.      * until the file is closed.  That is probably just fine
  1261.      * since the file is locked anyway while open.  5/11/2004
  1262.      */
  1263.     if (n == ZWFILE)
  1264.       fflush(fp[n]);
  1265. #endif /* COMMENT */
  1266.     return(rc);
  1267. }
  1268.  
  1269. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  1270.  
  1271. int
  1272. zsoutl(n,s) int n; char *s; {
  1273.     if (zsout(n,s) < 0)
  1274.         return(-1);
  1275. #ifdef IKSD
  1276.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1277.         return(ttoc(LF));
  1278.     }
  1279. #endif /* IKSD */
  1280.  
  1281.     if (n == ZCTERM)
  1282.       return(Vscrnprintf("\n"));
  1283.     if (n == ZSFILE)                    /* But session log is unbuffered */
  1284.       return(write(fileno(fp[n]),"\n",1));
  1285.     if (fputs("\n",fp[n]) == EOF)
  1286.         return(-1); /* (===OS2 ? \r\n) */
  1287.     return(0);
  1288. }
  1289.  
  1290. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  1291.  
  1292. int
  1293. zsoutx(n,s,x) int n, x; char *s; {
  1294. #ifdef IKSD
  1295.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1296.         return(ttol(s,x));
  1297.     }
  1298. #endif /* IKSD */
  1299.  
  1300.     if (n == ZCTERM) {
  1301.         int i;
  1302.         for (i = 0; i < x; i++)
  1303.           if (!Vscrnprintf("%c",s[i]))
  1304.             return(-1);
  1305.         return(x);
  1306.     }
  1307.     return(write(fileno(fp[n]),s,x) == x ? x : -1);
  1308. }
  1309.  
  1310. /*  Z C H O U T  --  Add a character to the given file.  */
  1311.  
  1312. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  1313.  
  1314. int
  1315. #ifdef CK_ANSIC
  1316. zchout(register int n, char c)
  1317. #else
  1318. zchout(n,c) register int n; char c;
  1319. #endif /* CK_ANSIC */
  1320. /* zchout() */ {
  1321. #ifdef IKSD
  1322.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1323.         return(ttoc(c));
  1324.     }
  1325. #endif /* IKSD */
  1326.  
  1327.     if ( n==ZCTERM )
  1328.         return(Vscrnprintf("%c",c));
  1329.     if (n == ZSFILE)                    /* Use unbuffered for session log */
  1330.         return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
  1331.                                 /* Buffered for everything else */
  1332.         if (putc(c,fp[n]) == EOF)       /* If true, maybe there was an error */
  1333.         return(ferror(fp[n])?-1:0);     /* Check to make sure */
  1334.         else                                    /* Otherwise... */
  1335.         return(0);                      /* There was no error. */
  1336. }
  1337.  
  1338. /* (PWP) buffered character output routine to speed up file IO */
  1339.  
  1340. int
  1341. zoutdump() {
  1342.     int x;
  1343.     zoutptr = zoutbuffer;               /* Reset buffer pointer in all cases */
  1344. #ifdef DEBUG
  1345.     if (deblog)
  1346.       debug(F101,"zoutdump chars","",zoutcnt);
  1347. #endif /* DEBUG */
  1348.     if (zoutcnt == 0) {                 /* Nothing to output */
  1349.         return(0);
  1350.     } else if (zoutcnt < 0) {           /* Unexpected negative argument */
  1351.         zoutcnt = 0;                    /* Reset output buffer count */
  1352.         return(-1);                     /* and fail. */
  1353.     }
  1354.  
  1355. #ifdef CK_LABELED
  1356.     if (binary == XYFT_L ) {
  1357.         x = do_label_recv() ;
  1358.         if ( x > 0 ) { /* more room in the buffer */
  1359.             debug(F101,"zoutdump do_label_recv unfilled buffer","",zoutcnt);
  1360.             return 0 ;
  1361.         } else if ( x < 0 ) {
  1362.             debug(F101,"zoutdump do_label_recv error","",x);
  1363.             return -1 ;
  1364.         }
  1365.     }
  1366. #endif /* CK_LABELED */
  1367.  
  1368. #ifdef IKSD
  1369.     if (inserver && !local && fp[ZOFILE] == stdout) {
  1370.         x = ttol(zoutbuffer,zoutcnt);
  1371.         zoutcnt = 0;
  1372.         return( x > 0 ? 0 : -1);
  1373.     }
  1374. #endif /* IKSD */
  1375.  
  1376. #ifndef COMMENT
  1377.     /*
  1378.       Frank Prindle suggested that replacing this fwrite() by an fflush()
  1379.       followed by a write() would improve the efficiency, especially when
  1380.       writing to stdout.  Subsequent tests showed a 5-fold improvement.
  1381.  
  1382.       This appears to slow down NT.  So I changed it back.
  1383.     */
  1384.     x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE]);
  1385. #else /* COMMENT */
  1386.     fflush(fp[ZOFILE]);
  1387.     x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)
  1388. #endif /* COMMENT */
  1389.     if (x == zoutcnt) {
  1390. #ifdef DEBUG
  1391.         if (deblog)                     /* Save a function call... */
  1392.           debug(F101,"zoutdump write ok","",zoutcnt);
  1393. #endif /* DEBUG */
  1394.         zoutcnt = 0;                    /* Reset output buffer count */
  1395.         return(0);                      /* write() worked OK */
  1396.     } else {
  1397. #ifdef DEBUG
  1398.         if (deblog) {
  1399.             debug(F101,"zoutdump write error","",errno);
  1400.             debug(F101,"zoutdump write returns","",x);
  1401.         }
  1402. #endif /* DEBUG */
  1403.         zoutcnt = 0;                    /* Reset output buffer count */
  1404.         return(-1);                     /* write() failed */
  1405.     }
  1406. }
  1407.  
  1408. /*  C H K F N  --  Internal function to verify file number is ok  */
  1409.  
  1410. /*
  1411.  Returns:
  1412.   -1: File number n is out of range
  1413.    0: n is in range, but file is not open
  1414.    1: n in range and file is open
  1415. */
  1416. int
  1417. chkfn(n) int n; {
  1418.     if (n != ZDFILE) debug(F101,"chkfn","",n);
  1419.     if (n < 0 || n >= ZNFILS) {
  1420.         if (n != ZDFILE) debug(F101,"chkfn out of range","",n);
  1421.         return(-1);
  1422.     } else {
  1423.         if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]);
  1424.         return((fp[n] == NULL) ? 0 : 1);
  1425.     }
  1426. }
  1427.  
  1428. /*  Z G E T F S -- Return file size regardless of accessibility */
  1429. /*
  1430.   Returns:
  1431.     >= 0 if the file size can be determined
  1432.       -1 if the file size is unknown
  1433.       -2 if the file is a directory
  1434. */
  1435.  
  1436. CK_OFF_T
  1437. zgetfs(name) char *name;
  1438. {
  1439.     struct stat buf;
  1440.     int x;
  1441.  
  1442.     if (!name)
  1443.         return(-1);
  1444.     if (!*name)
  1445.         return(-1);
  1446.  
  1447.     x = os2stat(name,&buf);
  1448.     if (x < 0) {
  1449.         return(-1);                             /* stat failed */
  1450.     }
  1451.     else if (!S_ISREG (buf.st_mode)             /* Must be regular file */
  1452. #ifdef S_ISFIFO
  1453.               && !S_ISFIFO (buf.st_mode)        /* or FIFO */
  1454. #endif /* S_ISFIFO */
  1455.               ) {
  1456.         return(-2);
  1457.     }
  1458.     return(buf.st_size);                        /* return size */
  1459. }
  1460.  
  1461.  
  1462. /*  Z C H K I  --  Check if input file exists and is readable  */
  1463.  
  1464. /*
  1465.   Returns:
  1466.    >= 0 if the file can be read (returns the size).
  1467.      -1 if file doesn't exist or can't be accessed,
  1468.      -2 if file exists but is not readable (e.g. a directory file).
  1469.      -3 if file exists but protected against read access.
  1470.  
  1471.   For Berkeley Unix, a file must be of type "regular" to be readable.
  1472.   Directory files, special files, and symbolic links are not readable.
  1473. */
  1474.  
  1475. CK_OFF_T
  1476. zchki(name) char *name; {
  1477.     struct stat buf;
  1478.     int x, itsadir = 0;
  1479.     extern int zchkid, diractive, matchfifo;
  1480.  
  1481.     if (!name) return(-1);
  1482.  
  1483. #ifdef CKROOT
  1484.     debug(F111,"zchki setroot",ckroot,ckrootset);
  1485.     if (ckrootset)
  1486.         if (!zinroot(name)) {
  1487.             debug(F110,"zchki setroot violation",name,0);
  1488.             return(-1);
  1489.         }
  1490. #endif /* CKROOT */
  1491.  
  1492.     x = os2stat(name,&buf);
  1493.     if (x < 0) {
  1494.         debug(F111,"zchki stat fails",name,errno);
  1495.         return(-1);
  1496.     }
  1497.  
  1498.     if (S_ISDIR (buf.st_mode))
  1499.       itsadir = 1;
  1500.  
  1501.     if (!(itsadir && zchkid)) {         /* Unless this... */
  1502.         if (!S_ISREG (buf.st_mode)      /* Must be regular file */
  1503. #ifdef S_ISFIFO
  1504.             && (!matchfifo || !S_ISFIFO (buf.st_mode))  /* or FIFO */
  1505. #endif /* S_ISFIFO */
  1506.             ) {
  1507.             debug(F111,"zchki not regular file (or fifo)",name,matchfifo);
  1508.             return(-2);
  1509.         }
  1510.     }
  1511.     debug(F111,"zchki stat ok:",name,x);
  1512.  
  1513.     if (diractive) {                    /* If listing don't check access */
  1514.         x = 1;
  1515.     } else {
  1516. #ifdef SW_ACC_ID
  1517.         debug(F100,"zchki swapping ids for access()","",0);
  1518.         priv_on();
  1519. #endif /* SW_ACC_ID */
  1520.         x = access(name,R_OK);
  1521. #ifdef SW_ACC_ID
  1522.         priv_off();
  1523.         debug(F100,"zchki swapped ids restored","",0);
  1524. #endif /* SW_ACC_ID */
  1525.     }
  1526.     if (x < 0) {        /* Is the file accessible? */
  1527.         debug(F111,"zchki access failed:",name,x); /* No */
  1528.         return(-3);
  1529.     } else {
  1530.         iflen = buf.st_size;            /* Yes, remember size */
  1531.         ckstrncpy(nambuf,name,MAXNAMLEN); /* and name globally. */
  1532.         debug(F111,"zchki access ok:",name,iflen);
  1533.         return( (iflen > -1L) ? iflen : 0L );
  1534.     }
  1535. }
  1536.  
  1537. /*  Z C H K O  --  Check if output file can be created  */
  1538.  
  1539. /*
  1540.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  1541. */
  1542. int
  1543. zchko(name) char *name; {
  1544.     int i, x, itsadir=0;
  1545.     char *s;
  1546.     extern int zchkod;                  /* Used by IF WRITEABLE */
  1547.  
  1548.     if (!name) return(-1);              /* Watch out for null pointer. */
  1549.  
  1550. #ifdef CKROOT
  1551.     debug(F111,"zchko setroot",ckroot,ckrootset);
  1552.     if (ckrootset)
  1553.         if (!zinroot(name)) {
  1554.             debug(F110,"zchko setroot violation",name,0);
  1555.             errno = EACCES;
  1556.             return(-1);
  1557.         }
  1558. #endif /* CKROOT */
  1559.  
  1560.     debug(F111,"zchkod",name,zchkod);
  1561.  
  1562.     /*
  1563.     zchkod is a global flag meaning we're checking not to see if the directory
  1564.     file is writeable, but if it's OK to create files IN the directory.
  1565.     */
  1566.     if (!zchkod && isdir(name))         /* Directories are not writeable */
  1567.       return(-1);
  1568.  
  1569.     x = (int)strlen(name);              /* Get length of filename */
  1570.     s = malloc(x+3);                    /* Must copy because we can't */
  1571.     if (!s) {                           /* write into our argument. */
  1572.         fprintf(stderr,"zchko: Malloc error 46\n");
  1573.         return(-1);
  1574.     }
  1575.     ckstrncpy(s,name,x+3);
  1576.  
  1577.     for (i = x; i > 0; i--) {           /* Strip filename from right. */
  1578.         if (ISDIRSEP(s[i-1])) {
  1579.             itsadir = 1;
  1580.             break;
  1581.         }
  1582.     }
  1583.     debug(F101,"zchko i","",i);
  1584.  
  1585. #ifdef COMMENT
  1586. /*
  1587.   The following does not work for "foo/bar" where the foo directory does
  1588.   not exist even though we could create it: access("foo/.") fails, but
  1589.   access("foo") works OK.
  1590. */
  1591. /* So now we use "path/." if path given, or "." if no path given. */
  1592.     s[i++] = '.';                       /* Append "." to path. */
  1593.     s[i] = '\0';
  1594. #else
  1595. /* So NOW we strip path segments from the right as long as they don't */
  1596. /* exist -- we only call access() for path segments that *do* exist.. */
  1597. /* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */
  1598. /* succeeds when I have write access to foo and bar but baz doesn't exit.) */
  1599.  
  1600.     if (itsadir && i > 0) {
  1601.         s[i-1] = '\0';
  1602.         while (s[0] && !isdir(s)) {
  1603.             for (i = (int)strlen(s); i > 0; i--) {
  1604.                 if (ISDIRSEP(s[i-1])) {
  1605.                     s[i-1] = '\0';
  1606.                     break;
  1607.                 }
  1608.             }
  1609.             if (i == 0)
  1610.               s[0] = '\0';
  1611.         }
  1612.     } else {
  1613.         s[i++] = '.';                   /* Append "." to path. */
  1614.         s[i] = '\0';
  1615.     }
  1616. #endif /* COMMENT */
  1617.  
  1618.     if (!s[0])
  1619.         strcpy(s,".");
  1620.  
  1621. #ifdef NT
  1622.     {
  1623.         /* We are only checking directory access at this point. 
  1624.          * The file attribute READ_ONLY is meaningless for directories
  1625.          * in Windows.  So all we can do is see whether we can access
  1626.          * the directory information at all.  We can't use access()
  1627.          * for this because it is broken.
  1628.          */
  1629.         DWORD attr = GetFileAttributes((LPTSTR)s);
  1630.         x = (attr == 0xffffffff) ? -1 : 0;
  1631.     }
  1632. #else /* NT */
  1633.     x = 0;              /* No unwritable directories in OS/2 */
  1634. #endif /* NT */
  1635.  
  1636.     if (x < 0)
  1637.       debug(F111,"zchko access failed:",s,errno);
  1638.     else
  1639.       debug(F111,"zchko access ok:",s,x);
  1640.     free(s);                            /* Free temporary storage */
  1641.     return((x < 0) ? -1 : 0);           /* and return. */
  1642. }
  1643.  
  1644. static char *
  1645. UNCname(char * name) {
  1646.     int i;
  1647.     for ( i=0; name[i] && i <= MAXNAMLEN; i++ )
  1648.         UNCnam[i] = (name[i] == '/' ? '\\' : name[i]);
  1649.     UNCnam[i] = '\0';
  1650.     return(UNCnam);
  1651. }
  1652.  
  1653. /*  Z D E L E T  --  Delete the named file.  */
  1654.  
  1655. int
  1656. zdelet(name) char *name; {
  1657.     int x;
  1658. #ifdef CK_LOGIN
  1659.     if (isguest)
  1660.       return(-1);
  1661. #endif /* CK_LOGIN */
  1662.  
  1663. #ifdef CKROOT
  1664.     debug(F111,"zdelet setroot",ckroot,ckrootset);
  1665.     if (ckrootset)
  1666.         if (!zinroot(name)) {
  1667.             debug(F110,"zdelet setroot violation",name,0);
  1668.             return(-1);
  1669.         }
  1670. #endif /* CKROOT */
  1671.  
  1672.     if ( !strncmp(name,"//",2) || !strncmp(name,"\\\\",2))
  1673.         x =unlink(UNCname(name));
  1674.     else
  1675.         x = unlink(name);
  1676.     debug(F111,"zdelet",name,x);
  1677. #ifdef CKSYSLOG
  1678.     if (ckxsyslog >= SYSLG_FC && ckxlogging) {
  1679.         char buf[1024];
  1680.         fullname[0] = '\0';
  1681.         zfnqfp(name,CKMAXPATH,fullname);
  1682.         debug(F110,"zdelet fullname",fullname,0);
  1683.         if (x < 0) {
  1684.             sprintf(buf, "file[] %s: delete failed", fullname);
  1685.             cksyslog(SYSLG_FC, 0, buf, NULL, NULL);
  1686.         } else {
  1687.             sprintf(buf, "file[] %s: delete ok", fullname);
  1688.             cksyslog(SYSLG_FC, 1, buf, NULL, NULL);
  1689.         }
  1690.     }
  1691. #endif /* CKSYSLOG */
  1692.     return(x);
  1693. }
  1694.  
  1695. void
  1696. ChangeNameForFAT(char *name) {
  1697.     char *src, *dst, *next, *ptr, *dot, *start;
  1698.     static char invalid[] = ":;,=+\"[]<>| \t";
  1699.  
  1700.  
  1701.     /* Skip over the drive letter (if any) */
  1702.     if ( isalpha(name[0]) && (name[1] == ':') )
  1703.         start = name + 2;
  1704.     else
  1705.         start = name;
  1706.  
  1707.     /* Absolute path? */
  1708.     src = dst = start;
  1709.     if ( ISDIRSEP(*src) )
  1710.         src++, dst++;
  1711.  
  1712.     while ( *src )
  1713.     {
  1714.         /* Find the end of the directory or file name */
  1715.         for ( next = src;
  1716.               *next && !(ISDIRSEP(*next));
  1717.               next++ );
  1718.  
  1719.         /* Find the last dot in this name */
  1720.         for ( ptr = src, dot = NULL; ptr < next; ptr++ )
  1721.             if ( *ptr == '.' )
  1722.             {
  1723.                 dot = ptr; /* remember last dot */
  1724.                 *ptr = '_';
  1725.             }
  1726.  
  1727.         /* If no DOT then treat an Underscore as a DOT */
  1728.         if ( dot == NULL )
  1729.             for ( ptr = src; ptr < next; ptr++ )
  1730.                 if ( *ptr == '_' )
  1731.                     dot = ptr; /* remember last _ as if it were a dot */
  1732.  
  1733.         /* Does the name meet 8.3 format? */
  1734.         if ( dot && (dot > src) &&
  1735.              ((next - dot <= 4) ||
  1736.                ((next - src > 8) && (dot - src > 3))) )
  1737.         {
  1738.             if ( dot )
  1739.                 *dot = '.';
  1740.  
  1741.             for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ )
  1742.                 *dst++ = *ptr;
  1743.  
  1744.             for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ )
  1745.                 *dst++ = *ptr;
  1746.         }
  1747.         else
  1748.         {
  1749.             if ( dot && (next - src == 1) )
  1750.                 *dot = '.';           /* special case: "." as a path component */
  1751.  
  1752.             for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ )
  1753.                 *dst++ = *ptr;
  1754.         }
  1755.  
  1756.         *dst++ = *next; /* either '/' or 0 */
  1757.  
  1758.         if ( *next )
  1759.         {
  1760.             src = next + 1;
  1761.  
  1762.             if ( *src == 0 ) /* handle trailing '/' on dirs ! */
  1763.                 *dst = 0;
  1764.         }
  1765.         else
  1766.             break;
  1767.     }
  1768.  
  1769.     /* Finally, convert invalid characters */
  1770.     for ( src = start; *src != 0; ++src )
  1771.         if ( strchr(invalid, *src) != NULL )
  1772.             *src = '_';
  1773. }
  1774.  
  1775.  
  1776. int
  1777. IsFileNameValid(char *name)
  1778. {
  1779.     int rc = FALSE;
  1780.     static char prevpath[CKMAXPATH+4] = { '\0', '\0' };
  1781.     static int prevstat = -1;
  1782.  
  1783. #ifdef NT
  1784.     HANDLE hf ;
  1785.     DWORD lasterror = 0 ;
  1786. #else /* NT */
  1787.     HFILE hf;
  1788.     ULONG uAction;
  1789. #endif /* NT */
  1790.  
  1791.     if ( prevstat > -1 ) {
  1792.         if ( name[0] == prevpath[0] ) {
  1793.             if ( !strcmp(name,prevpath) ) {
  1794.                 debug(F111,"isdir cache hit",name,prevstat);
  1795.                 return(prevstat);
  1796.             }
  1797.         }
  1798.     }
  1799.  
  1800. #ifdef NT
  1801.     /* A difference between Win9x and NT/2000 is that on Win9x a
  1802.        ERROR_FILE_NOT_FOUND when the name is invalid such as a name
  1803.        surrounded by double-quotes when OPEN_EXISTING is used instead
  1804.        of OPEN_ALWAYS.
  1805.     */
  1806.     hf = CreateFile( name,
  1807.                      GENERIC_READ | GENERIC_WRITE,
  1808.                      FILE_SHARE_READ | FILE_SHARE_WRITE, /* Allow Sharing */
  1809.                      NULL, /* No Security Attributes specified */
  1810.                      OPEN_EXISTING,
  1811.                      FILE_ATTRIBUTE_NORMAL,
  1812.                      NULL ) ;
  1813.     lasterror = GetLastError();
  1814.     if ( hf == INVALID_HANDLE_VALUE )
  1815.     {
  1816.         switch ( lasterror ) {
  1817.         case ERROR_INVALID_PARAMETER:
  1818.             debug(F111,"IsFileNameValid() Invalid Handle","Invalid Parameter",lasterror);
  1819.             break;
  1820.         case ERROR_INVALID_NAME:
  1821.             debug(F111,"IsFileNameValid() Invalid Handle","Invalid Name",lasterror);
  1822.             break;
  1823.         case ERROR_FILENAME_EXCED_RANGE:
  1824.             debug(F111,"IsFileNameValid() Invalid Handle","FileName Exceeds Range",lasterror);
  1825.             break;
  1826.         case ERROR_FILE_NOT_FOUND:
  1827.             debug(F111,"IsFileNameValid() Invalid Handle","File Not Found",lasterror);
  1828.             if ( isWin95() ) {
  1829.                 hf = CreateFile( name,
  1830.                                  GENERIC_READ | GENERIC_WRITE,
  1831.                                  FILE_SHARE_READ | FILE_SHARE_WRITE, /* Allow Sharing */
  1832.                                  NULL, /* No Security Attributes specified */
  1833.                                  OPEN_ALWAYS,
  1834.                                  FILE_ATTRIBUTE_NORMAL,
  1835.                                  NULL ) ;
  1836.                 if ( hf != INVALID_HANDLE_VALUE ) {
  1837.                                         CloseHandle(hf);
  1838.                     debug(F111,"IsFileNameValid() Win9x Valid Handle",
  1839.                            "File Created",lasterror);
  1840.                     rc = TRUE;
  1841.                     DeleteFile( name ) ;
  1842.                 }
  1843.                 break;
  1844.             }
  1845.             /* fall through */
  1846.         default:
  1847.             debug(F111,"IsFileNameValid() Invalid Handle","returning TRUE",lasterror);
  1848.             rc = TRUE;
  1849.         }
  1850.     }
  1851.     else
  1852.     {
  1853.         debug(F101,"IsFileNameValid() Valid Handle","",lasterror);
  1854.         CloseHandle( hf ) ;
  1855.         rc = TRUE ;
  1856.     }
  1857. #else /* NT */
  1858.     switch( DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
  1859.                      OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0) )
  1860.     {
  1861.     case ERROR_INVALID_NAME:
  1862.     case ERROR_FILENAME_EXCED_RANGE:
  1863.     case ERROR_INVALID_PARAMETER:
  1864.         break;          /* FALSE */
  1865.     case NO_ERROR:
  1866.         DosClose(hf);
  1867.     default:
  1868.         rc = TRUE;
  1869.     }
  1870. #endif /* NT */
  1871.     ckstrncpy(prevpath,name,CKMAXPATH+4);
  1872.     prevstat = rc;
  1873.     return rc;
  1874. }
  1875.  
  1876. unsigned long
  1877. zdskspace(int drive) {
  1878. #ifdef NT
  1879.     DWORD spc, bps, fc, c ;
  1880.     char rootpath[4] ;
  1881.     int gle;
  1882.     BOOL (_stdcall *pGetDiskFreeSpaceEx)
  1883.         ( LPCTSTR lpDirectoryName,                 // directory name
  1884.           PULARGE_INTEGER lpFreeBytesAvailable,    // bytes available to caller
  1885.           PULARGE_INTEGER lpTotalNumberOfBytes,    // bytes on disk
  1886.           PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
  1887.           )=NULL;
  1888.     ULARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
  1889.     (FARPROC) pGetDiskFreeSpaceEx = GetProcAddress( GetModuleHandle("kernel32.dll"),
  1890.                                           "GetDiskFreeSpaceExA");
  1891.  
  1892.     if (drive)
  1893.     {
  1894.         rootpath[0] = '@' + drive ;
  1895.         rootpath[1] = ':' ;
  1896.         rootpath[2] = '\\' ;
  1897.         rootpath[3] = '\0' ;
  1898.  
  1899.         debug(F110,"zdskspace() rootpath",rootpath,0);
  1900.  
  1901.         if (pGetDiskFreeSpaceEx)
  1902.         {
  1903.             debug(F110,"zdskspace()","pGetDiskFreeSpaceEx",0);
  1904.  
  1905.             if ( !pGetDiskFreeSpaceEx (rootpath,
  1906.                                         (PULARGE_INTEGER)&i64FreeBytesToCaller,
  1907.                                         (PULARGE_INTEGER)&i64TotalBytes,
  1908.                                         (PULARGE_INTEGER)&i64FreeBytes)) {
  1909.                 gle = GetLastError();
  1910.                 debug(F111,"zdskspace() failure","lastError",gle);
  1911.                 return (1) ;
  1912.             }
  1913.             return(i64FreeBytesToCaller.HighPart ? (unsigned long)-1 :
  1914.                     i64FreeBytesToCaller.LowPart);
  1915.         } else {
  1916.             debug(F110,"zdskspace()","GetDiskFreeSpace",0);
  1917.             if ( !GetDiskFreeSpace( rootpath, &spc, &bps, &fc, &c )) {
  1918.                 gle = GetLastError();
  1919.                 debug(F111,"zdskspace() failure","lastError",gle);
  1920.                 return (1) ;
  1921.             }
  1922.             return spc * bps * fc ;
  1923.         }
  1924.     }
  1925.     else {
  1926.         debug(F110,"zdskspace()","no drive specified",0);
  1927.  
  1928.         if (pGetDiskFreeSpaceEx)
  1929.         {
  1930.             debug(F110,"zdskspace()","pGetDiskFreeSpaceEx",0);
  1931.             if ( !pGetDiskFreeSpaceEx (NULL,
  1932.                                         (PULARGE_INTEGER)&i64FreeBytesToCaller,
  1933.                                         (PULARGE_INTEGER)&i64TotalBytes,
  1934.                                         (PULARGE_INTEGER)&i64FreeBytes)) {
  1935.                 gle = GetLastError();
  1936.                 debug(F111,"zdskspace() failure","lastError",gle);
  1937.                 return (1) ;
  1938.             }
  1939.             return(i64FreeBytesToCaller.HighPart  ? (unsigned long)-1 :
  1940.                     i64FreeBytesToCaller.LowPart);
  1941.         } else {
  1942.             debug(F110,"zdskspace()","GetDiskFreeSpace",0);
  1943.             if ( !GetDiskFreeSpace( NULL, &spc, &bps, &fc, &c ))
  1944.                 gle = GetLastError();
  1945.                 debug(F111,"zdskspace() failure","lastError",gle);
  1946.                 return (1) ;
  1947.         }
  1948.         return spc * bps * fc ;
  1949.     }
  1950. #else /* NT */
  1951.     FSALLOCATE fsa;
  1952.     if ( DosQueryFSInfo(drive, 1, (PBYTE) &fsa, sizeof(fsa)) )
  1953.         return 0;
  1954.     return fsa.cUnitAvail * fsa.cSectorUnit * fsa.cbSector;
  1955. #endif /* NT */
  1956. }
  1957.  
  1958. char *
  1959. GetLoadPath(void) {
  1960. #ifdef NT
  1961.    static char filename[512] ;
  1962.    filename[0] = '\0' ;
  1963.    GetModuleFileName( NULL, filename, 512 ) ;
  1964.    debug(F111,"GetLoadPath",filename,strlen(filename));
  1965.    return filename;
  1966. #else /* NT */
  1967.    PTIB pptib;
  1968.    PPIB pppib;
  1969.    char *szPath;
  1970.  
  1971.    DosGetInfoBlocks(&pptib, &pppib);
  1972.  
  1973.    szPath = pppib -> pib_pchenv;
  1974.  
  1975.    while (*szPath)
  1976.       szPath = strchr(szPath, 0) + 1;
  1977.  
  1978.    return szPath + 1;
  1979. #endif /* NT */
  1980. }
  1981.  
  1982.  
  1983. /*  Z R T O L  --  Convert remote filename into local form  */
  1984.  
  1985. VOID
  1986. zrtol(name,name2) char *name, *name2; {
  1987.     nzrtol(name,name2,1,0,CKMAXPATH);
  1988. }
  1989.  
  1990. VOID
  1991. nzrtol(name,name2,fncnv,fnrpath,max)
  1992.     char *name, *name2; int fncnv, fnrpath, max;
  1993. { /* nzrtol */
  1994.     char *p; int flag = 0, n = 0;
  1995.     char tmpbuf[CKMAXPATH+1], *tmp;
  1996.     int devnull = 0;
  1997.     int acase = 0;
  1998.     if (!name2) return;
  1999.     if (!name) name = "";
  2000.     debug(F110,"zrtol original name",name,0);
  2001.  
  2002.     /* Handle the path -- we don't have to convert its format, since */
  2003.     /* the standard path format and our internal format are the same. */
  2004.  
  2005.     tmpbuf[0] = NUL;
  2006.     tmp = tmpbuf;
  2007.     devnull = !strcmp(name,"/dev/null");
  2008.  
  2009.     if (!devnull && fnrpath == PATH_OFF) {/* RECEIVE PATHNAMES OFF */
  2010.         zstrip(name,&p);
  2011.         ckstrncpy(tmpbuf,p,CKMAXPATH);
  2012.     } else if (!devnull &&
  2013.                 fnrpath == PATH_ABS) {  /* RECEIVE PATHNAMES ABSOLUTE */
  2014.         ckstrncpy(tmpbuf,name,CKMAXPATH);
  2015.     } else if (!devnull &&
  2016.                 isabsolute(name)) {     /* RECEIVE PATHNAMES RELATIVE */
  2017.         sprintf(tmpbuf,".%s",name);
  2018.     } else {                            /* Ditto */
  2019.         ckstrncpy(tmpbuf,name,CKMAXPATH);
  2020.     }
  2021.     tmpbuf[CKMAXPATH] = NUL;
  2022.     debug(F110,"zrtol tmpbuf",tmpbuf,0);
  2023.  
  2024.     /* Even if we are not converting need to make sure that  */
  2025.     /* the directory separator is '/' and that a few special */
  2026.     /* characters are not used.                              */
  2027.  
  2028.     p = tmpbuf;
  2029.     while ( *p ) {
  2030.         if ( *p == '\\')
  2031.             *p = '/';
  2032.         p++;
  2033.     }
  2034.  
  2035.     if (!fncnv || devnull) {            /* Not converting */
  2036.         ckstrncpy(name2,tmpbuf,max);    /* We're done. */
  2037.         if (!IsFileNameValid(name2)) {
  2038.             /* Lets first try just altering some illegal characters*/
  2039.             p = name2;
  2040.             while ( *p ) {
  2041.                 switch ( *p ) {
  2042.                 case ':':
  2043.                 case '*':
  2044.                 case '?':
  2045.                 case '|':
  2046.                 case '"':
  2047.                 case '<':
  2048.                 case '>':
  2049.                     *p = '_';
  2050.                     break;
  2051.                 }
  2052.                 p++;
  2053.             }
  2054.             if (!IsFileNameValid(name2))
  2055.                 ChangeNameForFAT(name2);
  2056.         }
  2057.         debug(F110,"zrtol non-converted name",name2,0);
  2058.         return;
  2059.     }
  2060.     name = tmpbuf;                      /* Converting */
  2061.  
  2062.     p = name2;
  2063.     for (; *name != '\0' && n < maxnam; name++) {
  2064.         if (*name > SP) flag = 1;       /* Strip leading blanks and controls */
  2065.         if (flag == 0 && *name < '!')
  2066.           continue;
  2067.         if (fncnv > 0) {
  2068.             if (isupper(*name))             /* Check for mixed case */
  2069.                 acase |= 1;
  2070.             else if (islower(*name))
  2071.                 acase |= 2;
  2072.         }
  2073.         switch ( *name ) {
  2074.         case ':':                       /* Convert illegal chars */
  2075.         case '*':
  2076.         case '?':
  2077.         case '|':
  2078.         case '"':
  2079.         case '<':
  2080.         case '>':
  2081.         case ' ':                       /* And Space */
  2082.                 break;
  2083.             *p = '_';                   /* To underscore */
  2084.             break;
  2085.         default:
  2086.             *p = *name;
  2087.         }
  2088.         p++;
  2089.         n++;
  2090.     }
  2091.     *p-- = '\0';                        /* Terminate */
  2092.     while (*p < '!' && p > name2)       /* Strip trailing blanks & controls */
  2093.       *p-- = '\0';
  2094.  
  2095.     if (*name2 == '\0') {               /* Nothing left? */
  2096.         strcpy(name2,"NONAME");         /* do this... */
  2097.     } else if (acase == 1) {            /* All uppercase? */
  2098.         p = name2;                      /* So convert all letters to lower */
  2099.         while (*p) {
  2100.             if (isupper(*p))
  2101.               *p = tolower(*p);
  2102.             p++;
  2103.         }
  2104.     }
  2105.     if (!IsFileNameValid(name2))
  2106.       ChangeNameForFAT(name2);
  2107.     debug(F110,"zrtol new name",name2,0);
  2108. }
  2109.  
  2110. /*  Z S T R I P  --  Strip device & directory name from file specification */
  2111.  
  2112. /*  Strip pathname from filename "name", return pointer to result in name2 */
  2113.  
  2114. #ifdef pdp11
  2115. #define ZSTRPLEN 64
  2116. #else
  2117. #define ZSTRPLEN MAXPATH
  2118. #endif /* pdp11 */
  2119. static char work[ZSTRPLEN+1];
  2120.  
  2121. VOID
  2122. zstrip(name,name2) char *name, **name2; {
  2123.     char *cp, *pp;
  2124.     int n = 0;
  2125.     debug(F110,"zstrip before",name,0);
  2126.     if (!name) { *name2 = ""; return; }
  2127.     pp = work;
  2128.     /* Strip disk letter and colon */
  2129.     if (isalpha(*name) && (*(name+1) == ':')) name += 2;
  2130.     debug(F110,"zstrip after disk-stripping",name,0);
  2131.  
  2132.     for (cp = name; *cp; cp++) {
  2133.         if (ISDIRSEP(*cp)) {
  2134.             pp = work;
  2135.             n = 0;
  2136.         } else {
  2137.             *pp++ = *cp;
  2138.             if (n++ >= ZSTRPLEN)
  2139.               break;
  2140.         }
  2141.     }
  2142.     *pp = '\0';                         /* Terminate the string */
  2143.     *name2 = work;
  2144.     debug(F110,"zstrip after",*name2,0);
  2145. }
  2146.  
  2147. /*  Z L T O R  --  Local TO Remote */
  2148.  
  2149. VOID
  2150. zltor(name,name2) char *name, *name2; {
  2151.     nzltor(name,name2,1,0,CKMAXPATH);
  2152. }
  2153.  
  2154. /*  N Z L T O R  --  New Local TO Remote */
  2155.  
  2156. /* fncnv = 0 for no conversion, > 0 for regular conversion, < 0 for minimal */
  2157.  
  2158. VOID
  2159. nzltor(name,name2,fncnv,fnspath,max)
  2160.     char *name, *name2; int fncnv, fnspath, max;
  2161. { /* nzltor */
  2162.     char *cp=NULL, *pp=NULL;
  2163.     int n = 0;
  2164.     char *dotp = NULL;
  2165.     char tmpbuf[CKMAXPATH+1];
  2166.     char *p=NULL;
  2167.  
  2168.     CHAR c;
  2169.  
  2170. #ifndef NOCSETS
  2171.     extern int fcharset, /* tcharset, */ language;
  2172.     int langsv;
  2173.     _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
  2174. #ifdef CK_ANSIC
  2175.     extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
  2176. #else
  2177.     extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
  2178. #endif /* CK_ANSIC */
  2179.     langsv = language;
  2180.     language = L_USASCII;
  2181. #ifdef COMMENT
  2182.     /* Proper translation of filenames must be done elsewhere */
  2183.     n = tcharset ? tcharset : TC_USASCII;
  2184.     sxo = xls[n][fcharset];
  2185. #else
  2186.     sxo = xls[TC_USASCII][fcharset];
  2187. #endif /* COMMENT */
  2188. #endif /* NOCSETS */
  2189.  
  2190.     debug(F110,"nzltor",name,0);
  2191.  
  2192.     /* Handle pathname */
  2193.  
  2194.     tmpbuf[0] = NUL;
  2195.     if (fnspath == PATH_OFF) {          /* PATHNAMES OFF */
  2196.         zstrip(name,&p);
  2197.         ckstrncpy(tmpbuf,p,CKMAXPATH);
  2198.         tmpbuf[CKMAXPATH] = NUL;
  2199.     } else {
  2200.         int x = 0;
  2201.         if ( name[0] == '.' && ISDIRSEP(name[1]) )
  2202.             x = 2;
  2203.         else if ( name[0] == '.' && name[1] == '.' && ISDIRSEP(name[2]) )
  2204.             x = 3;
  2205.         if ( fnspath == PATH_ABS ) {    /* ABSOLUTE */
  2206.             zfnqfp(name+x,CKMAXPATH,tmpbuf);
  2207.         } else {                        /* RELATIVE */
  2208.             ckstrncpy(tmpbuf,name+x,CKMAXPATH);
  2209.         }
  2210.     }
  2211.     debug(F110,"nzltor tmpbuf",tmpbuf,0);
  2212.  
  2213.     if (!fncnv) {                       /* Not converting */
  2214.         if (isalpha(*tmpbuf) && (*(tmpbuf+1) == ':')) /* Strip disk name */
  2215.             ckstrncpy(name2,&tmpbuf[2],max);    /* We're done. */
  2216.         else
  2217.             ckstrncpy(name2,tmpbuf,max);
  2218. #ifndef NOCSETS
  2219.         langsv = language;
  2220. #endif /* NOCSETS */
  2221.         return;
  2222.     }
  2223.     name = tmpbuf;                      /* Converting */
  2224.     if (isalpha(*name) && (*(name+1) == ':')) /* Strip disk name */
  2225.         name += 2;
  2226.  
  2227.     pp = work;
  2228.     for (cp = name, n=0; *cp && n < max; cp++, n++) {        /* Strip path name */
  2229.         c= *cp;
  2230. #ifndef NOCSETS
  2231.         if (sxo) c = (*sxo)(c);         /* Convert to ASCII */
  2232. #endif /* NOCSETS */
  2233.         if (fncnv > 0 && islower(c))       /* Uppercase letters */
  2234.             *pp++ = toupper(c);               /* Change tilde to 'X' */
  2235.         else if (c == '~')
  2236.             *pp++ = 'X';
  2237.         else if (fncnv > 0 && c == '#')            /* Change number sign to 'X' */
  2238.             *pp++ = 'X';
  2239.         else if (c == '*' || c == '?')
  2240.             *pp++ = 'X';
  2241.         else if (c <= ' ')            /* Change space and controls to 'X' */
  2242.             *pp++ = '_';                /* was 'X' */
  2243.         else if (fncnv > 0 && c == '.') {          /* Change dot to underscore */
  2244.             dotp = pp;                  /* Remember where we last did this */
  2245.             *pp++ = '_';
  2246.         } else
  2247.             *pp++ = c;
  2248.     }
  2249.     *pp = NUL;                          /* Tie it off. */
  2250.     if (dotp) *dotp = '.';              /* Restore last dot (if any) */
  2251.     cp = name2;                         /* If nothing before dot, */
  2252.     if (*work == '.') *cp++ = 'X';      /* insert 'X' */
  2253.     ckstrncpy(cp,work,max);
  2254. #ifndef NOCSETS
  2255.     language = langsv;
  2256. #endif /* NOCSETS */
  2257.     debug(F110,"zltor name2",name2,0);
  2258. }
  2259.  
  2260.  
  2261. /*  Z C H D I R  --  Change directory  */
  2262. /*
  2263.   Call with:
  2264.     dirnam = pointer to name of directory to change to,
  2265.       which may be "" or NULL to indicate user's home directory.
  2266.   Returns:
  2267.     0 on failure
  2268.     1 on success
  2269. */
  2270. int
  2271. zchdir(dirnam) char *dirnam; {
  2272. #ifndef NOSPL
  2273.     extern struct mtab *mactab;             /* Main macro table */
  2274.     extern int nmac;                        /* Number of macros */
  2275. #endif /* NOSPL */
  2276.     char hd[CKMAXPATH+1];
  2277.     char *p;
  2278.     int len;
  2279.  
  2280.     debug(F110,"zchdir",dirnam,0);
  2281.     if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
  2282.       dirnam = zhome();                 /* use user's home directory. */
  2283.     debug(F110,"zchdir 2",dirnam,0);
  2284.  
  2285.     ckstrncpy(hd,dirnam,CKMAXPATH+1);
  2286.     debug(F110,"zchdir 3",hd,0);
  2287.  
  2288. #ifdef CKROOT
  2289.     debug(F111,"zchdir setroot",ckroot,ckrootset);
  2290.     if (ckrootset)
  2291.         if (!zinroot(hd)) {
  2292.             debug(F110,"zchdir setroot violation",hd,0);
  2293.             return(0);
  2294.         }
  2295. #endif /* CKROOT */
  2296.  
  2297.     if (isalpha(hd[0]) && hd[1] == ':') {
  2298.         if (zchdsk(hd[0]))
  2299.           return(0);
  2300.         if (hd[2] == 0)
  2301.           return(1);                    /* Handle drive-only case */
  2302.     }
  2303.  
  2304.  
  2305.     len = strlen(hd) ;
  2306.     if ( !strncmp(hd,"//",2) || !strncmp(hd,"\\\\",2)) {
  2307.         int i;
  2308.         if ( ISDIRSEP(hd[len-1]) ) {
  2309.             /* We now need to strip the trailing directory separator if it is not */
  2310.             /* part of the machine or object name.                                */
  2311.             for ( i=2 ; i<len && !(ISDIRSEP(hd[i])) ; i++ ); /* machine */
  2312.             for ( i++ ; i<len && !(ISDIRSEP(hd[i])) ; i++ ); /* object */
  2313.             if (i < len-1 )
  2314.                 hd[len-1] = '\0';
  2315.         }
  2316.     } else {
  2317.         /* strip trailing DIRSEP except after d:; chdir() doesn't like it */
  2318.         if ( len > 1 && ISDIRSEP(hd[len - 1]) && hd[len - 2] != ':')
  2319.             hd[len - 1] = 0;
  2320.     }
  2321.  
  2322.     if (chdir(hd) == 0) {
  2323. #ifdef IKSDB
  2324.         extern int ikdbopen;
  2325.         if (inserver && ikdbopen) {
  2326. #ifdef CKROOT
  2327.             slotdir(isguest ? anonroot : "", zgtdir());
  2328. #else
  2329.             slotdir("", zgtdir());
  2330. #endif /* CKROOT */
  2331.         }
  2332. #endif /* IKSDB */
  2333.  
  2334. #ifndef NOSPL
  2335.         if (nmac) {             /* Any macros defined? */
  2336.             int k;                /* Yes */
  2337.             static on_cd = 0;
  2338.             if ( !on_cd ) {
  2339.                 on_cd = 1;
  2340.                 k = mlook(mactab,"on_cd",nmac); /* Look this up */
  2341.                 if (k >= 0) {                   /* If found, */
  2342.                     if (dodo(k,zgtdir(),0) > -1)  /* set it up, */
  2343.                         parser(1);                  /* and execute it */
  2344.                 }
  2345.                 on_cd = 0;
  2346.             }
  2347.         }
  2348. #endif /* NOSPL */
  2349.         return(1);              /* Try to cd */
  2350.     } else
  2351.         return(0);
  2352. }
  2353.  
  2354. /*  Z H O M E  --  Return pointer to user's home directory  */
  2355.  
  2356. static char homedir[CKMAXPATH+1]="";
  2357.  
  2358. char *
  2359. zhome() {
  2360.     extern char startupdir[];
  2361.     int i;
  2362.     char * home;
  2363.  
  2364. #ifdef CKROOT
  2365.     if (ckrootset)
  2366.       return((char *)ckroot);
  2367. #endif /* CKROOT */
  2368.  
  2369.     if (homedir[0])
  2370.         return(homedir);
  2371.  
  2372.     home = getenv("HOME");
  2373.     if (home) {
  2374.         ckstrncpy(homedir,home,CKMAXPATH);
  2375.     } else {
  2376. #ifdef NT
  2377.         char * homedrive = (char *)GetHomeDrive();
  2378.         char * homepath  = (char *)GetHomePath();
  2379.         char * profile   = getenv("USERPROFILE");
  2380.         char * personal  = (char *)GetPersonal();
  2381.         if (homedrive && homepath)
  2382.             sprintf(homedir,"%s%s",homedrive,homepath);
  2383.         else if ( profile )
  2384.             sprintf(homedir,"%s",profile);
  2385.         else if ( personal )
  2386.             ckstrncpy(homedir,personal,CKMAXPATH);
  2387.         else
  2388. #endif /* NT */
  2389.             ckstrncpy(homedir,startupdir,CKMAXPATH);
  2390.     }
  2391.  
  2392. #ifdef NT
  2393.     GetShortPathName(homedir,homedir,CKMAXPATH);
  2394. #endif /* NT */
  2395.  
  2396.     /* we know have the directory, but need to make it consistent */
  2397.     /* with all of the other Kermit directory variables: forward  */
  2398.     /* slashes and a trailing slash.                              */
  2399.     i = strlen(homedir)-1;
  2400.     if ( !(ISDIRSEP(homedir[i])) ) {
  2401.         homedir[i+1] = '/';
  2402.         homedir[i+2] = NUL;
  2403.     }
  2404.     for (i-- ; i >= 0 ; i--) {
  2405.         if ( homedir[i] == '\\' )
  2406.           homedir[i] = '/';
  2407.     }
  2408.  
  2409.     debug(F110,"zhome sets homedir to",homedir,0);
  2410.     return(homedir);
  2411. }
  2412.  
  2413. /*  Z G T D I R  --  Return pointer to user's current directory  */
  2414.  
  2415. #define CWDBL MAXPATH
  2416. static char cwdbuf[CWDBL+1];
  2417.  
  2418. char *
  2419. zgtdir() {
  2420.     char *buf;
  2421.     int x=0,len=0;
  2422.  
  2423. #ifndef __IBMC__ /* which has a macro for this */
  2424.     extern char *getcwd();
  2425. #endif /* __IBMC__ */
  2426.     buf = cwdbuf;
  2427.     debug(F101,"zgtdir CWDBL","",CWDBL);
  2428.     getcwd(buf,CWDBL);
  2429.     len = strlen(buf);
  2430.     for ( x=len-1;x >= 0; x-- )
  2431.         if ( buf[x] == '\\' )
  2432.             buf[x] = '/';
  2433.     if ( buf[len-1] != '/' ) {
  2434.         buf[len] = '/';
  2435.         buf[len+1] = NUL;
  2436.     }
  2437.     debug(F110,"zgtdir getcwd()",buf,0);
  2438.     return(buf);
  2439. }
  2440.  
  2441. /*  Z X C M D -- Run a system command so its output can be read like a file */
  2442.  
  2443. int
  2444. zxcmd(filnum,comand) int filnum; char *comand; {
  2445.     int out, rc;
  2446.     int pipes[2];
  2447.  
  2448.     debug(F111,"zxcmd",comand,filnum);
  2449.     if (chkfn(filnum) < 0) return(-1);  /* Need a valid Kermit file number. */
  2450.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  2451.       return(0);
  2452.  
  2453.     /* popen() invalidates the StdHandle temporarily, don't do screen updates */
  2454.     /* while it starts the child process                                      */
  2455.     rc = RequestScreenMutex( 5000 );
  2456.     if ( rc )
  2457.     {
  2458.         debug(F100,"zxcmd() unable to retrieve Screen Mutex","",0);
  2459.         return -1;
  2460.     }
  2461.  
  2462.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  2463.     debug(F101,"zxcmd out",comand,out);
  2464.  
  2465.     if (!out) {                         /* Input from a command */
  2466.         if (priv_chk() ||
  2467.              ((fp[filnum] = popen(comand,"rb")) == NULL)
  2468.              ) {
  2469.             ReleaseScreenMutex();
  2470.             return(0);
  2471.         }
  2472.         zincnt = 0;                     /* (PWP) reset input buffer */
  2473.         zinptr = zinbuffer;
  2474.     } else { /* Output to a command */
  2475.         if (priv_chk() ||
  2476.              ((fp[filnum] = popen(comand,"wb")) == NULL)
  2477.              ) {
  2478.             ReleaseScreenMutex();
  2479.             return(0);
  2480.         }
  2481.         zoutcnt = 0;                    /* (PWP) reset input buffer */
  2482.         zoutptr = zoutbuffer;
  2483.     }
  2484.     ReleaseScreenMutex();
  2485.     fp[ZSYSFN] = fp[filnum];            /* remember the pipe handle */
  2486.     ispipe[filnum] = 1;
  2487.     return(1);
  2488. } /* zxcmd */
  2489.  
  2490. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  2491.  
  2492. /*  Used internally by zclose - returns -1 on failure, 1 on success. */
  2493.  
  2494. int
  2495. zclosf(filnum) int filnum; {
  2496.     int wstat, out;
  2497.     debug(F101,"zclosf filnum","",filnum);
  2498.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  2499.     debug(F101,"zclosf out","",out);
  2500.  
  2501. #ifndef NOPOPEN
  2502.     if (ispipe[filnum]) {
  2503.         int x;
  2504.         x = pclose(fp[filnum]);
  2505.         pexitstat = x;                  /* *** CHECK THIS *** */
  2506.         fp[filnum] = NULL;
  2507.         ispipe[filnum] = 0;
  2508.         return((x != 0) ? -1 : 1);
  2509.     }
  2510. #endif /* NOPOPEN */
  2511.     debug(F101,"zclosf fp[filnum]","", fp[filnum]);
  2512.     debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
  2513.  
  2514.     fclose(fp[filnum]);
  2515.     fp[filnum] = NULL;
  2516.     ispipe[filnum] = 0;
  2517.     debug(F101,"zclosf fp[filnum]","",fp[filnum]);
  2518. #ifdef CK_CHILD
  2519.     return(pexitstat == 0 ? 1 : 0);
  2520. #else
  2521.     return(1);
  2522. #endif /* CK_CHILD */
  2523. }
  2524.  
  2525. #ifdef NT
  2526. static HANDLE hKernel = INVALID_HANDLE_VALUE;
  2527. static DWORD (WINAPI *p_GetLongPathNameA)(
  2528.     LPCSTR lpFileName,
  2529.     LPSTR lpBuffer,
  2530.     DWORD cchBuffer
  2531.     ) = NULL;
  2532.  
  2533. DWORD 
  2534. ckGetLongPathName(LPCSTR lpFileName, LPSTR lpBuffer, DWORD cchBuffer)
  2535. {
  2536.     if ( !p_GetLongPathNameA ) {
  2537.         if (hKernel == INVALID_HANDLE_VALUE)
  2538.             hKernel = LoadLibrary("kernel32.dll");
  2539.         if (hKernel != INVALID_HANDLE_VALUE)
  2540.             (FARPROC) p_GetLongPathNameA =
  2541.                 GetProcAddress( hKernel, "GetLongPathNameA" );
  2542.     }
  2543.  
  2544.     if ( !p_GetLongPathNameA ) {
  2545.         DWORD len, i;
  2546.         if ( !lpFileName || !lpBuffer )
  2547.             return(0);
  2548.  
  2549.         len = strlen(lpFileName);
  2550.         if ( len + 1 <= cchBuffer )
  2551.             ckstrncpy(lpBuffer,lpFileName,cchBuffer);
  2552.         return (len);
  2553.     } else {
  2554.         return(p_GetLongPathNameA(lpFileName,lpBuffer,cchBuffer));
  2555.     }
  2556. }
  2557. #endif /* NT */
  2558.  
  2559. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  2560. /*
  2561.   Returns the number of files that match fn1, with data structures set up
  2562.   so that first file (if any) will be returned by the next znext() call.
  2563.  
  2564.   Depends on external variable wildxpand: 0 means we expand wildcards
  2565.   internally, nonzero means we call the shell to do it.
  2566.   OS2 ignores wildxpand since it always expands the list internally.
  2567. */
  2568.  
  2569. int win95_8_3 = 0;              /* Do not use 8.3 FAT file name notation */
  2570.  
  2571. static char findpath[2][MAXPATH+4];
  2572. static char findpathrel[2][MAXPATH+4];
  2573. static char findfspec[2][MAXPATH];
  2574. static char findfspec2[2][MAXPATH];
  2575. static int findpathwild[2];
  2576. #define MAX_FIND_LEVEL 63
  2577. /* findlevel indicates how deeply nested we are in the directory tree */
  2578. /* it is used as an index into the other structures.                  */
  2579. static int  findlevel[2] = {-1,-1};
  2580.  
  2581. /* findeop - (end of path) is a pointer to the end of the path at the */
  2582. /* current depth in the tree.  It is used as a method for quickly     */
  2583. /* restoring the previous level when setting up the next query.       */
  2584. static char * findeop[2][MAX_FIND_LEVEL+1] = {{
  2585.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2586.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2587.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2588.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2589.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2590.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2591.     NULL,NULL,NULL,NULL
  2592. },{
  2593.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2594.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2595.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2596.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2597.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2598.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  2599.     NULL,NULL,NULL,NULL
  2600. }};
  2601.  
  2602. #ifdef NT
  2603. /* finddata - the directory entry from the most recent query */
  2604. static WIN32_FIND_DATA finddata[2];
  2605.  
  2606. /* findhandle - a stack of handles for each of the outstanding queries */
  2607. static HANDLE findhandle[2][MAX_FIND_LEVEL+1] = {{
  2608.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2609.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2610.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2611.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2612.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2613.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2614.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2615.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2616.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2617.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2618.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2619.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2620.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2621.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2622.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2623.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2624.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2625.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2626.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2627.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2628.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2629.     INVALID_HANDLE_VALUE
  2630. },{
  2631.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2632.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2633.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2634.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2635.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2636.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2637.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2638.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2639.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2640.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2641.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2642.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2643.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2644.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2645.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2646.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2647.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2648.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2649.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2650.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2651.     INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,INVALID_HANDLE_VALUE,
  2652.     INVALID_HANDLE_VALUE
  2653. }};
  2654. #else /* NT */
  2655. /* finddata - the directory entry from the most recent query */
  2656. static FILEFINDBUF3    finddata[2];
  2657.  
  2658. /* findhandle - a stack of handles for each of the outstanding queries */
  2659. static HDIR            findhandle[2][MAX_FIND_LEVEL+1] = {{
  2660.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2661.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2662.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2663.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2664.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2665.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2666.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2667.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2668.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2669.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2670.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE
  2671. },{
  2672.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2673.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2674.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2675.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2676.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2677.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2678.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2679.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2680.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2681.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,
  2682.     HDIR_CREATE,HDIR_CREATE,HDIR_CREATE,HDIR_CREATE
  2683. }};
  2684. static ULONG           findcount=0;
  2685. #endif /* NT */
  2686. static int os2dironly[2]={0,0};         /* only report directories?   */
  2687. static int os2fileonly[2]={0,0};        /* only report files?         */
  2688. static int os2recursive[2]={0,0};       /* recursively traverse tree? */
  2689. static char localfn[2][MAXPATH+4];
  2690. static char rewindfn[2][MAXPATH+4];
  2691. static char rewindpath[2][MAXPATH+4];
  2692. static char rewindpathrel[2][MAXPATH+4];
  2693. static char rewindfspec[2][MAXPATH];
  2694. static char stream[2][MAXPATH];
  2695. static int lasterror[2]={0,0};
  2696. int zxpn = 0;                       /* 0 or 1, allows separate searches */
  2697.  
  2698. #ifdef RECURSIVE
  2699. int
  2700. os2findpush(void) {
  2701.     if ( findlevel[zxpn] >= MAX_FIND_LEVEL )
  2702.       return(0);
  2703.     findlevel[zxpn]++;
  2704.     findeop[zxpn][findlevel[zxpn]] = findpath[zxpn] + strlen(findpath[zxpn]);
  2705. #ifdef NT
  2706.     ckstrncat(findpath[zxpn],finddata[zxpn].cFileName,MAXPATH+4);
  2707. #else /* NT */
  2708.     ckstrncat(findpath[zxpn],finddata[zxpn].achName,MAXPATH+4 );
  2709. #endif /* NT */
  2710.     ckstrncat(findpath[zxpn],"/",MAXPATH+4);
  2711.     ckstrncpy(localfn[zxpn],findpath[zxpn],MAXPATH+4);
  2712.     ckstrncat(localfn[zxpn],findpathrel[zxpn],MAXPATH+4);
  2713.     ckstrncat(localfn[zxpn],findfspec[zxpn],MAXPATH+4);
  2714.     debug(F111,"os2findpush",findpath[zxpn],findlevel[zxpn]);
  2715.     return(1);
  2716. }
  2717.  
  2718. int
  2719. os2findpop(void) {
  2720.     debug(F111,"os2findpop",findpath[zxpn],findlevel[zxpn]);
  2721.     if ( findlevel[zxpn] <= 0 )
  2722.       return(0);
  2723.     *findeop[zxpn][findlevel[zxpn]] = NUL;
  2724.     findeop[zxpn][findlevel[zxpn]] = NULL;
  2725.     findlevel[zxpn]--;
  2726.     ckstrncpy(localfn[zxpn],findpath[zxpn],MAXPATH+4);
  2727.     ckstrncat(localfn[zxpn],findpathrel[zxpn],MAXPATH+4);
  2728.     ckstrncat(localfn[zxpn],findfspec[zxpn],MAXPATH+4);
  2729.     return(1);
  2730. }
  2731. #endif /* RECURSIVE */
  2732.  
  2733. int
  2734. os2findfirstfile(char * fn) {
  2735. #ifndef NT
  2736.     HDIR hfind = HDIR_CREATE;
  2737. #endif /* NT */
  2738.     debug(F110,"os2findfirstfile searching for",fn,0);
  2739.  
  2740.     if ( findlevel[zxpn] < 0 )
  2741.         findlevel[zxpn] = 0;
  2742. #ifdef NT
  2743.     findhandle[zxpn][findlevel[zxpn]] = FindFirstFile( fn, &finddata[zxpn] );
  2744.     if ( findhandle[zxpn][findlevel[zxpn]] == INVALID_HANDLE_VALUE ) {
  2745.         return(0);
  2746.     }
  2747.     debug(F110,"os2findfirstfile found",finddata[zxpn].cFileName,0);
  2748.     debug(F110,"os2findfirstfile found",
  2749.            finddata[zxpn].cAlternateFileName,0);
  2750.     if ( finddata[zxpn].cAlternateFileName[0] == '\0' )
  2751.         ckstrncpy(finddata[zxpn].cAlternateFileName,finddata[zxpn].cFileName,14);
  2752. #else /* NT */
  2753.     findcount = 1;                      /* one entry at a time */
  2754.     lasterror[zxpn] =
  2755.       DosFindFirst(fn,
  2756.                    &hfind,
  2757.                    (ULONG) FILE_NORMAL | FILE_ARCHIVED | FILE_DIRECTORY |
  2758.                    FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY,
  2759.                    (PVOID) &finddata[zxpn],
  2760.                    (ULONG) sizeof(finddata[0]),
  2761.                    &findcount, FIL_STANDARD);
  2762.     if (lasterror[zxpn] || findcount != 1) {
  2763.         DosFindClose(hfind);
  2764.         return(0);
  2765.     }
  2766.     findhandle[zxpn][findlevel[zxpn]] = hfind;
  2767. #endif /* NT */
  2768.     return(1);
  2769. }
  2770.  
  2771. int
  2772. os2findnextfile(void) {
  2773. #ifdef NT
  2774.     int rc = 0;
  2775.     if ( findlevel[zxpn] < 0 )
  2776.         return 0;
  2777.     if ( findhandle[zxpn][findlevel[zxpn]] == INVALID_HANDLE_VALUE)
  2778.       return 0;
  2779.     rc = FindNextFile( findhandle[zxpn][findlevel[zxpn]], &finddata[zxpn] );
  2780.     debug(F111,"os2findnextfile",finddata[zxpn].cFileName,rc);
  2781.     debug(F111,"os2findnextfile (alternate)",
  2782.            finddata[zxpn].cAlternateFileName,rc);
  2783.     if ( finddata[zxpn].cAlternateFileName[0] == '\0' ) {
  2784.         ckstrncpy(finddata[zxpn].cAlternateFileName,finddata[zxpn].cFileName,14);
  2785.         strupr(finddata[zxpn].cAlternateFileName);
  2786.     }
  2787.     return(rc);
  2788. #else /* NT */
  2789.     HDIR hfind = findhandle[zxpn][findlevel[zxpn]];
  2790.     if (hfind == HDIR_CREATE)
  2791.       return 0;
  2792.     findcount = 1;
  2793.     lasterror[zxpn] =
  2794.       DosFindNext(hfind,
  2795.                   (PVOID) &(finddata[zxpn]),
  2796.                   (ULONG) sizeof(finddata[0]),
  2797.                   &findcount);
  2798.     return(!lasterror[zxpn] && (findcount == 1));
  2799. #endif /* NT */
  2800. }
  2801.  
  2802. int
  2803. os2findclose(void) {
  2804.     debug(F111,"os2findclose","findlevel",findlevel[zxpn]);
  2805.     if ( findlevel[zxpn] < 0)
  2806.         return(0);
  2807. #ifdef NT
  2808.     FindClose(findhandle[zxpn][findlevel[zxpn]]);
  2809.     findhandle[zxpn][findlevel[zxpn]] = INVALID_HANDLE_VALUE;
  2810. #else
  2811.     DosFindClose(findhandle[zxpn][findlevel[zxpn]]);
  2812.     findhandle[zxpn][findlevel[zxpn]] = HDIR_CREATE;
  2813. #endif /* NT */
  2814.     return 1;
  2815. }
  2816.  
  2817. int
  2818. os2findisdir(void) {
  2819. #ifdef NT
  2820.     return (finddata[zxpn].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  2821. #else /* NT */
  2822.     return (finddata[zxpn].attrFile & FILE_DIRECTORY);
  2823. #endif /* NT */
  2824. }
  2825.  
  2826. /* Define DOTDIRS if you want znext() to return the "." and ".." entries */
  2827. /* in the directory pointed to by the relative path of 'fn'.             */
  2828.  
  2829. int
  2830. zxrewind() {
  2831.     int i,j,len;
  2832.     CHAR * FileName=NULL;
  2833.  
  2834.     /* Cancel previous zxpand if necessary */
  2835.     for (; findlevel[zxpn] >= 0; findlevel[zxpn]-- ) {
  2836.         if (findhandle[zxpn][findlevel[zxpn]] !=
  2837. #ifdef NT
  2838.              INVALID_HANDLE_VALUE
  2839. #else /* NT */
  2840.              HDIR_CREATE
  2841. #endif /* NT */
  2842.              )
  2843.         {
  2844.             os2findclose();
  2845.         }
  2846.         findeop[zxpn][findlevel[zxpn]] = NULL;
  2847.     }
  2848.  
  2849.     /* Initialize variables for expannsion */
  2850.     fcount[zxpn] = fcntsav[zxpn];
  2851.     fcountstream[zxpn] = fcntstreamsav[zxpn];
  2852.     strcpy(localfn[zxpn],rewindfn[zxpn]);
  2853.     strcpy(findpath[zxpn],rewindpath[zxpn]);
  2854.     strcpy(findpathrel[zxpn],rewindpathrel[zxpn]);
  2855.     strcpy(findfspec[zxpn],rewindfspec[zxpn]);
  2856.     debug(F111,"zxrewind","fcntsav[zxpn]",fcntsav[zxpn]);
  2857.     findlevel[zxpn] = 0;
  2858.     findeop[zxpn][0] = findpath[zxpn];
  2859.  
  2860.     /* Now that we know how many, reset for the call to znext() */
  2861.     if (!os2findfirstfile(localfn[zxpn])) {
  2862. #ifdef RECURSIVE
  2863.         if (os2recursive[zxpn]) {
  2864.             /* However, we are looking at subdirectories   */
  2865.             /* so we must now switch to the next directory */
  2866.             os2findclose();
  2867.  
  2868.           findfirstsubdir:
  2869.             /* prepare to list all subdirectories */
  2870.             if (findpath[zxpn][0])
  2871.               ckstrncpy(localfn[zxpn],findpath[zxpn],MAXPATH+4);
  2872.             else
  2873.               ckstrncpy(localfn[zxpn],"./",MAXPATH+4);
  2874.             ckstrncat(localfn[zxpn],"*",MAXPATH+4);
  2875.  
  2876.             /* find the first potential directory */
  2877.             if (os2findfirstfile(localfn[zxpn])>0) {
  2878.                 do {
  2879. #ifdef NT
  2880.                     if ( win95_8_3 )
  2881.                         FileName = finddata[zxpn].cAlternateFileName;
  2882.                     else
  2883.                         FileName = finddata[zxpn].cFileName;
  2884. #else /* NT */
  2885.                     FileName = finddata[zxpn].achName;
  2886. #endif /* NT */
  2887.                     if (os2findisdir() && strcmp(".",FileName) &&
  2888.                          strcmp("..",FileName))
  2889.                     {
  2890.                         /* we have a directory that is not . or .. */
  2891.                         if (!os2findpush()) {
  2892.                             fcntsav[zxpn] = fcount[zxpn] = 
  2893.                                 fcountstream[zxpn] =
  2894.                                 fcntstreamsav[zxpn] = -1;
  2895.                             return(fcount[zxpn]+1);
  2896.                         }
  2897.                         if (os2findfirstfile(localfn[zxpn]) > 0) {
  2898.                             debug(F100,"","",0);
  2899.                             goto findfirstdone;
  2900.                         } else {
  2901.                             debug(F100,"","",0);
  2902.                             goto findfirstsubdir;
  2903.                         }
  2904.                     }
  2905.                 } while ( os2findnextfile() );
  2906.             }
  2907.  
  2908.           findfirstdir2:
  2909.             /* There are no more subdirectories of the current dir */
  2910.             os2findclose();
  2911.             if (findlevel[zxpn] > 0) {
  2912.                 os2findpop();
  2913.                 while (os2findnextfile()) {
  2914.                     if (os2findisdir()) {
  2915.                         if (!os2findpush()) {
  2916.                             fcntsav[zxpn] = fcount[zxpn] = 
  2917.                                 fcountstream[zxpn] =
  2918.                                 fcntstreamsav[zxpn] = -1;
  2919.                             return(fcount[zxpn]+1);
  2920.                         }
  2921.                         if (os2findfirstfile(localfn[zxpn])>0) {
  2922.                             debug(F100,"","",0);
  2923.                             goto findfirstdone;
  2924.                         } else {
  2925.                             debug(F100,"","",0);
  2926.                             goto findfirstsubdir;
  2927.                         }
  2928.                     }
  2929.                 }
  2930.                 goto findfirstdir2;
  2931.             }
  2932.           findfirstdone:;
  2933.         }
  2934.         else
  2935. #endif /* RECURSIVE */
  2936.         {
  2937.             fcntsav[zxpn] = fcount[zxpn] = 
  2938.                 fcountstream[zxpn] =
  2939.                     fcntstreamsav[zxpn] = -1;
  2940.             return(0);
  2941.         }
  2942.     }
  2943.     return(fcount[zxpn]);
  2944. }
  2945.  
  2946. /*  N Z X P A N D  --  Expland a file list, with options.  */
  2947. /*
  2948.   Call with:
  2949.    s = pointer to filename or pattern.
  2950.    flags = option bits:
  2951.  
  2952.      flags & ZX_FILONLY   Match regular files
  2953.      flags & ZX_DIRONLY   Match directories
  2954.      flags & ZX_RECURSE   Descend through directory tree
  2955.      flags & ZX_MATCHDOT  Match "dot files"
  2956.      flags & ZX_NOBACKUP  Don't match "backup files"
  2957.  
  2958.    Returns the number of files that match s, with data structures set up
  2959.    so that first file (if any) will be returned by the next znext() call.
  2960. */
  2961. int
  2962. nzxpand(CHAR * fn, int flags) {
  2963.     int i,j,k,len,brace=0,bracket=0;
  2964.     CHAR * FileName=NULL;
  2965.  
  2966.     if (!fn)
  2967.       return(0);
  2968.     if (!(*fn))
  2969.       return(0);
  2970.     if (strlen(fn) > MAXPATH)
  2971.       return(-1);
  2972.  
  2973.     debug(F110,"nzxpand fn",fn,0);
  2974.     debug(F101,"nzxpand flags","",flags);
  2975.  
  2976. #ifdef CKROOT
  2977.     debug(F111,"zxpand setroot",ckroot,ckrootset);
  2978.     if (ckrootset)
  2979.         if (!zinroot(fn)) {
  2980.         debug(F110,"zxpand setroot violation",fn,0);
  2981.         return(0);
  2982.     }
  2983. #endif /* CKROOT */
  2984.  
  2985.     /* Cancel previous zxpand if necessary */
  2986.     for (; findlevel[zxpn] >= 0; findlevel[zxpn]-- ) {
  2987.         if (findhandle[zxpn][findlevel[zxpn]] !=
  2988. #ifdef NT
  2989.              INVALID_HANDLE_VALUE
  2990. #else /* NT */
  2991.              HDIR_CREATE
  2992. #endif /* NT */
  2993.              )
  2994.         {
  2995.             os2findclose();
  2996.         }
  2997.     }
  2998.  
  2999.     /* Initialize variables for expannsion */
  3000.     findlevel[zxpn] = 0;
  3001.     findeop[zxpn][0] = findpath[zxpn];
  3002.     fcntsav[zxpn] = fcount[zxpn] = 
  3003.         fcountstream[zxpn] =
  3004.             fcntstreamsav[zxpn] = 0;
  3005.     findpathwild[zxpn] = 0;
  3006.     findpathrel[zxpn][0] = NUL;
  3007.     stream[zxpn][0] = NUL;
  3008.  
  3009.     /* save values for calls to znext() */
  3010.     os2dironly[zxpn] = (flags & ZX_DIRONLY);
  3011. #ifdef RECURSIVE
  3012.     os2recursive[zxpn] = (flags & ZX_RECURSE);
  3013. #endif /* RECURSIVE */
  3014.     os2fileonly[zxpn] = (flags & ZX_FILONLY);
  3015.  
  3016.     /* findpath is just the directory */
  3017.     ckstrncpy(findpath[zxpn], fn, MAXPATH); /* Leave room to add slash-star */
  3018.  
  3019.     /* localfn is the path and the file specification */
  3020.     ckstrncpy(localfn[zxpn], fn, MAXPATH);
  3021.  
  3022.     /* is fn just a directory? */
  3023.     if (isdir(localfn[zxpn]))
  3024.     {
  3025.         /* if yes, but its really a drive, append "./*" */
  3026.         if (strlen(localfn[zxpn]) == 2 && localfn[zxpn][1] == ':' ) {
  3027.             ckstrncat(localfn[zxpn], "./*",MAXPATH+4);
  3028.         } else {
  3029.             /* append "/*" */
  3030.             ckstrncat(findpath[zxpn], "/",MAXPATH+4);
  3031.             ckstrncat(localfn[zxpn], "/*",MAXPATH+4);
  3032.         }
  3033.         /* to specify that we want to find all files */
  3034.     }
  3035.     else {
  3036.         /* could be a file name?  or a path/filename?  */
  3037.         /* or a path with wildcards?                   */
  3038.         /* we can't handle the wildcards yet.          */
  3039.  
  3040.         /* look for a directory separator or drive indicator */
  3041.         for (i = strlen(findpath[zxpn]); i >= 0; i--) {
  3042.             if (ISDIRSEP(findpath[zxpn][i]) ||
  3043.                  (i == 1 && findpath[zxpn][i] == ':'))
  3044.             {
  3045.                 /* we found a directory separator or drive indicator. */
  3046.                 /* are we at the last character in the string? */
  3047.                 if (!findpath[zxpn][i+1])
  3048.                     ckstrncat(localfn[zxpn], "*",MAXPATH+4); /* yes, we want all files */
  3049.                 else
  3050.                     findpath[zxpn][i+1] = '\0'; /* no, isolate the path */
  3051.                 break;
  3052.             }
  3053.         }
  3054.  
  3055.         /* if we didn't find a path.  assume its just a filename */
  3056.         /* so prepend the current directory to the local filename */
  3057.         if (i < 0 && !ISDIRSEP(localfn[zxpn][0]) && localfn[zxpn][1] != ':') {
  3058.             findpath[zxpn][0] = '\0';
  3059.             ckstrncpy(nambuf, "./",MAXNAMLEN+4);
  3060.             ckstrncat(nambuf, localfn[zxpn],MAXPATH+4);
  3061.             ckstrncpy(localfn[zxpn], nambuf,MAXPATH+4);
  3062.         }
  3063.     }
  3064.  
  3065.     /* Now that we know the path and the filename we need to look for */
  3066.     /* patterns in the file name.                                     */
  3067.     for (i = strlen(localfn[zxpn]); i >= 0; i--) {
  3068.         if (ISDIRSEP(localfn[zxpn][i]) || localfn[zxpn][i] == ':') {
  3069.  
  3070.             /* NTFS supports streams which are indicated by
  3071.              *
  3072.              *    filename:stream
  3073.              */
  3074.  
  3075.             if (i > 1 && localfn[zxpn][i] == ':') {
  3076.                 /* Assume we have a stream only if the ':' is found
  3077.                  * beyond the traditional drive indicator.  We copy
  3078.                  * the ':' because it makes it easier to append later on.
  3079.                  */
  3080.                 ckstrncpy(stream[zxpn],localfn[zxpn]+i,MAXPATH);
  3081.                 localfn[zxpn][i] = NUL;
  3082.                 continue;
  3083.             }
  3084.  
  3085.             /* Save the file specification */
  3086.             ckstrncpy(findfspec[zxpn],localfn[zxpn]+i+1,MAXPATH+4);
  3087.  
  3088.             /* Now create the file specification with {} and [] replaced */
  3089.             /* with * and ? respectively.                                */
  3090.             for ( j=0,k=0,len=strlen(findfspec[zxpn]),brace=0,bracket=0;
  3091.                   j<=len ; j++)
  3092.             {
  3093.                 /* copy everything including the trailing NUL */
  3094.                 switch( findfspec[zxpn][j] ) {
  3095.                 case '{':
  3096.                     if ( !brace && !bracket ) {
  3097.                         findfspec2[zxpn][k++] = '*';
  3098.                     }
  3099.                     brace++;
  3100.                     break;
  3101.                 case '}':
  3102.                     brace--;
  3103.                     break;
  3104.                 case '[':
  3105.                     if ( !bracket && !brace ) {
  3106.                         findfspec2[zxpn][k++] = '?';
  3107.                     }
  3108.                     bracket++;
  3109.                     break;
  3110.                 case ']':
  3111.                     bracket--;
  3112.                     break;
  3113.                 default:
  3114.                     if ( !bracket && !brace ) {
  3115.                         findfspec2[zxpn][k++] = findfspec[zxpn][j];
  3116.                     }
  3117.                 }
  3118.             }
  3119.  
  3120.             /* and then replace the local filename string with the modified */
  3121.             /* pattern if a set of braces or brackets were found. */
  3122.             if ( strcmp(findfspec[zxpn],findfspec2[zxpn]) )
  3123.                 strcpy(localfn[zxpn]+i+1,findfspec2[zxpn]);
  3124.             else
  3125.                 findfspec2[zxpn][0] = '\0';
  3126.             break;
  3127.         }
  3128.     }
  3129.  
  3130.     /* At this point we should have a path in findpath[zxpn] if only "." */
  3131.     /* If not, something has gone wrong above.                           */
  3132.  
  3133.     /* Is there a relative path? */
  3134.     if ( !isdir(findpath[zxpn]) ){ /* The path is not a valid directory */
  3135.         i = strlen(findpath[zxpn]);
  3136.         if (i) {
  3137.             for (i = strlen(findpath[zxpn]) ; i >= 0 ; i--) {
  3138.                 if ( findpath[zxpn][i] == '*' ||
  3139.                      findpath[zxpn][i] == '?')
  3140.                     findpathwild[zxpn] = 1;
  3141.  
  3142.                 if (ISDIRSEP(findpath[zxpn][i])) {
  3143.                     char saved = findpath[zxpn][i];
  3144.                     findpath[zxpn][i] = NUL;
  3145.                     if (isdir(findpath[zxpn])) {
  3146.                         strcpy(findpathrel[zxpn],&findpath[zxpn][i+1]);
  3147.                         break;
  3148.                     } else {
  3149.                         findpath[zxpn][i] = saved;
  3150.                     }
  3151.                 } else if (findpath[zxpn][i] == ':') {
  3152.                     char saved = findpath[zxpn][i+1];
  3153.                     findpath[zxpn][i+1] = NUL;
  3154.                     if (isdir(findpath[zxpn])) {
  3155.                         findpath[zxpn][i+1] = saved;
  3156.                         strcpy(findpathrel[zxpn],&findpath[zxpn][i+1]);
  3157.                         findpath[zxpn][i+1] = NUL;
  3158.                         break;
  3159.                     } else {
  3160.                         findpath[zxpn][i+1] = saved;
  3161.                     }
  3162.                 }
  3163.             }
  3164.             if (i < 0) {
  3165.                 strcpy(findpathrel[zxpn],findpath[zxpn]);
  3166.                 findpath[zxpn][0] = NUL;
  3167.             }
  3168.         }
  3169.     }
  3170.  
  3171.     /* Get the first entry: either file or directory */
  3172.   findfirstfile:
  3173.     debug(F100,"zxpand about to FindFirst","",0);
  3174.     if (os2findfirstfile(localfn[zxpn])) {
  3175.  
  3176. /* Count the entry if it meets the requirements of dironly and fileonly */
  3177.  
  3178. #ifdef NT
  3179.         if ( win95_8_3 )
  3180.             FileName = finddata[zxpn].cAlternateFileName;
  3181.         else
  3182.             FileName = finddata[zxpn].cFileName;
  3183. #else /* NT */
  3184.         FileName = finddata[zxpn].achName;
  3185. #endif /* NT */
  3186.  
  3187.         if ((!(os2dironly[zxpn] || os2fileonly[zxpn]) ||
  3188.              (os2dironly[zxpn] && os2findisdir()) ||
  3189.              (os2fileonly[zxpn] && !os2findisdir())) &&
  3190.             (
  3191. #ifdef DOTDIRS
  3192.               (findlevel[zxpn] == 0) ||
  3193.               !os2recursive[zxpn] ||
  3194. #endif /* DOTDIRS */
  3195.              (strcmp(".",FileName) && strcmp("..",FileName)) ))
  3196.         {
  3197.             if ( !findfspec2[zxpn][0] ||
  3198.                  ckmatch(findfspec[zxpn], FileName, 0, 1) ) 
  3199.             {
  3200.                 fcount[zxpn]++;
  3201. #ifdef STREAMS
  3202.                 if ( stream[zxpn][0] )
  3203.                     fcountstream[zxpn] += StreamCount(findpath[zxpn],findpathrel[zxpn],
  3204.                                                       FileName, stream[zxpn]);
  3205. #endif /* STREAMS */
  3206.             } else
  3207.                 debug(F111,"zxpand rejected",FileName,fcount[zxpn]);
  3208.         }
  3209.         else
  3210.             debug(F111,"zxpand rejected",FileName,fcount[zxpn]);
  3211.  
  3212.         /* Findnextfile: */
  3213.         while (os2findnextfile()) {
  3214. #ifdef NT
  3215.             if ( win95_8_3 )
  3216.                 FileName = finddata[zxpn].cAlternateFileName;
  3217.             else
  3218.                 FileName = finddata[zxpn].cFileName;
  3219. #else /* NT */
  3220.             FileName = finddata[zxpn].achName;
  3221. #endif /* NT */
  3222.  
  3223.             if ((!(os2dironly[zxpn] || os2fileonly[zxpn]) ||
  3224.                  (os2dironly[zxpn] && os2findisdir()) ||
  3225.                  (os2fileonly[zxpn] && !os2findisdir())) &&
  3226.                 (
  3227. #ifdef DOTDIRS
  3228.                   (findlevel[zxpn] == 0) ||
  3229.                   !os2recursive[zxpn] ||
  3230. #endif /* DOTDIRS */
  3231.                  (strcmp(".",FileName) && strcmp("..",FileName)) ))
  3232.             {
  3233.                 if ( !findfspec2[zxpn][0] ||
  3234.                      ckmatch(findfspec[zxpn],FileName,0, 1) )
  3235.                 {
  3236.                     fcount[zxpn]++;
  3237. #ifdef STREAMS
  3238.                     if ( stream[zxpn][0] )
  3239.                         fcountstream[zxpn] += StreamCount(findpath[zxpn],findpathrel[zxpn],
  3240.                                                       FileName, stream[zxpn]);
  3241. #endif /* STREAMS */
  3242.                 } else
  3243.                     debug(F111,"zxpand rejected",FileName,fcount[zxpn]);
  3244.             }
  3245.             else
  3246.                 debug(F111,"zxpand rejected",FileName,fcount[zxpn]);
  3247.         }
  3248.     }
  3249. #ifdef RECURSIVE
  3250.     if (os2recursive[zxpn]) {
  3251. /*
  3252.   Done expanding the files for the current directory,
  3253.   now look for subdirectories.
  3254.  */
  3255.         os2findclose();
  3256.         if (findpath[zxpn][0])
  3257.           ckstrncpy(localfn[zxpn],findpath[zxpn],MAXPATH+4);
  3258.         else
  3259.           ckstrncpy(localfn[zxpn],"./",MAXPATH+4);
  3260.         ckstrncat(localfn[zxpn],"*",MAXPATH+4);
  3261.  
  3262.         if (os2findfirstfile(localfn[zxpn])) {
  3263.         do {
  3264. #ifdef NT
  3265.             if ( win95_8_3 )
  3266.                 FileName = finddata[zxpn].cAlternateFileName;
  3267.             else
  3268.                 FileName = finddata[zxpn].cFileName;
  3269. #else /* NT */
  3270.             FileName = finddata[zxpn].achName;
  3271. #endif /* NT */
  3272.             if (os2findisdir() && strcmp(".",FileName) && strcmp("..",FileName))
  3273.             {
  3274.                 if (!os2findpush()) {
  3275.                     fcntsav[zxpn] = fcount[zxpn] = 
  3276.                         fcountstream[zxpn] =
  3277.                             fcntstreamsav[zxpn] = 0;
  3278.                     return(fcount[zxpn]);
  3279.                 } else {
  3280.                     debug(F100,"","",0);
  3281.                     goto findfirstfile;
  3282.                 }
  3283.             }
  3284.         } while (os2findnextfile());
  3285.                 }
  3286.  
  3287.       findnextdir:
  3288.         if (findlevel[zxpn] > 0) {
  3289.             os2findclose();
  3290.             os2findpop();
  3291.             while (os2findnextfile()) {
  3292.                 if (os2findisdir()) {
  3293.                     if (!os2findpush()) {
  3294.                         fcntsav[zxpn] = fcount[zxpn] = 
  3295.                             fcountstream[zxpn] =
  3296.                                 fcntstreamsav[zxpn] = 0;
  3297.                         return(fcount[zxpn]);
  3298.                     } else {
  3299.                         debug(F100,"","",0);
  3300.                         goto findfirstfile;
  3301.                     }
  3302.                 }
  3303.             }
  3304.             goto findnextdir;
  3305.         }
  3306.     }
  3307. #endif /* RECURSIVE */
  3308.  
  3309. #ifdef NT
  3310.     lasterror[zxpn] = GetLastError();
  3311. #endif /* NT */
  3312.     os2findclose();
  3313.  
  3314.     if (lasterror[zxpn] != ERROR_NO_MORE_FILES) {
  3315.         fcntsav[zxpn] = fcount[zxpn] = 
  3316.             fcountstream[zxpn] =
  3317.                 fcntstreamsav[zxpn] = 0;
  3318.         return(fcount[zxpn]);
  3319.     }
  3320.     debug(F111,"zxpand","fcount[zxpn]",fcount[zxpn]);
  3321.     fcntsav[zxpn] = fcount[zxpn];
  3322.     fcntstreamsav[zxpn] = fcountstream[zxpn];
  3323.     strcpy(rewindfn[zxpn],localfn[zxpn]);
  3324.     strcpy(rewindpath[zxpn],findpath[zxpn]);
  3325.     strcpy(rewindpathrel[zxpn],findpathrel[zxpn]);
  3326.     strcpy(rewindfspec[zxpn],findfspec[zxpn]);
  3327.  
  3328.     /* Before we leave fix findpath[] so that it does not contain    */
  3329.     /* extraneous information such as drive letter or . and .. paths */
  3330.     strcpy(nambuf,findpath[zxpn]);
  3331.     i = 0;
  3332.     len = strlen(nambuf);
  3333.     for ( j=0; i <= len ; i++,j++ ) {
  3334.         while ((i == 0 || nambuf[i-1] == ':' || ISDIRSEP(nambuf[i-1])) &&
  3335.                 nambuf[i] == '.' && ISDIRSEP(nambuf[i+1]))
  3336.             i+=2;
  3337.         findpath[zxpn][j] = nambuf[i];
  3338.     }
  3339.  
  3340.     zxrewind(); /* places its return value into fcount[] */
  3341.     return(fcount[zxpn]>0?fcount[zxpn]:0);
  3342. }
  3343.  
  3344. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  3345. /*
  3346.    Returns > 0 if there's another file, with its name copied into the argument
  3347.    string, or 0 if no more files in list.
  3348. */
  3349. int
  3350. znext(fn) char *fn; {
  3351.     extern int zxpn;
  3352.     char * fn_file = NULL;
  3353.     CHAR * FileName;
  3354.  
  3355.     debug(F111,"znext","fcount[zxpn]",fcount[zxpn]);
  3356.  
  3357.     if ( fn == NULL )
  3358.         return(-1);
  3359.     fn[0] = '\0';               /* initialize the buffer in case of error */
  3360.  
  3361.   findnextfile3:
  3362.     if ( findlevel[zxpn] < 0)
  3363.         return(-1);
  3364.  
  3365.     if (fcount[zxpn]-- > 0
  3366. #ifdef NT
  3367.         && findhandle[zxpn][findlevel[zxpn]] != INVALID_HANDLE_VALUE
  3368. #else
  3369.         && findhandle[zxpn][findlevel[zxpn]] != HDIR_CREATE
  3370. #endif /* NT */
  3371.         ) {
  3372.         fcountstream[zxpn]--;
  3373.  
  3374.       findnextfile2:
  3375.         if ( deblog && fn[0] ) {
  3376.             debug(F111,"znext rejected",fn,fcount[zxpn]);
  3377.         }
  3378.         ckstrncpy(fn,findpath[zxpn],CKMAXPATH);
  3379.  
  3380.         if (os2recursive[zxpn])
  3381.             ckstrncat(fn,findpathrel[zxpn],CKMAXPATH);
  3382.  
  3383. #ifdef NT
  3384.         if ( win95_8_3 )
  3385.             FileName = finddata[zxpn].cAlternateFileName;
  3386.         else
  3387.             FileName = finddata[zxpn].cFileName;
  3388. #else /* NT */
  3389.         FileName = finddata[zxpn].achName;
  3390. #endif /* NT */
  3391.         while (os2dironly[zxpn] && !os2findisdir() ||
  3392.                ((
  3393. #ifdef DOTDIRS
  3394.                  os2recursive[zxpn] &&
  3395.                  (findlevel[zxpn] > 0) &&
  3396. #endif /* DOTDIRS */
  3397.                  os2findisdir() &&
  3398. #ifdef NT
  3399.                  (!strcmp(".",finddata[zxpn].cFileName) ||
  3400.                   !strcmp("..",finddata[zxpn].cFileName))
  3401. #else /* NT */
  3402.                  (!strcmp(".",finddata[zxpn].achName) ||
  3403.                   !strcmp("..",finddata[zxpn].achName))
  3404. #endif /* NT */
  3405.                  )) ||
  3406.                os2fileonly[zxpn] && os2findisdir()
  3407.                ) {
  3408.             /* The current file does not meet the necessary criteria */
  3409.             /* therefore we must look at the next file.              */
  3410. #ifdef NT
  3411.             if ( win95_8_3 )
  3412.                 FileName = finddata[zxpn].cAlternateFileName;
  3413.             else
  3414.                 FileName = finddata[zxpn].cFileName;
  3415. #else /* NT */
  3416.             FileName = finddata[zxpn].achName;
  3417. #endif /* NT */
  3418.             debug(F111,"znext rejected",FileName,fcount[zxpn]);
  3419.  
  3420.             if (!os2findnextfile()) {
  3421.                 /* The next file does not exist */
  3422. #ifdef RECURSIVE
  3423.                 if (os2recursive[zxpn]) {
  3424.                     /* However, we are looking at subdirectories   */
  3425.                     /* so we must now switch to the next directory */
  3426.                     os2findclose();
  3427.  
  3428.                   findnextsubdir:
  3429.                     /* prepare to list all subdirectories */
  3430.                     if (findpath[zxpn][0])
  3431.                       ckstrncpy(localfn[zxpn],findpath[zxpn],MAXPATH+4);
  3432.                     else
  3433.                       ckstrncpy(localfn[zxpn],"./",MAXPATH+4);
  3434.                     ckstrncat(localfn[zxpn],"*",MAXPATH+4);
  3435.  
  3436.                     /* Find the first potential directory */
  3437.                     if (os2findfirstfile(localfn[zxpn]) > 0)
  3438.                     do {
  3439. #ifdef NT
  3440.                         if ( win95_8_3 )
  3441.                             FileName = finddata[zxpn].cAlternateFileName;
  3442.                         else
  3443.                             FileName = finddata[zxpn].cFileName;
  3444. #else /* NT */
  3445.                         FileName = finddata[zxpn].achName;
  3446. #endif /* NT */
  3447.                         if (os2findisdir() &&
  3448.                             strcmp(".",FileName) &&
  3449.                             strcmp("..",FileName)
  3450.                             ) {
  3451.                             /* we have a directory that is not . or .. */
  3452.                             if (!os2findpush()) {
  3453.                                 debug(F111,"znext bad 1",fn,fcount[zxpn]+1);
  3454.                                 fcount[zxpn] = -1;
  3455.                                 fcountstream[zxpn] = -1;
  3456.                                 return(fcount[zxpn]);
  3457.                             }
  3458.                             if (os2findfirstfile(localfn[zxpn])>0) {
  3459.                                 goto findnextfile2;
  3460.                             } else {
  3461.                                 goto findnextsubdir;
  3462.                             }
  3463.                         }
  3464.                     } while ( os2findnextfile() );
  3465.  
  3466.                   findnextdir:
  3467.                     /* There are no more subdirectories of the current dir */
  3468.                     os2findclose();
  3469.                     if (findlevel[zxpn] > 0) {
  3470.                         os2findpop();
  3471.                         while (os2findnextfile()) {
  3472.                             if (os2findisdir()) {
  3473.                                 if (!os2findpush()) {
  3474.                                     debug(F111,"znext bad 2",fn,fcount[zxpn]+1);
  3475.                                     fcount[zxpn] = -1;
  3476.                                     fcountstream[zxpn] = -1;
  3477.                                     return(fcount[zxpn]);
  3478.                                 }
  3479.                                 if (os2findfirstfile(localfn[zxpn])>0) {
  3480.                                     goto findnextfile2;
  3481.                                 } else {
  3482.                                     goto findnextsubdir;
  3483.                                 }
  3484.                             }
  3485.                         }
  3486.                         goto findnextdir;
  3487.                     }
  3488.                 } else
  3489. #endif /* RECURSIVE */
  3490.                 {
  3491.                     fcount[zxpn] = -1;
  3492.                     fcountstream[zxpn] = -1;
  3493.                     debug(F111,"znext bad 3",fn,fcount[zxpn]+1);
  3494.                     return(0);
  3495.                 }
  3496.             }
  3497. #ifdef NT
  3498.             if ( win95_8_3 )
  3499.                 FileName = finddata[zxpn].cAlternateFileName;
  3500.             else
  3501.                 FileName = finddata[zxpn].cFileName;
  3502. #else /* NT */
  3503.             FileName = finddata[zxpn].achName;
  3504. #endif /* NT */
  3505.         }
  3506.  
  3507.         /* Later when we call ckmatch() we need to pass only the filename */
  3508.         /* and not the entire path, so remember where the filename is now */
  3509.         fn_file = fn + strlen(fn);
  3510. #ifdef NT
  3511.         if ( win95_8_3 )
  3512.             FileName = finddata[zxpn].cAlternateFileName;
  3513.         else
  3514.             FileName = finddata[zxpn].cFileName;
  3515. #else /* NT */
  3516.         FileName = finddata[zxpn].achName;
  3517. #endif /* NT */
  3518.         ckstrncat(fn,FileName,CKMAXPATH);
  3519.         if ( stream[0] )
  3520.             ckstrncat(fn,stream[zxpn],CKMAXPATH);
  3521.  
  3522.         if (!os2findnextfile()) {
  3523.             /* The next file does not exist */
  3524. #ifdef RECURSIVE
  3525.             if (os2recursive[zxpn]) {
  3526.                 /* However, we are looking at subdirectories   */
  3527.                 /* so we must now switch to the next directory */
  3528.                 os2findclose();
  3529.  
  3530.               findnextsubdir2:
  3531.                 /* prepare to list all subdirectories */
  3532.                 if (findpath[zxpn][0])
  3533.                   ckstrncpy(localfn[zxpn],findpath[zxpn],MAXPATH+4);
  3534.                 else
  3535.                   ckstrncpy(localfn[zxpn],"./",MAXPATH+4);
  3536.                 ckstrncat(localfn[zxpn],"*",MAXPATH+4);
  3537.  
  3538.                 /* Find the first potential directory */
  3539.                 if (os2findfirstfile(localfn[zxpn])>0)
  3540.                   do {
  3541. #ifdef NT
  3542.                       if ( win95_8_3 )
  3543.                           FileName = finddata[zxpn].cAlternateFileName;
  3544.                       else
  3545.                           FileName = finddata[zxpn].cFileName;
  3546. #else /* NT */
  3547.                       FileName = finddata[zxpn].achName;
  3548. #endif /* NT */
  3549.                       if ( os2findisdir() &&
  3550.                           strcmp(".",FileName) &&
  3551.                           strcmp("..",FileName)
  3552.                           ) {
  3553.                           /* we have a directory that is not . or .. */
  3554.                           if (!os2findpush()) {
  3555.                               debug(F111,"znext bad 4",fn,fcount[zxpn]+1);
  3556.                               fcount[zxpn] = -1;
  3557.                               fcountstream[zxpn] = -1;
  3558.                               return(fcount[zxpn]);
  3559.                           }
  3560.                           if(os2findfirstfile(localfn[zxpn])>0) {
  3561.                               goto findnextdone;
  3562.                           } else {
  3563.                               goto findnextsubdir2;
  3564.                           }
  3565.                       }
  3566.                   } while ( os2findnextfile() );
  3567.  
  3568.               findnextdir2:
  3569.                 /* There are no more subdirectories of the current dir */
  3570.                 os2findclose();
  3571.                 if (findlevel[zxpn] > 0) {
  3572.                     os2findpop();
  3573.                     while (os2findnextfile()) {
  3574.                         if (os2findisdir()) {
  3575.                             if (!os2findpush()) {
  3576.                                 debug(F111,"znext bad 5",fn,fcount[zxpn]+1);
  3577.                                 fcount[zxpn] = -1;
  3578.                                 fcountstream[zxpn] = -1;
  3579.                                 return(fcount[zxpn]);
  3580.                             }
  3581.                             if (os2findfirstfile(localfn[zxpn])>0) {
  3582.                                 goto findnextdone;
  3583.                             } else {
  3584.                                 goto findnextsubdir2;
  3585.                             }
  3586.                         }
  3587.                     }
  3588.                     goto findnextdir2;
  3589.                 }
  3590.               findnextdone:;
  3591.             }
  3592. #endif /* RECURSIVE */
  3593.         }
  3594.     } else {
  3595.         *fn = '\0';
  3596.         fcount[zxpn] = -1;
  3597.         fcountstream[zxpn] = -1;
  3598.     }
  3599.  
  3600.     /* if the current fn is not in the matchlist */
  3601.     /* then try the next file name until we find */
  3602.     /* the next match.                           */
  3603.     if ( *fn && findfspec2[zxpn][0] &&
  3604.          !ckmatch(findfspec[zxpn], fn_file, 0, 1) ) {
  3605. #ifdef NT
  3606.         if ( win95_8_3 )
  3607.             FileName = finddata[zxpn].cAlternateFileName;
  3608.         else
  3609.             FileName = finddata[zxpn].cFileName;
  3610. #else /* NT */
  3611.         FileName = finddata[zxpn].achName;
  3612. #endif /* NT */
  3613.         debug(F111,"znext rejected",FileName,fcount[zxpn]);
  3614.         fcount[zxpn]++;                 /* we didn't really find the file */
  3615. #ifdef STREAMS
  3616.         if ( stream[zxpn][0] )
  3617.             fcountstream[zxpn] += StreamCount(findpath[zxpn],findpathrel[zxpn],
  3618.                                                FileName, stream[zxpn]);
  3619. #endif /* STREAMS */
  3620.         goto findnextfile3;
  3621.     }
  3622.  
  3623. #ifdef NT
  3624.     if ( win95_8_3 ) {
  3625.         char name8_3[CKMAXPATH+1];
  3626.         DWORD len;
  3627.  
  3628.         len = GetShortPathName(fn,name8_3,CKMAXPATH+1);
  3629.         if ( len > 0 && len <= CKMAXPATH )
  3630.             ckstrncpy(fn,name8_3,CKMAXPATH+1);
  3631.     }
  3632. #endif /* NT */
  3633.  
  3634.     debug(F111,"znext",fn,fcount[zxpn]+1);
  3635.     return(fcount[zxpn]);
  3636. }
  3637.  
  3638.  
  3639. /*  Z C H K S P A  --  Check if there is enough space to store the file  */
  3640.  
  3641. /*
  3642.  Call with file specification f, size n in bytes.
  3643.  Returns -1 on error, 0 if not enough space, 1 if enough space.
  3644. */
  3645. int
  3646. zchkspa(char *f, CK_OFF_T n)
  3647. {
  3648. /* OS/2 gives us an easy way to do this. */
  3649.     unsigned long x, filesize = 0L;
  3650.     debug(F111,"zchkspa",f,n);
  3651.     if (isalpha(f[0]) && f[1] == ':') {
  3652.         x = zdskspace(toupper(f[0]) - 'A' + 1);
  3653.         debug(F111,"zchkspa disk","size",x);
  3654.     } else {
  3655.         x = zdskspace(0);
  3656.         debug(F111,"zchkspa no disk","size",x);
  3657.     }
  3658.     if ( x > 0 && x < 1024 )    /* zdskspace() unable to return space */
  3659.         return(1);
  3660.  
  3661.     if (x > n)                  /* plenty of space */
  3662.         return(1);
  3663.  
  3664.     if (fncact == XYFX_U || fncact == XYFX_X) { /* Update or Replace */
  3665.       filesize = zchki(f);
  3666.       return((x+filesize >= n) ? 1 : 0);
  3667.     }
  3668.  
  3669.     return(0);
  3670. }
  3671.  
  3672.  
  3673. /*  Z N E W N  --  Make a new name for the given file  */
  3674.  
  3675. /*
  3676.   Given the name, fn, of a file that already exists, this function builds a
  3677.   new name of the form "<oldname>.~<n>~", where <oldname> is argument name
  3678.   (fn), and <n> is a version number, one higher than any existing version
  3679.   number for that file, up to 9999.  This format is consistent with that used
  3680.   by GNU EMACS.  If the constructed name is too long for the system's maximum,
  3681.   enough characters are truncated from the end of <fn> to allow the version
  3682.   number to fit.  If no free version numbers exist between 1 and 9999, a
  3683.   version number of "xxxx" is used.  Returns a pointer to the new name in
  3684.   argument s.
  3685.  
  3686.   On systems which use 8.3 notation, or when SET MSKERMIT ... 
  3687.   is used we borrow the technique used in MS-DOS Kermit:
  3688.   "The idea is to pad out the main name part (8 chars) with ascii zeros and
  3689.    then change the last chars successively to a 1, 2, etc. until
  3690.    a unique name is found. All registers are preserved"
  3691. */
  3692.  
  3693. VOID
  3694. znewn(fn,s) char *fn, **s; {
  3695. #define ZNEWNBL 255
  3696. #define ZNEWNMD 4
  3697.     static char buf[ZNEWNBL+1];
  3698.     char *bp, *xp, *yp;
  3699.     static char localfn[MAXPATH+1];
  3700.     char *tp=NULL, *zp=NULL, ch, temp[14];
  3701.     int len = 0, d = 0, n, t, i, j, k, power = 1;
  3702.  
  3703.     int max = MAXNAMLEN;                /* Maximum name length */
  3704.  
  3705.     if (max < 14) max = 14;             /* Make it reasonable */
  3706.     if (max > ZNEWNBL) max = ZNEWNBL;
  3707.     bp = buf;                           /* Buffer for building new name */
  3708.     yp = fn;
  3709.     while (*yp) {                       /* Copy old name into buffer */
  3710.         *bp++ = *yp++;
  3711.         if (len++ > ZNEWNBL) break;     /* ...up to buffer length */
  3712.     }
  3713.     *s = NULL;
  3714.     for (i = 1; i < ZNEWNMD + 1; i++) { /* Version numbers up to 10**i - 1 */
  3715.         power *= 10;                    /* Next power of 10 */
  3716.         j = max - len;                  /* Space left for version number */
  3717.         k = 3 + i;                      /* Space needed for it */
  3718.         if (j < k) {                    /* Make room if necessary */
  3719.             len -= (k - j);             /* Adjust length of filename */
  3720.             bp = buf + len;             /* Point to new end */
  3721.         }
  3722.         *bp++ = '*';                    /* Put a star on the end (UNIX) */
  3723.         *bp-- = '\0';                   /* Terminate with null */
  3724.  
  3725.         debug(F110,"znewn: about to expand",buf,0);
  3726.         n = nzxpand(buf,0);             /* Expand the resulting wild name */
  3727.                                         /* n is the number of matches */
  3728.         debug(F101,"znewn matches","",n);
  3729.         while (n-- > 0) {               /* Find any existing name.~n~ files */
  3730.             znext(localfn);
  3731.             xp = localfn;
  3732.             xp += len;                  /* Look for .~<n>~ at the end of it */
  3733.             if (*xp == '.' && *(xp+1) == '~') { /* Has a version number */
  3734.                 t = atoi(xp+2);                 /* Get it */
  3735.                 if (t > d) d = t;       /* Save d = highest version number */
  3736.             }
  3737.         }
  3738.         if (d < power-1) {              /* Less than maximum possible? */
  3739.             debug(F110,"znewn number ok",buf,0);
  3740.             sprintf(bp,".~%d~",d+1);    /* Yes, make "name.~<d+1>~" */
  3741.             *s = buf;                   /* Point to new name */
  3742.             ck_znewn = d+1;             /* Also make it available globally */
  3743.             break;                      /* Done, return it */
  3744.         }
  3745.     }
  3746.     if (*s == NULL) {
  3747.         debug(F110,"znewn: too many names",buf,0);
  3748.         sprintf(bp,".~xxxx~");          /* Too many, use xxxx. */
  3749.         ck_znewn = -1;                  /* Also make it available globally */
  3750.         *s = buf;
  3751.     }
  3752.     {
  3753.         char *p;
  3754.         p = (char *) malloc(ZNEWNBL+1); /* Get fully qualified name */
  3755.         if (p) {
  3756.             if (zfnqfp(buf, ZNEWNBL, p))
  3757.               ckstrncpy(buf,p,ZNEWNBL);
  3758.             free(p);
  3759.         }
  3760.     }
  3761.     if (!mskrename && IsFileNameValid(buf)) {
  3762.         debug(F110,"znewn: os2 filename valid",buf,0);
  3763.         return; /* HPFS */
  3764.     }
  3765.  
  3766.     /* otherwise make FAT 8.3 name */
  3767.     debug(F110,"znewn: os2 filename invalid",buf,0);
  3768.     xp = bp = buf;
  3769.     yp = fn;
  3770.     while (*yp) {                       /* Copy name into buf */
  3771.         ch = *bp++ = *yp++;
  3772.         if (ISDIRSEP(ch) || (ch == ':')) xp=bp;
  3773.     }
  3774.     *bp = '\0';
  3775.  
  3776.     if ( mskrename ) {
  3777.         zp = yp = xp;
  3778.         i = 1;
  3779.         while (*yp && (*yp != '.')) {
  3780.             yp++;
  3781.             if (++i<=8)
  3782.                 zp=yp;
  3783.         }
  3784.         /* zp points to 8th character in name, or yp, whichever occurs first. */
  3785.         strcpy(temp,yp);                    /* Copy extension, if any */
  3786.  
  3787.         /* pad out with zeros and make the initial filename '1'. */
  3788.         while (zp != xp+8) {
  3789.             if ( zp == xp )
  3790.                 *zp++='X';
  3791.             if ( zp < xp+7 ) 
  3792.                 *zp++='0';
  3793.             else 
  3794.                 *zp++='1';
  3795.         }
  3796.         strcpy(zp--,temp);                    /* Get the extension back */
  3797.         
  3798.         while (1) {
  3799.             n = nzxpand(buf,0);                 /* Expand the resulting wild name */
  3800.             debug(F101,"znewn: matches","",n);
  3801.             if (n == 0) {
  3802.                 debug(F110,"znewn: os2 file name is MS-Kermit",buf,0);
  3803.                 return;
  3804.             }
  3805.  
  3806.             for ( zp = xp+7; zp > xp; zp--) {
  3807.                 if (*zp == '9') {
  3808.                     *zp = '0';
  3809.                 } else {
  3810.                     (*zp)++;
  3811.                     break;
  3812.                 }
  3813.             }
  3814.             if ( zp == xp ) {
  3815.                 debug(F110,"znewn: os2 file name is MS-Kermit (overflow)",buf,0);
  3816.                 return;
  3817.             }
  3818.         }
  3819.     } else {
  3820.         zp = yp = xp;
  3821.         i = 1;
  3822.         while (*yp && (*yp != '.')) {
  3823.             yp++;
  3824.             if (++i<=6)
  3825.                 zp=yp;
  3826.         }
  3827.         /* zp points to 6th character in name, or yp, whichever occurs first. */
  3828.         strcpy(temp,yp);                    /* Copy extension, if any */
  3829.  
  3830.         while (zp != xp+8) {
  3831.             if ( zp < xp+5 ) *zp++='0';
  3832.             else *zp++='?';                 /* Pad out with wild cards */
  3833.         }
  3834.         strcpy(zp,temp);                    /* Get the extension back */
  3835.         debug(F110,"znewn: about to expand",buf,0);
  3836.         n = nzxpand(buf,0);                 /* Expand the resulting wild name */
  3837.         debug(F101,"znewn: matches","",n);
  3838.         d = 0;                              /* Index number */
  3839.         debug(F110,"znewn: temp",temp,0);
  3840.         while (znext(temp)) {
  3841.             if ( tp = strrchr( temp, '/' ) )
  3842.                 tp++;
  3843.             else
  3844.                 tp = temp;
  3845.             i = atoi(tp+5);
  3846.             debug(F111,"znewn: tp=atoi(tp+5)",tp,i);
  3847.             if (i > d) d = i;
  3848.             debug(F101,"znewn: d","",d);
  3849.         }
  3850.         sprintf(temp,"%03d",d+1);           /* Get the number into a string */
  3851.         ck_znewn = d+1;
  3852.         memcpy(xp+5, temp, 3);
  3853.         debug(F110,"znewn: os2 file name is FAT",buf,0);
  3854.     }
  3855.     return;
  3856. }
  3857.  
  3858. /*  Z R E N A M E  --  Rename a file  */
  3859. /*
  3860.    Call with old and new names.
  3861.    If new name is the name of a directory, the 'old' file is moved to
  3862.    that directory.
  3863.    Returns 0 on success, -1 on failure.
  3864. */
  3865. int
  3866. zrename(old,new) char *old, *new; {
  3867.     char *p, *s;
  3868.     int x;
  3869.     int len;
  3870.  
  3871.     if (!old) old = "";
  3872.     if (!new) new = "";
  3873.     debug(F110,"zrename old",old,0);
  3874.     debug(F110,"zrename new",new,0);
  3875.     if (!*old) return(-1);
  3876.     if (!*new) return(-1);
  3877.  
  3878. #ifdef IKSD
  3879. #ifdef CK_LOGIN
  3880.     if (inserver && isguest)
  3881.       return(-1);
  3882. #endif /* CK_LOGIN */
  3883. #endif /* IKSD */
  3884.  
  3885. #ifdef CKROOT
  3886.     debug(F111,"zrename setroot",ckroot,ckrootset);
  3887.     if (ckrootset) {
  3888.         if (!zinroot(old)) {
  3889.             debug(F110,"zrename old: setroot violation",old,0);
  3890.             return(-1);
  3891.         }
  3892.         if (!zinroot(new)) {
  3893.             debug(F110,"zrename new: setroot violation",new,0);
  3894.             return(-1);
  3895.         }
  3896.     }
  3897. #endif /* CKROOT */
  3898.  
  3899.     p = NULL;
  3900.  
  3901.     if (isdir(new)) {
  3902.         char *q = NULL;
  3903.  
  3904.         x = strlen(new);
  3905.         len = strlen(new) + strlen(old) + 2;
  3906.         if (!(p = malloc(len)))
  3907.           return(-1);
  3908.         ckstrncpy(p,new,len);                  /* Directory part */
  3909.         if (!ISDIRSEP(*(new+x-1)))      /* Separator, if needed */
  3910.           ckstrncat(p,"/",len);
  3911.         zstrip(old,&q);                 /* Strip path part from old name */
  3912.         ckstrncat(p,q,len);                    /* Concatenate to new directory */
  3913.         debug(F110,"zrename dir",p,0);
  3914.     } else {
  3915. #ifdef DEBUG
  3916.         debug(F110,"zrename no dir",new,0);
  3917. #endif
  3918.         len = strlen(new) + 64;
  3919.         if (!(p = malloc(len)))
  3920.           return(-1);
  3921.         ckstrncpy(p,new,len);
  3922.     }
  3923.     s = p;
  3924.  
  3925. #ifdef IKSD
  3926.         if ( inserver && (!ENABLED(en_del)) ) {
  3927.             if ( zchki(s) > -1 ) {
  3928.                 if (p) free(p);
  3929.                 return(-1);
  3930.             }
  3931.         }
  3932. #endif /* IKSD */
  3933.     if ( !strncmp(s,"//",2) || !strncmp(s,"\\\\",2))
  3934.          ckstrncpy(s,UNCname(s),len);
  3935.     if ( !strncmp(s,"//",2) || !strncmp(s,"\\\\",2) )
  3936.         old = UNCname(old);
  3937. /*
  3938.   Atomic, preferred, uses a single system call, rename(), if available.
  3939.   OS/2 rename() returns nonzero, but not necessarily -1 (?), on failure.
  3940. */
  3941.     x = rename(old,s);
  3942. #ifdef CKSYSLOG
  3943.     if (ckxsyslog >= SYSLG_FC && ckxlogging) {
  3944.         char buf[1024];
  3945.         fullname[0] = '\0';
  3946.         zfnqfp(old,CKMAXPATH,fullname);
  3947.         tmp2[0] = '\0';
  3948.         zfnqfp(s,CKMAXPATH,tmp2);
  3949.         if (x) {
  3950.             sprintf(buf,"file[] %s: rename to %s failed (%m)",fullname,tmp2);
  3951.             cksyslog(SYSLG_FC, 0, buf, NULL, NULL);
  3952.         } else {
  3953.             sprintf(buf,"file[] %s: renamed to %s ok", fullname, tmp2);
  3954.             cksyslog(SYSLG_FC, 1, buf, NULL, NULL);
  3955.         }
  3956.     }
  3957. #endif /* CKSYSLOG */
  3958.  
  3959.     if (p) free(p);
  3960.     return(x ? -1 : 0);
  3961. }
  3962.  
  3963. /*  Z C O P Y  --  Copy a file  */
  3964. /*
  3965.    Call with source and destination names.
  3966.    If destination name is the name of a directory, the source file is
  3967.    copied to that directory with the original name.
  3968.    Returns 0 on success, -1 on failure.
  3969. */
  3970. int
  3971. zcopy(source,destination) char *source, *destination; {
  3972.     char *p = NULL, *s;
  3973.     int x;
  3974.     int len;
  3975. #ifdef NT
  3976.     BOOL bCancel = 0;
  3977.     static BOOL (WINAPI * p_CopyFileExA)(LPCSTR lpExistingFileName,
  3978.                                           LPCSTR lpNewFileName,
  3979.                                           LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  3980.                                           LPVOID lpData OPTIONAL,
  3981.                                           LPBOOL pbCancel OPTIONAL,
  3982.                                           DWORD dwCopyFlags
  3983.                                           )=NULL;
  3984. #endif /* NT */
  3985.  
  3986.     if (!source) source = "";
  3987.     if (!destination) destination = "";
  3988.  
  3989.     debug(F110,"zcopy src arg",source,0);
  3990.     debug(F110,"zcopy dst arg",destination,0);
  3991.  
  3992.     if (!*source) return(-1);
  3993.     if (!*destination) return(-1);
  3994.  
  3995. #ifdef IKSD
  3996. #ifdef CK_LOGIN
  3997.     if (inserver && isguest)
  3998.       return(-4);
  3999. #endif /* CK_LOGIN */
  4000. #endif /* IKSD */
  4001.  
  4002. #ifdef CKROOT
  4003.     debug(F111,"zcopy setroot",ckroot,ckrootset);
  4004.     if (ckrootset) {
  4005.         if (!zinroot(source)) {
  4006.             debug(F110,"zcopy source: setroot violation",source,0);
  4007.             return(-1);
  4008.         }
  4009.         if (!zinroot(destination)) {
  4010.             debug(F110,"zcopy destination: setroot violation",destination,0);
  4011.             return(-1);
  4012.         }
  4013.     }
  4014. #endif /* CKROOT */
  4015.  
  4016.     s = destination;
  4017.  
  4018.     if (isdir(destination)) {
  4019.         char *q = NULL;
  4020.  
  4021.         x = strlen(destination);
  4022.         len = strlen(destination) + strlen(source) + 2;
  4023.         if (!(p = malloc(len)))
  4024.           return(-1);
  4025.         ckstrncpy(p,destination,len);          /* Directory part */
  4026.         if (!ISDIRSEP(*(destination+x-1))) /* Separator, if needed */
  4027.           ckstrncat(p,"/",len);
  4028.         zstrip(source,&q);              /* Strip path part from old name */
  4029.         ckstrncat(p,q,len);                    /* Concatenate to new directory */
  4030.         debug(F110,"zcopy dir",p,0);
  4031.     } else {
  4032.         debug(F110,"zcopy no dir",destination,0);
  4033.         len = strlen(destination) + 64;
  4034.         if (!(p = malloc(len)))
  4035.           return(-1);
  4036.         ckstrncpy(p,destination,len);
  4037.     }
  4038.  
  4039.     s = p;
  4040.  
  4041.     if ( !strncmp(s,"//",2) || !strncmp(s,"\\\\",2) )
  4042.          ckstrncpy(s,UNCname(s),len);
  4043.     if ( !strncmp(s,"//",2) || !strncmp(s,"\\\\",2) )
  4044.         source = UNCname(source);
  4045.  
  4046. #ifdef IKSD
  4047.     if ( inserver && (!ENABLED(en_del)) ) {
  4048.         if ( zchki(s) > -1 ) {
  4049.             if (p) free(p);
  4050.             return(-4);
  4051.         }
  4052.     }
  4053. #endif /* IKSD */
  4054.  
  4055. #ifndef NT
  4056.     x = (DosCopy( source, s, DCPY_FAILEAS ) ? -1 : 0);
  4057. #else /* NT */
  4058.     if ( !p_CopyFileExA ) {
  4059.         if (hKernel == INVALID_HANDLE_VALUE)
  4060.             hKernel = LoadLibrary("kernel32.dll");
  4061.         if (hKernel != INVALID_HANDLE_VALUE)
  4062.             (FARPROC) p_CopyFileExA =
  4063.                 GetProcAddress( hKernel, "CopyFileExA" );
  4064.     }
  4065.  
  4066.     if ( p_CopyFileExA ) {
  4067.         x = (p_CopyFileExA( source, s, NULL, NULL, &bCancel, 0) ? 0 : -1);
  4068.         if (x<0) {
  4069.             DWORD lasterror = GetLastError();
  4070.             debug(F111,"CopyFileEx failed to",s,lasterror);
  4071.             if (lasterror == ERROR_CALL_NOT_IMPLEMENTED)
  4072.                 goto copyfile;
  4073.         }
  4074.     } else {
  4075.       copyfile:
  4076.         x = (CopyFile( source, s, FALSE ) ? 0 : -1);
  4077.         if (x<0)
  4078.             debug(F111,"CopyFile failed to",s,GetLastError());
  4079.     }
  4080. #endif /* NT */
  4081.  
  4082. #ifdef CKSYSLOG
  4083.     if (x > -1 && ckxsyslog >= SYSLG_FC && ckxlogging) {
  4084.         char buf[1024];
  4085.         if (x) {
  4086.             sprintf(buf,"file[] %s: copy to %s failed", fullname, tmp2);
  4087.             cksyslog(SYSLG_FC, 0, buf, NULL, NULL);
  4088.         } else {
  4089.             sprintf(buf,"file[] %s: copy to %s ok", fullname, tmp2);
  4090.             cksyslog(SYSLG_FC, 1, buf, NULL, NULL);
  4091.         }
  4092.     }
  4093. #endif /* CKSYSLOG */
  4094.  
  4095.     if (p) free(p);
  4096.     return(x);
  4097. }
  4098.  
  4099. /*  Z L I N K  --  Link a file  */
  4100. /*
  4101.    Call with source and destination names.
  4102.    If destination name is the name of a directory, the source file is
  4103.    copied to that directory with the original name.
  4104.    Returns 0 on success, -1 on failure.
  4105. */
  4106. int
  4107. zlink(source,destination) char *source, *destination; {
  4108. #ifdef OS2ONLY
  4109.     return -1;
  4110. #else /* OS2ONLY */
  4111.     char *p = NULL, *s;
  4112.     int x;
  4113.     int len;
  4114. #ifdef NT
  4115.     BOOL bCancel = 0;
  4116. #endif /* NT */
  4117.     static BOOL (WINAPI * p_CreateHardLinkA)(LPCSTR lpFileName,
  4118.                                              LPCSTR lpExistingFileName,
  4119.                                              LPSECURITY_ATTRIBUTES lpSecurityAttributes
  4120.                                              )=NULL;
  4121.     static HANDLE hKernel = INVALID_HANDLE_VALUE;
  4122.     
  4123.     if ( !p_CreateHardLinkA ) {
  4124.         if (hKernel == INVALID_HANDLE_VALUE)
  4125.             hKernel = LoadLibrary("kernel32.dll");
  4126.         if (hKernel != INVALID_HANDLE_VALUE)
  4127.             (FARPROC) p_CreateHardLinkA =
  4128.                 GetProcAddress( hKernel, "CreateHardLinkA" );
  4129.     }
  4130.  
  4131.     if ( !p_CreateHardLinkA )
  4132.         return -1;
  4133.  
  4134.     if (!source) source = "";
  4135.     if (!destination) destination = "";
  4136.  
  4137.     debug(F110,"zlink src arg",source,0);
  4138.     debug(F110,"zlink dst arg",destination,0);
  4139.  
  4140.     if (!*source) return(-1);
  4141.     if (!*destination) return(-1);
  4142.  
  4143. #ifdef IKSD
  4144. #ifdef CK_LOGIN
  4145.     if (inserver && isguest)
  4146.       return(-4);
  4147. #endif /* CK_LOGIN */
  4148. #endif /* IKSD */
  4149.  
  4150. #ifdef CKROOT
  4151.     debug(F111,"zlink setroot",ckroot,ckrootset);
  4152.     if (ckrootset) {
  4153.         if (!zinroot(source)) {
  4154.             debug(F110,"zlink source: setroot violation",source,0);
  4155.             return(-1);
  4156.         }
  4157.         if (!zinroot(destination)) {
  4158.             debug(F110,"zlink destination: setroot violation",destination,0);
  4159.             return(-1);
  4160.         }
  4161.     }
  4162. #endif /* CKROOT */
  4163.  
  4164.     s = destination;
  4165.  
  4166.     if (isdir(destination)) {
  4167.         char *q = NULL;
  4168.  
  4169.         x = strlen(destination);
  4170.         len = strlen(destination) + strlen(source) + 2;
  4171.         if (!(p = malloc(len)))
  4172.           return(-1);
  4173.         ckstrncpy(p,destination,len);          /* Directory part */
  4174.         if (!ISDIRSEP(*(destination+x-1)))      /* Separator, if needed */
  4175.           ckstrncat(p,"/",len);
  4176.         zstrip(source,&q);                      /* Strip path part from old name */
  4177.         ckstrncat(p,q,len);                    /* Concatenate to new directory */
  4178.         debug(F110,"zlink dir",p,0);
  4179.     } else {
  4180.         debug(F110,"zlink no dir",destination,0);
  4181.         len = strlen(destination) + 64;
  4182.         if (!(p = malloc(len)))
  4183.           return(-1);
  4184.         ckstrncpy(p,destination,len);
  4185.     }
  4186.  
  4187.     s = p;
  4188.  
  4189.     if ( !strncmp(s,"//",2) || !strncmp(s,"\\\\",2) )
  4190.          ckstrncpy(s,UNCname(s),len);
  4191.     if ( !strncmp(s,"//",2) || !strncmp(s,"\\\\",2) )
  4192.         source = UNCname(source);
  4193.  
  4194. #ifdef IKSD
  4195.     if ( inserver && (!ENABLED(en_del)) ) {
  4196.         if ( zchki(s) > -1 ) {
  4197.             if (p) free(p);
  4198.             return(-4);
  4199.         }
  4200.     }
  4201. #endif /* IKSD */
  4202.  
  4203.     x = (p_CreateHardLinkA(s,source,NULL) ? 0 : -1 );
  4204.  
  4205. #ifdef CKSYSLOG
  4206.     if (x > -1 && ckxsyslog >= SYSLG_FC && ckxlogging) {
  4207.         char buf[1024];
  4208.         if (x) {
  4209.             sprintf(buf,"file[] %s: link to %s failed", fullname, tmp2);
  4210.             cksyslog(SYSLG_FC, 0, buf, NULL, NULL);
  4211.         } else {
  4212.             sprintf(buf,"file[] %s: link to %s ok", fullname, tmp2);
  4213.             cksyslog(SYSLG_FC, 1, buf, NULL, NULL);
  4214.         }
  4215.     }
  4216. #endif /* CKSYSLOG */
  4217.  
  4218.     if (p) free(p);
  4219.     return(x);
  4220. #endif /* OS2ONLY */
  4221. }
  4222.  
  4223. /*  Z S A T T R */
  4224. /*
  4225.  Fills in a Kermit file attribute structure for the file which is to be sent.
  4226.  Returns 0 on success with the structure filled in, or -1 on failure.
  4227.  If any string member is null, then it should be ignored.
  4228.  If any numeric member is -1, then it should be ignored.
  4229. */
  4230. #ifdef CK_PERMS
  4231.  
  4232. #ifdef CK_GPERMS
  4233. #undef CK_GPERMS
  4234. #endif /* CK_GPERMS */
  4235.  
  4236. #ifdef S_IRUSR
  4237. #ifdef S_IWUSR
  4238. #ifdef S_IXUSR
  4239. #define CK_GPERMS
  4240. #endif /* S_IXUSR */
  4241. #endif /* S_IWUSR */
  4242. #endif /* S_IRUSR */
  4243.  
  4244. static char gperms[2];
  4245.  
  4246. #endif /* CK_GPERMS */
  4247.  
  4248. static char lperms[24];
  4249.  
  4250. #ifdef CK_PERMS
  4251. static char xlperms[24];
  4252.  
  4253. char *
  4254. zgperm(f) char *f; {
  4255.     int x; char *s = (char *)xlperms;
  4256.     struct stat buf;
  4257.     debug(F110,"zgperm",f,0);
  4258.     if (!f) return("----------");
  4259.     if (!*f) return("----------");
  4260.  
  4261. #ifdef CKROOT
  4262.     debug(F111,"zgperm setroot",ckroot,ckrootset);
  4263.     if (ckrootset) if (!zinroot(f)) {
  4264.         debug(F110,"zgperm setroot violation",f,0);
  4265.         return("----------");
  4266.     }
  4267. #endif /* CKROOT */
  4268.  
  4269.     x = os2stat(f,&buf);
  4270.     if (x < 0)
  4271.       return(NULL);
  4272.     sprintf(s,"%o",buf.st_mode);
  4273.     debug(F110,"zgperm",s,0);
  4274.     return(s);
  4275. }
  4276. #else
  4277. char *
  4278. zgperm(f) char *f; {
  4279.     return(NULL);
  4280. }
  4281. #endif /* CK_PERMS */
  4282.  
  4283. int
  4284. zsattr(xx) struct zattr *xx; {
  4285.     long k; int x;
  4286.     struct stat buf;
  4287.  
  4288.     k = iflen % 1024L;                  /* File length in K */
  4289.     if (k != 0L) k = 1L;
  4290.     xx->lengthk = (iflen / 1024L) + k;
  4291.     xx->type.len = 0;                   /* File type can't be filled in here */
  4292.     xx->type.val = "";
  4293.     if (*nambuf) {
  4294.         xx->date.val = zfcdat(nambuf);  /* File creation date */
  4295.         xx->date.len = (int)strlen(xx->date.val);
  4296.     } else {
  4297.         xx->date.len = 0;
  4298.         xx->date.val = "";
  4299.     }
  4300.     xx->creator.len = 0;                /* File creator */
  4301.     xx->creator.val = "";
  4302.     xx->account.len = 0;                /* File account */
  4303.     xx->account.val = "";
  4304.     xx->area.len = 0;                   /* File area */
  4305.     xx->area.val = "";
  4306.     xx->password.len = 0;               /* Area password */
  4307.     xx->password.val = "";
  4308.     xx->blksize = -1L;                  /* File blocksize */
  4309.     xx->xaccess.len = 0;                /* File access */
  4310.     xx->xaccess.val = "";
  4311.     xx->encoding.len = 0;               /* Transfer syntax */
  4312.     xx->encoding.val = 0;
  4313.     xx->disp.len = 0;                   /* Disposition upon arrival */
  4314.     xx->disp.val = "";
  4315.     xx->lprotect.len = 0;               /* Local protection */
  4316.     xx->lprotect.val = "";
  4317.     xx->gprotect.len = 0;               /* Generic protection */
  4318.     xx->gprotect.val = "";
  4319.     debug(F111,"zsattr lperms",xx->lprotect.val,xx->lprotect.len);
  4320.     debug(F111,"zsattr gperms",xx->gprotect.val,xx->gprotect.len);
  4321. #ifdef NT
  4322.     xx->systemid.val = "UN";            /* UN = Win32 */
  4323. #else
  4324.     xx->systemid.val = "UO";            /* UO = OS/2 */
  4325. #endif /* NT */
  4326.     xx->systemid.len = 2;               /* System ID */
  4327.     xx->recfm.len = 0;                  /* Record format */
  4328.     xx->recfm.val = "";
  4329.     xx->sysparam.len = 0;               /* System-dependent parameters */
  4330.     xx->sysparam.val = "";
  4331.     xx->length = iflen;                 /* Length */
  4332.     return(0);
  4333. }
  4334.  
  4335. /* Z F C D A T  --  Get file creation date */
  4336. /*
  4337.   Call with pointer to filename.
  4338.   On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
  4339.   On failure, returns pointer to null string.
  4340. */
  4341. static char datbuf[40];
  4342.  
  4343. char *
  4344. #ifdef CK_ANSIC
  4345. zdtstr(time_t time)
  4346. #else
  4347. zdtstr(time) time_t time;
  4348. #endif /* CK_ANSIC */
  4349. /* zdtstr */ {
  4350.     struct tm * time_stamp;
  4351.     struct tm * localtime();
  4352.     int yy, ss;
  4353.     struct tm lts;
  4354.  
  4355.     debug(F101,"zdatstr time","",time);
  4356.     if (time < 0)
  4357.       return("");
  4358.     time_stamp = localtime(&(time));
  4359.     if (!time_stamp) {
  4360.         debug(F100,"localtime returns null","",0);
  4361.         return("");
  4362.     }
  4363.     memcpy(<s,time_stamp,sizeof(struct tm));
  4364.     time_stamp = <s;
  4365.     yy = time_stamp->tm_year;           /* Year - 1900 */
  4366.     yy += 1900;
  4367.     debug(F101,"zdatstr year","",yy);
  4368.  
  4369.     if (time_stamp->tm_mon  < 0 || time_stamp->tm_mon  > 11)
  4370.       return("");
  4371.     if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
  4372.       return("");
  4373.     if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
  4374.       return("");
  4375.     if (time_stamp->tm_min  < 0 || time_stamp->tm_min  > 59)
  4376.       return("");
  4377.     ss = time_stamp->tm_sec;            /* Seconds */
  4378.     if (ss < 0 || ss  > 59)             /* Some systems give a BIG number */
  4379.       ss = 0;
  4380.     sprintf(datbuf,
  4381.             "%04d%02d%02d %02d:%02d:%02d",
  4382.             yy,
  4383.             time_stamp->tm_mon + 1,
  4384.             time_stamp->tm_mday,
  4385.             time_stamp->tm_hour,
  4386.             time_stamp->tm_min
  4387.             , ss
  4388.             );
  4389.     yy = (int)strlen(datbuf);
  4390.     debug(F111,"zdatstr",datbuf,yy);
  4391.     if (yy > 17) datbuf[17] = '\0';
  4392.     return(datbuf);
  4393. }
  4394.  
  4395. char *
  4396. zfcdat(name) char *name; {
  4397.     struct stat buffer;
  4398.  
  4399.     datbuf[0] = '\0';
  4400.  
  4401. #ifdef CKROOT
  4402.     debug(F111,"zfcdat setroot",ckroot,ckrootset);
  4403.     if (ckrootset)
  4404.         if (!zinroot(name)) {
  4405.             debug(F110,"zfcdat setroot violation",name,0);
  4406.             return(0);
  4407.         }
  4408. #endif /* CKROOT */
  4409.  
  4410.     if (os2stat(name,&buffer) != 0) {
  4411.         debug(F110,"zfcdat stat failed",name,0);
  4412.         return("");
  4413.     }
  4414.     return(zdtstr(buffer.st_mtime));
  4415. }
  4416.  
  4417. static char zjdbuf[32] = { NUL, NUL };  /* Julian date buffer */
  4418.  
  4419. time_t
  4420. zstrdt(date,len) char * date; int len; {
  4421. /*
  4422.   To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
  4423.   is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
  4424. */
  4425.     long tmx=0, days;
  4426.     int i, n, isleapyear;
  4427.                    /*       J  F  M  A   M   J   J   A   S   O   N   D   */
  4428.                    /*      31 28 31 30  31  30  31  31  30  31  30  31   */
  4429.     static
  4430.     int monthdays [13] = {  0,0,31,59,90,120,151,181,212,243,273,304,334 };
  4431.     char s[5];
  4432.     struct tm *time_stamp;
  4433.  
  4434. #ifdef NT
  4435. struct _utimbuf tp;
  4436. #else /* NT */
  4437. struct utimbuf tp;
  4438. #endif /* NT */
  4439.  
  4440. #ifdef ANYBSD
  4441.     long timezone = 0L;
  4442.     static struct timeb tbp;
  4443. #endif /* ANYBSD */
  4444.  
  4445.     debug(F111,"zstrdt",date,len);
  4446.  
  4447.     if ((len == 0)
  4448.         || (len != 17)
  4449.         || (date[8] != ' ')
  4450.         || (date[11] != ':')
  4451.         || (date[14] != ':') ) {
  4452.         debug(F111,"Bad creation date ",date,len);
  4453.         return(-1);
  4454.     }
  4455.     debug(F111,"zstrdt date check 1",date,len);
  4456.     for(i = 0; i < 8; i++) {
  4457.         if (!isdigit(date[i])) {
  4458.             debug(F111,"Bad creation date ",date,len);
  4459.             return(-1);
  4460.         }
  4461.     }
  4462.     debug(F111,"zstrdt date check 2",date,len);
  4463.     i++;
  4464.  
  4465.     for (; i < 16; i += 3) {
  4466.         if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
  4467.             debug(F111,"Bad creation date ",date,len);
  4468.             return(-1);
  4469.         }
  4470.     }
  4471.     debug(F111,"zstrdt date check 3",date,len);
  4472.     debug(F100,"zstrdt so far so good","",0);
  4473.  
  4474.     s[4] = '\0';
  4475.     for (i = 0; i < 4; i++)             /* Fix the year */
  4476.       s[i] = date[i];
  4477.  
  4478.     n = atoi(s);
  4479.     debug(F111,"zstrdt year",s,n);
  4480.     if (n < 1970) {
  4481.         debug(F100,"zstrdt fails - year","",n);
  4482.         return(-1);
  4483.     }
  4484.  
  4485. /*  Previous year's leap days.  This won't work after year 2100. */
  4486.  
  4487.     isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
  4488.     days = (long) (n - 1970) * 365;
  4489.     days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
  4490.  
  4491.     s[2] = '\0';
  4492.  
  4493.     for (i = 4; i < 16; i += 2) {
  4494.         s[0] = date[i];
  4495.         s[1] = date[i + 1];
  4496.         n = atoi(s);
  4497.         switch (i) {
  4498.           case 4:                       /* MM: month */
  4499.             if ((n < 1 ) || ( n > 12)) {
  4500.                 debug(F111,"zstrdt 4 bad date ",date,len);
  4501.                 return(-1);
  4502.             }
  4503.             days += monthdays [n];
  4504.             if (isleapyear && n > 2)
  4505.               ++days;
  4506.             continue;
  4507.  
  4508.           case 6:                       /* DD: day */
  4509.             if ((n < 1 ) || ( n > 31)) {
  4510.                 debug(F111,"zstrdt 6 bad date ",date,len);
  4511.                 return(-1);
  4512.             }
  4513.             tmx = (days + n - 1) * 24L * 60L * 60L;
  4514.             i++;                        /* Skip the space */
  4515.             continue;
  4516.  
  4517.           case 9:                       /* hh: hour */
  4518.             if ((n < 0 ) || ( n > 23)) {
  4519.                 debug(F111,"zstrdt 9 bad date ",date,len);
  4520.                 return(-1);
  4521.             }
  4522.             tmx += n * 60L * 60L;
  4523.             i++;                        /* Skip the colon */
  4524.             continue;
  4525.  
  4526.           case 12:                      /* mm: minute */
  4527.             if ((n < 0 ) || ( n > 59)) {
  4528.                 debug(F111,"zstrdt 12 bad date ",date,len);
  4529.                 return(-1);
  4530.             }
  4531.             tmx += timezone;
  4532.             tmx += n * 60L;
  4533.             i++;                        /* Skip the colon */
  4534.             continue;
  4535.  
  4536.           case 15:                      /* ss: second */
  4537.             if ((n < 0 ) || ( n > 59)) {
  4538.                 debug(F111,"zstrdt 15 bad date ",date,len);
  4539.                 return(-1);
  4540.             }
  4541.             tmx += n;
  4542.         }
  4543.         time_stamp = localtime(&tmx);
  4544.         debug(F101,"zstrdt tmx 1","",tmx);
  4545.         if (!time_stamp)
  4546.           return(-1);
  4547.         time_stamp = localtime(&tmx);
  4548.         debug(F101,"zstrdt tmx 2","",tmx);
  4549.         if (time_stamp->tm_isdst)
  4550.           tmx -= 60L * 60L;             /* Adjust for daylight savings time */
  4551.         n = time_stamp->tm_year;
  4552.         if (n < 300) n += 1900;
  4553.         sprintf(zjdbuf,"%04d%03d",n,(time_stamp->tm_yday)+1);
  4554.     }
  4555.     return(tmx);
  4556. }
  4557.  
  4558. #ifdef COMMENT
  4559. char *
  4560. zjdate(date) char * date; {
  4561.     int x;
  4562.     if (!date) date = "";
  4563.     x = strlen(date);
  4564.     if (x < 1) return("0");
  4565.     if (zstrdt(date,x) < 0)
  4566.       return("-1");
  4567.     else
  4568.       return((char *)zjdbuf);
  4569. }
  4570. #endif /* COMMENT */
  4571.  
  4572. #ifdef ZLOCALTIME
  4573. /* Z L O C A L T I M E  --  GMT/UTC time string to local time string */
  4574.  
  4575. /*
  4576.    Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time.
  4577.    Returns:   "yyyymmdd hh:mm:ss" local date-time on success, NULL on failure.
  4578. */
  4579. static char zltimbuf[64];
  4580.  
  4581. char *
  4582. zlocaltime(gmtstring) char * gmtstring; {
  4583.     time_t tmx;
  4584.     long days;
  4585.     int i, n, x, isleapyear;
  4586.                    /*       J  F  M  A   M   J   J   A   S   O   N   D   */
  4587.                    /*      31 28 31 30  31  30  31  31  30  31  30  31   */
  4588.     static
  4589.     int monthdays [13] = {  0,0,31,59,90,120,151,181,212,243,273,304,334 };
  4590.     char s[5];
  4591.     struct tm *time_stamp;
  4592.  
  4593.     char * date = gmtstring;
  4594.     int len;
  4595.  
  4596.     len = strlen(date);
  4597.     debug(F111,"zlocaltime",date,len);
  4598.  
  4599.     if ((len == 0)
  4600.         || (len != 17)
  4601.         || (date[8] != ' ')
  4602.         || (date[11] != ':')
  4603.         || (date[14] != ':') ) {
  4604.         debug(F111,"Bad creation date ",date,len);
  4605.         return(NULL);
  4606.     }
  4607.     debug(F111,"zlocaltime date check 1",date,len);
  4608.     for(i = 0; i < 8; i++) {
  4609.         if (!isdigit(date[i])) {
  4610.             debug(F111,"Bad creation date ",date,len);
  4611.             return(NULL);
  4612.         }
  4613.     }
  4614.     debug(F111,"zlocaltime date check 2",date,len);
  4615.     i++;
  4616.  
  4617.     for (; i < 16; i += 3) {
  4618.         if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
  4619.             debug(F111,"Bad creation date ",date,len);
  4620.             return(NULL);
  4621.         }
  4622.     }
  4623.     debug(F111,"zlocaltime date check 3",date,len);
  4624.  
  4625.     debug(F100,"zlocaltime so far so good","",0);
  4626.  
  4627.     s[4] = '\0';
  4628.     for (i = 0; i < 4; i++)             /* Fix the year */
  4629.       s[i] = date[i];
  4630.  
  4631.     n = atoi(s);
  4632.     debug(F111,"zlocaltime year",s,n);
  4633.     if (n < 1970) {
  4634.         debug(F100,"zlocaltime fails - year","",n);
  4635.         return(NULL);
  4636.     }
  4637.  
  4638. /*  Previous year's leap days.  This won't work after year 2100. */
  4639.  
  4640.     isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
  4641.     days = (long) (n - 1970) * 365;
  4642.     days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
  4643.  
  4644.     s[2] = '\0';
  4645.  
  4646.     for (i = 4; i < 16; i += 2) {
  4647.         s[0] = date[i];
  4648.         s[1] = date[i + 1];
  4649.         n = atoi(s);
  4650.         switch (i) {
  4651.           case 4:                       /* MM: month */
  4652.             if ((n < 1 ) || ( n > 12)) {
  4653.                 debug(F111,"zlocaltime 4 bad date ",date,len);
  4654.                 return(NULL);
  4655.             }
  4656.             days += monthdays [n];
  4657.             if (isleapyear && n > 2)
  4658.               ++days;
  4659.             continue;
  4660.  
  4661.           case 6:                       /* DD: day */
  4662.             if ((n < 1 ) || ( n > 31)) {
  4663.                 debug(F111,"zlocaltime 6 bad date ",date,len);
  4664.                 return(NULL);
  4665.             }
  4666.             tmx = (days + n - 1) * 24L * 60L * 60L;
  4667.             i++;                        /* Skip the space */
  4668.             continue;
  4669.  
  4670.           case 9:                       /* hh: hour */
  4671.             if ((n < 0 ) || ( n > 23)) {
  4672.                 debug(F111,"zlocaltime 9 bad date ",date,len);
  4673.                 return(NULL);
  4674.             }
  4675.             tmx += n * 60L * 60L;
  4676.             i++;                        /* Skip the colon */
  4677.             continue;
  4678.  
  4679.           case 12:                      /* mm: minute */
  4680.             if ((n < 0 ) || ( n > 59)) {
  4681.                 debug(F111,"zlocaltime 12 bad date ",date,len);
  4682.                 return(NULL);
  4683.             }
  4684.             tmx += n * 60L;
  4685.             i++;                        /* Skip the colon */
  4686.             continue;
  4687.  
  4688.           case 15:                      /* ss: second */
  4689.             if ((n < 0 ) || ( n > 59)) {
  4690.                 debug(F111,"zlocaltime 15 bad date ",date,len);
  4691.                 return(NULL);
  4692.             }
  4693.             tmx += n;
  4694.         }
  4695.  
  4696. /*
  4697.   At this point tmx is the time_t representation of the argument date-time
  4698.   string without any timezone or DST adjustments.  Therefore it should be
  4699.   the same as the time_t representation of the GMT/UTC time.  Now we should
  4700.   be able to feed it to localtime() and have it converted to a struct tm
  4701.   representing the local time equivalent of the given UTC time.
  4702. */
  4703.         time_stamp = localtime(&tmx);
  4704.         if (!time_stamp)
  4705.           return(NULL);
  4706.     }
  4707.  
  4708. /* Now we simply reformat the struct tm to a string */
  4709.  
  4710.     x = time_stamp->tm_year;
  4711.     if (time_stamp->tm_year < 70 || time_stamp->tm_year > 8099)
  4712.       return(NULL);
  4713.     if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
  4714.       return(NULL);
  4715.     if (time_stamp->tm_mday < 1 || time_stamp->tm_mday > 31)
  4716.       return(NULL);
  4717.     if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 24)
  4718.       return(NULL);
  4719.     if (time_stamp->tm_min < 0 || time_stamp->tm_min > 60)
  4720.       return(NULL);
  4721.     if (time_stamp->tm_sec < 0 || time_stamp->tm_sec > 60)
  4722.       return(NULL);
  4723.     sprintf(zltimbuf,"%04d%02d%02d %02d:%02d:%02d",
  4724.             time_stamp->tm_year + 1900,
  4725.             time_stamp->tm_mon + 1,
  4726.             time_stamp->tm_mday,
  4727.             time_stamp->tm_hour,
  4728.             time_stamp->tm_min,
  4729.             time_stamp->tm_sec
  4730.             );
  4731.     return((char *)zltimbuf);
  4732. }
  4733. #endif /* ZLOCALTIME */
  4734.  
  4735. /* Z S T I M E  --  Set modification date/time+permissions for incoming file */
  4736. /*
  4737.  Call with:
  4738.  f  = pointer to name of existing file.
  4739.  yy = pointer to a Kermit file attribute structure in which yy->date.val
  4740.       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
  4741.       yy->lprotect.val & yy->gprotect.val are permission/protection values.
  4742.  x  = is a function code: 0 means to set the file's attributes as given.
  4743.       1 means compare the date in struct yy with the file creation date.
  4744.  Returns:
  4745.  -1 on any kind of error.
  4746.   0 if x is 0 and the attributes were set successfully.
  4747.   0 if x is 1 and date from attribute structure <= file creation date.
  4748.   1 if x is 1 and date from attribute structure > file creation date.
  4749. */
  4750. int
  4751. zstime(f,yy,x) char *f; struct zattr *yy; int x;
  4752. /* zstime */ {
  4753.     int r = -1;                         /* Return code */
  4754. #ifdef CK_PERMS
  4755.     int setperms = 0;
  4756. #endif /* CK_PERMS */
  4757.     int setdate = 0;
  4758.     struct stat sb;
  4759.     struct utimbuf tp;
  4760.     long tm=0;
  4761.  
  4762.     debug(F110,"zstime",f,0);
  4763.     debug(F111,"zstime date",yy->date.val,yy->date.len);
  4764.  
  4765. #ifdef CKROOT
  4766.     debug(F111,"zstime setroot",ckroot,ckrootset);
  4767.     if (ckrootset)
  4768.         if (!zinroot(f)) {
  4769.             debug(F110,"zstime setroot violation",f,0);
  4770.             return(0);
  4771.         }
  4772. #endif /* CKROOT */
  4773.  
  4774.     if (os2stat(f,&sb)) {                       /* Get the time for the file */
  4775.         debug(F110,"zstime: Can't stat file:",f,0);
  4776.         return(-1);
  4777.     }
  4778.  
  4779.     if (yy->date.len == 0) {            /* No date in struct */
  4780.         if (yy->lprotect.len != 0) {    /* So go do permissions */
  4781.             goto zsperms;
  4782.         } else {
  4783.             debug(F100,"zstime: nothing to do","",0);
  4784.             return(0);
  4785.         }
  4786.     }
  4787.     if ((tm = zstrdt(yy->date.val,yy->date.len)) < 0) {
  4788.         debug(F101,"zstime: zstrdt fails","",0);
  4789.         return(-1);
  4790.     }
  4791.     debug(F101,"zstime: tm","",tm);
  4792.     debug(F111,"zstime: A-pkt date ok ",yy->date.val,yy->date.len);
  4793.  
  4794.     setdate = 1;
  4795.  
  4796.   zsperms:
  4797. #ifdef CK_PERMS
  4798.     {
  4799.         int i, x = 0, xx, flag = 0;
  4800.         char * s;
  4801. #ifdef DEBUG
  4802.         char obuf[24];
  4803.         if (deblog) {
  4804.             debug(F111,"zstime lperms",yy->lprotect.val,yy->lprotect.len);
  4805.             debug(F111,"zstime gperms",yy->gprotect.val,yy->gprotect.len);
  4806.             debug(F110,"zstime system id",yy->systemid.val,0);
  4807.             sprintf(obuf,"%o",sb.st_mode);
  4808.             debug(F110,"zstime file perms before",obuf,0);
  4809.         }
  4810. #endif /* DEBUG */
  4811.         if ((yy->lprotect.len > 0 &&    /* Have local-format permissions */
  4812.             yy->systemid.len > 0 &&     /* from A-packet... */
  4813.             0 ) || (yy->lprotect.len < 0) /* OR by inheritance from old file */
  4814.             ) {
  4815.             flag = 1;
  4816.             s = yy->lprotect.val;       /* UNIX filemode */
  4817.             xx = yy->lprotect.len;
  4818.             if (xx < 0)                 /* len < 0 means inheritance */
  4819.               xx = 0 - xx;
  4820.             for (i = 0; i < xx; i++) {  /* Decode octal string */
  4821.                 if (*s <= '7' && *s >= '0') {
  4822.                     x = 8 * x + (int)(*s) - '0';
  4823.                 } else {
  4824.                     flag = 0;
  4825.                     break;
  4826.                 }
  4827.                 s++;
  4828.             }
  4829. #ifdef DEBUG
  4830.             sprintf(obuf,"%o",x);
  4831.             debug(F110,"zstime octal lperm",obuf,0);
  4832. #endif /* DEBUG */
  4833.         } else if (!flag && yy->gprotect.len > 0) {
  4834.             int g;
  4835.             g = xunchar(*(yy->gprotect.val));
  4836.             debug(F101,"zstime gprotect","",g);
  4837. #ifdef S_IRUSR
  4838.             debug(F100,"zstime S_IRUSR","",0);
  4839.             if (g & 1) x |= S_IRUSR;    /* Read permission */
  4840.             flag = 1;
  4841. #endif /* S_IRUSR */
  4842. #ifdef S_IWUSR
  4843.             debug(F100,"zstime S_IWUSR","",0);
  4844.             if (g & 2) x |= S_IWUSR;    /* Write permission */
  4845.             if (g & 16) x |= S_IWUSR;   /* Delete permission */
  4846.             flag = 1;
  4847. #endif /* S_IWUSR */
  4848. #ifdef S_IXUSR
  4849.             debug(F100,"zstime S_IXUSR","",0);
  4850.             if (g & 4) x |= S_IXUSR;
  4851.             flag = 1;
  4852. #endif /* S_IXUSR */
  4853.         }
  4854.         if (flag) {
  4855. #ifdef S_IFMT
  4856.             sb.st_mode = (sb.st_mode & S_IFMT) | x;
  4857.             setperms = 1;
  4858. #else
  4859. #ifdef _IFMT
  4860.             sb.st_mode = (sb.st_mode & _IFMT) | x;
  4861.             setperms = 1;
  4862. #endif /* _IFMT */
  4863. #endif /* S_IFMT */
  4864.         }
  4865. #ifdef DEBUG
  4866.         sprintf(obuf,"%o",sb.st_mode);
  4867.         debug(F110,"zstime file perms after",obuf,0);
  4868. #endif /* DEBUG */
  4869.     }
  4870. #endif /* CK_PERMS */
  4871.  
  4872.     debug(F101,"zstime: sb.st_atime","",sb.st_atime);
  4873.  
  4874.     tp.modtime = tm;                    /* Set modif. time to creation date */
  4875.     tp.actime = sb.st_atime;            /* Don't change the access time */
  4876.  
  4877.     switch (x) {                        /* Execute desired function */
  4878.       case 0:                           /* Set the creation date of the file */
  4879. #ifdef CK_PERMS                         /* And permissions */
  4880. /*
  4881.   NOTE: If we are inheriting permissions from a previous file, and the
  4882.   previous file was a directory, this would turn the new file into a directory
  4883.   too, but it's not, so we try to unset the right bit.  Luckily, this code
  4884.   will probably never be executed since the upper level modules do not allow
  4885.   reception of a file that has the same name as a directory.
  4886. */
  4887.         {
  4888.             int x;
  4889.             debug(F101,"zstime setperms","",setperms);
  4890.             if (S_ISDIR(sb.st_mode)) {
  4891.                 debug(F101,"zstime DIRECTORY bit on","",sb.st_mode);
  4892.                 sb.st_mode ^= 0040000;
  4893.                 debug(F101,"zstime DIRECTORY bit off","",sb.st_mode);
  4894.             }
  4895.             if (setperms) {
  4896.                 x = chmod(f,sb.st_mode);
  4897.                 debug(F101,"zstime chmod","",x);
  4898.             }
  4899.         }
  4900.         if (x < 0) return(-1);
  4901. #endif /* CK_PERMS */
  4902.  
  4903.         if (!setdate)                   /* We don't have a date */
  4904.           return(0);                    /* so skip the following... */
  4905.  
  4906.         if (utime(f,&tp)) {             /* Fix modification time */
  4907.             debug(F110,"zstime 0: can't set modtime for file",f,0);
  4908.             r = -1;
  4909.         } else  {
  4910.             debug(F110,"zstime 0: modtime set for file",f,0);
  4911.             r = 0;
  4912.         }
  4913.         break;
  4914.  
  4915.       case 1:                           /* Compare the dates */
  4916. /*
  4917.   This was st_atime, which was wrong.  We want the file-data modification
  4918.   time, st_mtime.
  4919. */
  4920.         debug(F111,"zstime 1: compare",f,sb.st_mtime);
  4921.         debug(F111,"zstime 1: compare","packet",tm);
  4922.  
  4923. /*
  4924.   In OS/2, sb.st_mtime, at least on a FAT file system, is always even.
  4925.   In that case, if the incoming file is only one second newer than the
  4926.   local file, consider them the same (yuk).
  4927. */
  4928. #ifdef COMMENT
  4929.           /* In IBM C 3.6 time_t is of type double.  This can't be done */
  4930.         if ((sb.st_mtime & 1) == 0)
  4931. #endif /* COMMENT */
  4932.           if ((tm - sb.st_mtime) == 1)
  4933.             tm--;
  4934.         r = (sb.st_mtime < tm) ? 0 : 1;
  4935.         break;
  4936.  
  4937.       default:                          /* Error */
  4938.         r = -1;
  4939.     }
  4940.     return(r);
  4941. }
  4942.  
  4943. /* Find initialization file. */
  4944.  
  4945. #ifndef NOFRILLS
  4946. int
  4947. zmail(p,f) char *p; char *f; {          /* Send file f as mail to address p */
  4948. /*
  4949.   Returns 0 on success
  4950.    2 if mail delivered but temp file can't be deleted
  4951.   -2 if mail can't be delivered
  4952.   The UNIX version always returns 0 because it can't get a good return
  4953.   code from zsyscmd.
  4954. */
  4955.  
  4956. #ifdef CK_LOGIN
  4957.     if (isguest)
  4958.       return(-2);
  4959. #endif /* CK_LOGIN */
  4960.  
  4961.     if (!f) f = "";
  4962.     if (!*f) return(-1);
  4963.  
  4964. #ifdef CKROOT
  4965.     debug(F111,"zmail setroot",ckroot,ckrootset);
  4966.     if (ckrootset)
  4967.         if (!zinroot(f)) {
  4968.             debug(F110,"zmail setroot violation",f,0);
  4969.             return(-1);
  4970.         }
  4971. #endif /* CKROOT */
  4972.  
  4973. /* The idea is to use /usr/ucb/mail, rather than regular mail, so that   */
  4974. /* a subject line can be included with -s.  Since we can't depend on the */
  4975. /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
  4976. /* and even if Mail has been moved to somewhere else, this should still  */
  4977. /* find it...  The search could be made more reliable by actually using  */
  4978. /* access() to see if /usr/ucb/Mail exists. */
  4979.  
  4980. /* Should also make some check on zmbuf overflow... */
  4981.  
  4982.     sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
  4983.     zsyscmd(zmbuf);
  4984.     return(-1);
  4985. }
  4986. #endif /* NOFRILLS */
  4987.  
  4988. #ifndef NOFRILLS
  4989. #ifdef NT
  4990. _PROTOTYP(int Win32PrtFile,( char *, char *));
  4991. #endif /* NT */
  4992.  
  4993.  
  4994. int
  4995. zprint(p,f) char *p; char *f; {         /* Print file f with options p */
  4996.     extern char * printername;          /* From ckuus3.c */
  4997.     extern int printpipe;
  4998.  
  4999.     debug(F110,"zprint file",f,0);
  5000.     debug(F110,"zprint flags",p,0);
  5001.     debug(F110,"zprint printername",printername,0);
  5002.     debug(F101,"zprint printpipe","",printpipe);
  5003.  
  5004. #ifdef CK_LOGIN
  5005.     if (isguest)
  5006.       return(-2);
  5007. #endif /* CK_LOGIN */
  5008.  
  5009.     if (!f) f = "";
  5010.     if (!*f) return(-1);
  5011.  
  5012. #ifdef CKROOT
  5013.     debug(F111,"zprint setroot",ckroot,ckrootset);
  5014.     if (ckrootset)
  5015.         if (!zinroot(f)) {
  5016.             debug(F110,"zprint setroot violation",f,0);
  5017.             return(-1);
  5018.         }
  5019. #endif /* CKROOT */
  5020.  
  5021.     prtfile(f);
  5022.     *zmbuf = '\0';
  5023.     return(0);
  5024. }
  5025. #endif /* NOFRILLS */
  5026.  
  5027. char *
  5028. whoami()
  5029. {
  5030.     static char realname[MAXPATH];
  5031. #ifdef NT
  5032.     DWORD len = MAXPATH;
  5033.     GetUserName( realname, &len );
  5034. #else /* NT */
  5035.     char * env = getenv("USER");
  5036.     if (env)
  5037.         ckstrncpy(realname,env,MAXPATH);
  5038.     else
  5039.         strcpy(realname,"os2user");
  5040. #endif /* NT */
  5041.     return realname;
  5042. }
  5043.  
  5044. /*  T I L D E _ E X P A N D  --  expand ~user to the user's home directory. */
  5045.  
  5046. char *
  5047. tilde_expand(dirname) char *dirname; {
  5048.     return(NULL);
  5049. }
  5050.  
  5051. /*
  5052.   Functions for executing system commands.
  5053.   zsyscmd() executes the system command in the normal, default way for
  5054.   the system.  In UNIX, it does what system() does.  Thus, its results
  5055.   are always predictable.
  5056.   zshcmd() executes the command using the user's preferred shell.
  5057. */
  5058. int
  5059. zsyscmd(s) char *s; {
  5060. #ifndef NOPUSH
  5061.     extern int vmode;
  5062.  
  5063. /*
  5064.   We must set the priority back to normal.  Otherwise all of children
  5065.   processes are going to inherit our FOREGROUNDSERVER priority and that
  5066.   would not be good for the system or ourselves.
  5067. */
  5068.    if (!priv_chk()) {
  5069.        ULONG rc = 0;
  5070. #ifndef KUI
  5071.        char title[80];
  5072.        title[0] = '\0';
  5073.        os2gettitle( title, 80 );
  5074.        msleep(100);
  5075.        RequestScreenMutex(SEM_INDEFINITE_WAIT);
  5076.        KbdHandlerCleanup();
  5077. #endif /* KUI */
  5078.        ResetThreadPrty();
  5079.        rc = system(s);
  5080.        SetThreadPrty(priority,15);
  5081. #ifndef KUI
  5082.        KbdHandlerInit();
  5083.        /* Reset mode and buffering for stdio */
  5084.        if ( k95stdin ) {
  5085. #ifdef NT
  5086.            _setmode(_fileno(stdin),_O_BINARY);
  5087. #else
  5088.            setmode(fileno(stdin),_O_BINARY);
  5089. #endif /* NT */
  5090.        }
  5091.        if ( k95stdout ) {
  5092. #ifdef NT
  5093.            _setmode(_fileno(stdout),_O_TEXT);
  5094. #else
  5095.            setmode(fileno(stdout),_O_TEXT);
  5096. #endif /* NT */
  5097.            setbuf(stdout,NULL);
  5098.        }
  5099.        if (
  5100. #ifndef NOSPL
  5101.         cmdlvl == 0
  5102. #else
  5103.         tlevel < 0
  5104. #endif /* NOSPL */
  5105.         )
  5106.            OS2WaitForKey();
  5107.        ReleaseScreenMutex();
  5108.        VscrnForceFullUpdate();
  5109.        VscrnIsDirty(vmode);
  5110.        os2settitle(title, FALSE);
  5111. #endif /* KUI */
  5112.        return(rc);
  5113.    }
  5114.    return(0);
  5115. #else /* NOPUSH */
  5116.     return(-1);
  5117. #endif /* NOPUSH */
  5118. }
  5119.  
  5120. /*
  5121.   Original UNIX code by H. Fischer; copyright rights assigned to Columbia U.
  5122.   Adapted to use getpwuid to find login shell because many systems do not
  5123.   have SHELL in environment, and to use direct calling of shell rather
  5124.   than intermediate system() call. -- H. Fischer (1985); many changes since
  5125.   then.  Call with s pointing to command to execute.
  5126. */
  5127.  
  5128. int
  5129. _zshcmd(s,wait) char *s; int wait; {
  5130. #ifndef NOPUSH
  5131.     PID_T pid;
  5132.     int rc;
  5133.     char title[80];
  5134. #ifdef NT
  5135.     SIGTYP (* savint)(int);
  5136. #endif /* NT */
  5137.     char *shell = getenv("SHELL");
  5138.     extern int vmode;
  5139.  
  5140.     if ( !shell )
  5141.        shell = getenv("COMSPEC");
  5142.  
  5143.     pexitstat = -3;                     /* Initialize process exit status */
  5144.  
  5145.     if (!priv_chk()) {
  5146. #ifndef KUI
  5147.         os2gettitle( title, 80 );
  5148.         msleep(100);
  5149.         RequestScreenMutex(SEM_INDEFINITE_WAIT);
  5150.         KbdHandlerCleanup();
  5151. #endif /* KUI */
  5152.  
  5153.         ResetThreadPrty();
  5154. #ifdef NT
  5155.         savint = signal( SIGINT, SIG_IGN );
  5156. #endif /* NT */
  5157.  
  5158.         if (!s || *s == '\0')
  5159.           pexitstat = system(shell);    /* was _spawnlp(P_WAIT, shell, NULL) */
  5160.         else
  5161.           pexitstat = system(s);
  5162. #ifdef NT
  5163.         signal( SIGINT, savint );
  5164. #endif /* NT */
  5165.  
  5166.         SetThreadPrty(priority,15);
  5167.  
  5168. #ifndef KUI
  5169.         KbdHandlerInit();
  5170.         if ( k95stdin ) {
  5171. #ifdef NT
  5172.             _setmode(_fileno(stdin),_O_BINARY);
  5173. #else
  5174.             setmode(fileno(stdin),_O_BINARY);
  5175. #endif /* NT */
  5176.         }
  5177.         if ( k95stdout ) {
  5178. #ifdef NT
  5179.             _setmode(_fileno(stdout),_O_TEXT);
  5180. #else
  5181.             setmode(fileno(stdout),_O_TEXT);
  5182. #endif /* NT */
  5183.             setbuf(stdout,NULL);
  5184.         }
  5185.         if ( wait && cmdsrc() == 0 )
  5186.             OS2WaitForKey();
  5187.         ReleaseScreenMutex();
  5188.         VscrnForceFullUpdate();
  5189.         VscrnIsDirty(vmode);
  5190.         os2settitle( title, FALSE );
  5191. #endif /* KUI */
  5192.     }
  5193. #else /* NOPUSH */
  5194.     pexitstat = 1;
  5195. #endif /* NOPUSH */
  5196.     return(pexitstat == 0);
  5197. }
  5198.  
  5199. int
  5200. zshcmd(s) char *s; {
  5201.     return(_zshcmd(s,1));
  5202. }
  5203.  
  5204. /*  I S W I L D  --  Check if filespec is "wild"  */
  5205.  
  5206. /*
  5207.   Returns 0 if it is a single file, 1 if it contains wildcard characters.
  5208.   Note: must match the algorithm used by match(), hence no [a-z], etc.
  5209. */
  5210. int
  5211. iswild(filespec) char *filespec; {
  5212.     char c; int x; char *p;
  5213.     int quo = 0;
  5214.  
  5215.     while ((c = *filespec++) != '\0') {
  5216.         if (c == '\\' && quo == 0) {
  5217.             quo = 1;
  5218.             continue;
  5219.         }
  5220.         if (!quo && (c == '*' || c == '?'
  5221. #ifdef CKREGEX
  5222.                       || c == '[' || c == '{'
  5223. #endif /* CKREGEX */
  5224.                       ))
  5225.             return(1);
  5226.         quo = 0;
  5227.     }
  5228.     return(0);
  5229. }
  5230.  
  5231.  
  5232. /*
  5233.    Tell if string pointer s is the name of an existing directory.
  5234.    Returns 1 if directory, 0 if not a directory.
  5235. */
  5236. int
  5237. isdir(s) char *s; {
  5238. #ifdef NT
  5239.     DWORD attrs;
  5240. #else /* NT */
  5241.     int x;
  5242.     struct stat statbuf;
  5243. #endif /* NT */
  5244.  
  5245.     if (!s) return(0);
  5246.     if (!*s) return(0);
  5247.  
  5248.     /* Disk letter like A: is top-level directory on a disk */
  5249.     if (((int)strlen(s) == 2) && (isalpha(*s)) && (*(s+1) == ':')) {
  5250.         return(1);
  5251.     }
  5252. #ifdef NT
  5253.     attrs = GetFileAttributes(s);
  5254.     if ( attrs == INVALID_FILE_ATTRIBUTES )
  5255.         return(0);
  5256.     return(attrs & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0);
  5257.  
  5258. #else
  5259.     x = os2stat(s,&statbuf);
  5260.     debug(F111,"isdir stat",s,x);
  5261.     if (x == -1) {
  5262.         debug(F101,"isdir errno","",errno);
  5263.         return(0);
  5264.     } else {
  5265.         debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode);
  5266.         return (S_ISDIR (statbuf.st_mode) ? 1 : 0);
  5267.     }
  5268. #endif
  5269. }
  5270.  
  5271. #ifdef CK_MKDIR
  5272. /* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */
  5273.  
  5274. /* Z M K D I R  --  Create directory(s) if necessary */
  5275. /*
  5276.    Call with:
  5277.     A pointer to a file specification that might contain directory
  5278.     information.  The filename is expected to be included.
  5279.     If the file specification does not include any directory separators,
  5280.     then it is assumed to be a plain file.
  5281.     If one or more directories are included in the file specification,
  5282.     this routine tries to create them if they don't already exist.
  5283.    Returns:
  5284.     0 or greater on success, i.e. the number of directories created.
  5285.    -1 on failure to create the directory
  5286. */
  5287. int
  5288. zmkdir(path) char *path; {
  5289.     char *xp, *tp, c;
  5290.     int x, count = 0, i;
  5291.  
  5292.     if (!path) path = "";
  5293.     if (!*path) return(-1);
  5294.  
  5295. #ifdef CKROOT
  5296.     debug(F111,"zmkdir setroot",ckroot,ckrootset);
  5297.     if (ckrootset)
  5298.         if (!zinroot(path)) {
  5299.             debug(F110,"zmkdir setroot violation",path,0);
  5300.             return(-1);
  5301.         }
  5302. #endif /* CKROOT */
  5303.  
  5304.     x = strlen(path);
  5305.     debug(F111,"zmkdir",path,x);
  5306.     if (x < 1 || x > MAXPATH)           /* Check length */
  5307.       return(-1);
  5308.     if (!(tp = malloc(x+1)))            /* Make a temporary copy */
  5309.       return(-1);
  5310.     strcpy(tp,path);
  5311.  
  5312.     /* Fixup for UNC if necessary */
  5313.     if ( !strncmp(tp,"//",2) || !strncmp(tp,"\\\\",2) ) { 
  5314.         strcpy(tp,UNCname(tp));
  5315.  
  5316.         xp = &tp[2];                    /* */
  5317.         while ( !(ISDIRSEP(*xp)) )      /* Find end of machine name */
  5318.             xp++;
  5319.         xp++;                           /* Skip to beginning of object name */
  5320.         while ( !(ISDIRSEP(*xp)) )      /* Find end of object name */
  5321.             xp++;
  5322.         xp++;                           /* Skip to first directory name */
  5323.  
  5324.         if ( xp-tp > x ) {
  5325.             free(tp);
  5326.             return(-1);
  5327.         }
  5328.     } else {
  5329.         xp = tp;
  5330.         if (ISDIRSEP(*xp))              /* Don't create root directory! */
  5331.             xp++;
  5332.     }
  5333.  
  5334.     /* Go thru filespec from left to right... */
  5335.     for (; *xp; xp++) {                 /* Create parts that don't exist */
  5336.         if (!ISDIRSEP(*xp))             /* Find next directory separator */
  5337.           continue;
  5338.         c = *xp;                        /* Got one. */
  5339.         *xp = NUL;                      /* Make this the end of the string. */
  5340.         if (!isdir(tp)) {               /* This directory exists already? */
  5341. #ifdef CK_LOGIN
  5342.             if (isguest)                /* Not allowed for guests */
  5343.                 return(-1);
  5344. #ifndef NOXFER
  5345.             else                    /* Nor if MKDIR and/or CD are disabled */
  5346. #endif /* CK_LOGIN */
  5347.                 if ((server
  5348. #ifdef IKSD
  5349.                       || inserver
  5350. #endif /* IKSD */
  5351.                       ) && (!ENABLED(en_mkd) || !ENABLED(en_cwd)))
  5352.                     return(-1);
  5353. #endif /* IKSD */
  5354.  
  5355.             debug(F110,"zmkdir making",tp,0);
  5356.             x =                         /* No, try to create it */
  5357.               _mkdir(tp);               /* The IBM way */
  5358.             if (x < 0) {
  5359.                 debug(F101,"zmkdir failed, errno","",errno);
  5360.                 free(tp);               /* Free temporary buffer. */
  5361.                 tp = NULL;
  5362.                 return(-1);             /* Return failure code. */
  5363.             } else
  5364.               count++;
  5365.         }
  5366.         *xp = c;                        /* Replace the separator. */
  5367.     }
  5368.     free(tp);                           /* Free temporary buffer. */
  5369.     return(count);                      /* Return success code. */
  5370. }
  5371. #endif /* CK_MKDIR */
  5372.  
  5373. int
  5374. zrmdir(char * path) {
  5375. #ifdef CK_LOGIN
  5376.     if (isguest)
  5377.       return(-1);
  5378. #endif /* CK_LOGIN */
  5379.  
  5380.     if (!path) path = "";
  5381.     if (!*path) return(-1);
  5382.  
  5383. #ifdef CKROOT
  5384.     debug(F111,"zrmdir setroot",ckroot,ckrootset);
  5385.     if (ckrootset)
  5386.         if (!zinroot(path)) {
  5387.             debug(F110,"zrmdir setroot violation",path,0);
  5388.             return(-1);
  5389.         }
  5390. #endif /* CKROOT */
  5391.  
  5392.  
  5393.     if ( !strncmp(path,"//",2) || !strncmp(path,"\\\\",2) )
  5394.         path = UNCname(path);
  5395.     return(rmdir(path));
  5396. }
  5397.  
  5398. /* Z F S E E K  --  Position input file pointer */
  5399. /*
  5400.    Call with:
  5401.     Long int, 0-based, indicating desired position.
  5402.    Returns:
  5403.     0 on success.
  5404.    -1 on failure.
  5405. */
  5406. #ifdef CK_RESEND
  5407. int
  5408. zfseek(CK_OFF_T pos)
  5409. {
  5410. #ifdef NT
  5411.     int rc;
  5412.     fpos_t fpos = pos;
  5413. #endif /* NT */
  5414.  
  5415.     zincnt = -1 ;               /* must empty the input buffer */
  5416.  
  5417.     debug(F101,"zfseek","",pos);
  5418. #ifdef NT
  5419.     if (GetFileType((HANDLE)_get_osfhandle(_fileno(fp[ZIFILE])))
  5420.          == FILE_TYPE_PIPE) {
  5421.         debug(F100,"zfseek FILE_TYPE_PIPE","",0);
  5422.         return(-1);
  5423.     }
  5424.     rc = fsetpos(fp[ZIFILE], &fpos);
  5425.  
  5426.     if (rc == 0) {
  5427.         debug(F100,"zfseek success","",0);
  5428.         return(0);
  5429.     } else {
  5430.         debug(F100,"zfseek failed","",GetLastError());
  5431.         return(-1);
  5432.     }
  5433. #else
  5434.     return(fseek(fp[ZIFILE], pos, 0)?-1:0);
  5435. #endif
  5436. }
  5437. #endif /* CK_RESEND */
  5438.  
  5439. struct zfnfp *
  5440. zfnqfp(fname, buflen, buf)  char * fname; int buflen; char * buf; {
  5441.     int x = 0, y = 0;
  5442.     char * xp;
  5443.     static struct zfnfp fnfp;
  5444.  
  5445.     if (!fname)
  5446.       return(NULL);
  5447.  
  5448.     /* initialize the data structure */
  5449.     fnfp.len = buflen;
  5450.     fnfp.fpath = buf;
  5451.     fnfp.fname = NULL;
  5452.  
  5453. #ifdef NT
  5454.     if ( GetFullPathName( fname, buflen, fnfp.fpath, &fnfp.fname ) ) {
  5455.         while ( fnfp.fpath[y] ) {
  5456.             if ( fnfp.fpath[y] == '\\' )
  5457.                 fnfp.fpath[y] = '/';
  5458.             y++;
  5459.         }
  5460.     if (isdir(fnfp.fpath)) {
  5461.         if (fnfp.fpath[y-1] != '/' && y < (buflen - 1)) {
  5462.         fnfp.fpath[y++] = '/';
  5463.         fnfp.fpath[y] = NUL;
  5464.         }
  5465.         fnfp.fname = NULL;
  5466.     }
  5467.         fnfp.len = strlen(fnfp.fpath);
  5468.         return(&fnfp);
  5469.     }
  5470.     else
  5471. #else /* NT */
  5472.       if (!DosQueryPathInfo(fname,5 /* Full Path Info */, fnfp.fpath,buflen)) {
  5473.           x = y = strlen(fnfp.fpath);
  5474.           for (x = x + 1; x >= 0; x--) {/* Find where the filename starts */
  5475.               if (fnfp.fpath[x] == '/') /* There is guaranteed to be one */
  5476.                   fnfp.fname = fnfp.fpath + x; /* Got it, set pointer */
  5477.               else if (fnfp.fpath[x] == '\\') {
  5478.                   fnfp.fpath[x] = '/';
  5479.                   fnfp.fname = fnfp.fpath + x; /* Got it, set pointer */
  5480.               }
  5481.           }
  5482.       if (isdir(fnfp.fpath)) {
  5483.           fnfp.fpath = NULL;
  5484.           if (fnfp.fpath[y-1] != '/' && y < (buflen - 1)) {
  5485.           fnfp.fpath[y++] = '/';
  5486.           fnfp.fpath[y] = NUL;
  5487.           }
  5488.       }
  5489.           fnfp.len = strlen(fnfp.fpath);
  5490.           return(&fnfp);                /* and return. */
  5491.       } else
  5492. #endif /* NT */
  5493.     return(NULL);
  5494. }
  5495.  
  5496. /*  Z C M P F N  --  Compare two filenames  */
  5497.  
  5498. /*  Returns 1 if the two names refer to the same existing file, 0 otherwise. */
  5499.  
  5500. int
  5501. zcmpfn(s1,s2) char * s1, * s2; {
  5502.     char buf1[CKMAXPATH+1];
  5503.     char buf2[CKMAXPATH+1];
  5504.     char linkname[CKMAXPATH+1];
  5505.     int x, rc = 0;
  5506.     struct stat buf;
  5507.  
  5508.     if (!s1) s1 = "";
  5509.     if (!s2) s2 = "";
  5510.     if (!*s1 || !*s2) return(0);
  5511.  
  5512.     if (zfnqfp(s1,CKMAXPATH,buf1)) {    /* Convert to full pathname */
  5513.  
  5514.         if (zfnqfp(s2,CKMAXPATH,buf2)) {
  5515.             debug(F110,"zcmpfn s1",buf1,0);
  5516.             debug(F110,"zcmpfn s2",buf2,0);
  5517.             if (!strncmp(buf1,buf2,CKMAXPATH))
  5518.               rc = 1;
  5519.         }
  5520.     }
  5521.     debug(F101,"zcmpfn result","",rc);
  5522.     return(rc);
  5523. }
  5524.  
  5525.  
  5526. #ifdef CKROOT
  5527.  
  5528. /* User-mode chroot() implementation */
  5529.  
  5530. int
  5531. zsetroot(s) char * s; {                 /* Sets the root */
  5532.     char buf[CKMAXPATH+1];
  5533.     if (!s) return(-1);
  5534.     if (!*s) return(-1);
  5535.     debug(F110,"zsetroot",s,0);
  5536.     if (!isdir(s)) return(-2);
  5537.     if (!zfnqfp(s,CKMAXPATH,buf))       /* Get full, real path */
  5538.       return(-3);
  5539.     if (access(buf,R_OK) < 0) {         /* Check access */
  5540.         debug(F110,"zsetroot access denied",buf,0);
  5541.         return(-4);
  5542.     }
  5543.     s = buf;
  5544.     if (ckrootset) {                    /* If root already set */
  5545.         if (!zinroot(s)) {              /* make sure new root is in it */
  5546.             debug(F110,"zsetroot new root not in root",ckroot,0);
  5547.             return(-5);
  5548.         }
  5549.     }
  5550.     if (zchdir(buf) < 1) return(-4);    /* Change directory to new root */
  5551.     ckrootset = ckstrncpy(ckroot,buf,CKMAXPATH); /* Now set the new root */
  5552.     if (ckroot[ckrootset-1] != '/') {
  5553.         ckroot[ckrootset++] = '/';
  5554.         ckroot[ckrootset] = '\0';
  5555.     }
  5556.     debug(F111,"zsetroot rootset",ckroot,ckrootset);
  5557.     ckrooterr = 0;                      /* Reset error flag */
  5558.     return(1);
  5559. }
  5560.  
  5561. char *
  5562. zgetroot() {                            /* Returns the root */
  5563.     if (!ckrootset)
  5564.       return(NULL);
  5565.     return((char *)ckroot);
  5566. }
  5567.  
  5568. int
  5569. zinroot(s) char * s; {                  /* Checks if file s is in the root */
  5570.     int x, n;
  5571.     struct zfnfp * f = NULL;
  5572.     char buf[CKMAXPATH+2];
  5573.  
  5574.     debug(F111,"zinroot setroot",ckroot,ckrootset);
  5575.     ckrooterr = 0;                      /* Reset global error flag */
  5576.     if (!ckrootset)                     /* Root not set */
  5577.       return(1);                        /* so it's ok - no need to check */
  5578.     if (!(f = zfnqfp(s,CKMAXPATH,buf))) /* Get full and real pathname */
  5579.       return(0);                        /* Fail if we can't  */
  5580.     n = f->len;                         /* Length of full pathname */
  5581.     debug(F111,"zinroot n",buf,n);
  5582.     if (n < (ckrootset - 1) || n > CKMAXPATH) { /* Bad length */
  5583.         ckrooterr = 1;                          /* Fail */
  5584.         return(0);
  5585.     }
  5586.     if (isdir(buf) && buf[n-1] != '/') {  /* If it's a directory name */
  5587.         buf[n++] = '/';                   /* make sure it ends with '/' */
  5588.         buf[n] = '\0';
  5589.     }
  5590.     x = ckstrcmp(buf,ckroot,ckrootset,0); /* Compare, case-insensitive */
  5591.     debug(F111,"zinroot checked",buf,x);
  5592.     if (x == 0)                         /* OK */
  5593.       return(1);
  5594.     ckrooterr = 1;                      /* Not OK */
  5595.     return(0);
  5596. }
  5597. #endif /* CKROOT */
  5598.  
  5599. #ifdef NT
  5600. static int
  5601. UnicodeToOEM(LPWSTR InString, char *OutString, int OutStringSize)
  5602. {
  5603.     return WideCharToMultiByte(CP_OEMCP, 0, InString, -1,
  5604.                                 OutString, OutStringSize, NULL, NULL);
  5605. }
  5606.  
  5607. static int
  5608. OEMToUnicode(char *InString, LPWSTR OutString, int OutStringSize)
  5609. {
  5610.     return MultiByteToWideChar(CP_OEMCP, 0, InString, -1,
  5611.                                 OutString, OutStringSize);
  5612. }
  5613.  
  5614. static int
  5615. UnicodeToANSI(LPWSTR InString, char *OutString, int OutStringSize)
  5616. {
  5617.     return WideCharToMultiByte(CP_ACP, 0, InString, -1,
  5618.                                 OutString, OutStringSize, NULL, NULL);
  5619. }
  5620.  
  5621. static int
  5622. ANSIToUnicode(char *InString, LPWSTR OutString, int OutStringSize)
  5623. {
  5624.     return MultiByteToWideChar(CP_ACP, 0, InString, -1,
  5625.                                 OutString, OutStringSize);
  5626. }
  5627. #endif /* NT */
  5628.  
  5629. #ifdef CK_LOGIN
  5630. _PROTOTYP(const char * SSPLogonDomain,(VOID));
  5631. _PROTOTYP(int IsSSPLogonAvail,(VOID));
  5632.  
  5633. #ifdef NT
  5634. static HANDLE hLoggedOn = INVALID_HANDLE_VALUE;
  5635. static PSID pSid = NULL;
  5636. static PSID pPriGroupSid = NULL;
  5637. static PTOKEN_GROUPS pTokenGroups = NULL;
  5638. static SID_NAME_USE SidNameUse;
  5639. static char HomeDir[MAXPATH] = "", ProfilePath[MAXPATH] = "";
  5640. static DWORD PrimaryGroupId;
  5641. CHAR * pReferenceDomainName = NULL;
  5642. static CHAR * pPDCName = NULL;
  5643.  
  5644. #ifndef PROFILEINFO
  5645. #define PI_NOUI 1                       // Prevents displaying of profile error messages.
  5646. #define PI_APPLYPOLICY 2                // Applies a Windows NT 4.0-style policy.
  5647.  
  5648. typedef struct _PROFILEINFOA {
  5649.     DWORD       dwSize;                 // Set to sizeof(PROFILEINFO) before calling
  5650.     DWORD       dwFlags;                // See flags above
  5651.     LPSTR       lpUserName;             // User name (required)
  5652.     LPSTR       lpProfilePath;          // Roaming profile path (optional, can be NULL)
  5653.     LPSTR       lpDefaultPath;          // Default user profile path (optional, can be NULL)
  5654.     LPSTR       lpServerName;           // Validating domain controller name in netbios format (optional, can be NULL but group NT4 style policy won't be applied)
  5655.     LPSTR       lpPolicyPath;           // Path to the NT4 style policy file (optional, can be NULL)
  5656.     HANDLE      hProfile;               // Filled in by the function.  Registry key handle open to the root.
  5657. } PROFILEINFOA, FAR * LPPROFILEINFOA;
  5658. #define PROFILEINFO PROFILEINFOA
  5659. #define LPPROFILEINFO LPPROFILEINFOA
  5660. #endif /* PROFILEINFO */
  5661. PROFILEINFO profinfo = { sizeof profinfo, 0, 0, 0, 0, 0, 0 };
  5662. VOID      * pEnvBlock = NULL;
  5663. static HINSTANCE hUserEnv=NULL, hAdvApi=NULL;
  5664. static BOOL (WINAPI * p_CreateEnvironmentBlock)(void **, HANDLE, BOOL)=NULL;
  5665. static BOOL (WINAPI * p_DestroyEnvironmentBlock)(void *)=NULL;
  5666. static BOOL (WINAPI * p_LoadUserProfileA)(HANDLE, PROFILEINFO *)=NULL;
  5667. static BOOL (WINAPI * p_UnloadUserProfileA)(HANDLE, HANDLE)=NULL;
  5668. static BOOL (WINAPI * p_DuplicateTokenEx)(HANDLE hExistingToken,
  5669.                        DWORD dwDesiredAccess,
  5670.                        LPSECURITY_ATTRIBUTES lpTokenAttributes,
  5671.                        SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  5672.                        TOKEN_TYPE TokenType,
  5673.                        PHANDLE phNewToken)=NULL;
  5674.  
  5675. BOOL GetTextualSid(
  5676.     PSID pSid,            // binary Sid
  5677.     LPTSTR TextualSid,    // buffer for Textual representation of Sid
  5678.     LPDWORD lpdwBufferLen // required/provided TextualSid buffersize
  5679.     )
  5680. {
  5681.     PSID_IDENTIFIER_AUTHORITY psia;
  5682.     DWORD dwSubAuthorities;
  5683.     DWORD dwSidRev=SID_REVISION;
  5684.     DWORD dwCounter;
  5685.     DWORD dwSidSize;
  5686.  
  5687.     // Validate the binary SID.
  5688.  
  5689.     if(!IsValidSid(pSid)) return FALSE;
  5690.  
  5691.     // Get the identifier authority value from the SID.
  5692.  
  5693.     psia = GetSidIdentifierAuthority(pSid);
  5694.  
  5695.     // Get the number of subauthorities in the SID.
  5696.  
  5697.     dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  5698.  
  5699.     // Compute the buffer length.
  5700.     // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
  5701.  
  5702.     dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
  5703.  
  5704.     // Check input buffer length.
  5705.     // If too small, indicate the proper size and set last error.
  5706.  
  5707.     if (*lpdwBufferLen < dwSidSize)
  5708.     {
  5709.         *lpdwBufferLen = dwSidSize;
  5710.         SetLastError(ERROR_INSUFFICIENT_BUFFER);
  5711.         return FALSE;
  5712.     }
  5713.  
  5714.     // Add 'S' prefix and revision number to the string.
  5715.  
  5716.     dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
  5717.  
  5718.     // Add SID identifier authority to the string.
  5719.  
  5720.     if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
  5721.     {
  5722.         dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  5723.                     TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
  5724.                     (USHORT)psia->Value[0],
  5725.                     (USHORT)psia->Value[1],
  5726.                     (USHORT)psia->Value[2],
  5727.                     (USHORT)psia->Value[3],
  5728.                     (USHORT)psia->Value[4],
  5729.                     (USHORT)psia->Value[5]);
  5730.     }
  5731.     else
  5732.     {
  5733.         dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  5734.                     TEXT("%lu"),
  5735.                     (ULONG)(psia->Value[5]      )   +
  5736.                     (ULONG)(psia->Value[4] <<  8)   +
  5737.                     (ULONG)(psia->Value[3] << 16)   +
  5738.                     (ULONG)(psia->Value[2] << 24)   );
  5739.     }
  5740.  
  5741.     // Add SID subauthorities to the string.
  5742.     //
  5743.     for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
  5744.     {
  5745.         dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
  5746.                     *GetSidSubAuthority(pSid, dwCounter) );
  5747.     }
  5748.  
  5749.     return TRUE;
  5750. }
  5751.  
  5752. #ifdef NTCREATETOKEN
  5753. #define MAXSIZE 4096
  5754. #define gle (GetLastError())
  5755. static BOOL getSids( TOKEN_PRIVILEGES **tokenPrivs, PSID *ownerSid, PSID *priGroupSid, TOKEN_GROUPS **tokenGroups, LUID *logonSessionId );
  5756. static BOOL showToken( HANDLE ht );
  5757. static void showSid( int indent, PSID ps );
  5758. static BOOL Sid2Text( PSID ps, char *buf, int bufSize );
  5759. static BOOL IsLogonSid( PSID ps );
  5760. static BOOL IsLocalSid( PSID ps );
  5761. static BOOL IsInteractiveSid( PSID ps );
  5762. static BOOL getPriv( const char *privName );
  5763.  
  5764. HANDLE
  5765. CreateTokenForUser(char * szUsername, char * szDomain, PSID luserSid, PSID preGroupSid,
  5766.                     TOKEN_GROUPS * userTokenGroups) {
  5767.     HINSTANCE hlib;
  5768.     DWORD rc = 0;
  5769.     PSID ownerSid = 0, iksdSid = 0;
  5770.     PSID admingrpSid = 0, worldSid = 0;
  5771.     LUID logonSessionId;
  5772.     TOKEN_PRIVILEGES *tokenPrivs;
  5773.     SID_IDENTIFIER_AUTHORITY NTsia = SECURITY_NT_AUTHORITY;
  5774.     SID_IDENTIFIER_AUTHORITY worldsia = SECURITY_WORLD_SID_AUTHORITY;
  5775.     char *domainName;
  5776.     DWORD luserSidSize;
  5777.     DWORD domainNameSize;
  5778.     SID_NAME_USE luserSidType;
  5779.     // returned handle
  5780.     HANDLE tokenHandle = INVALID_HANDLE_VALUE;
  5781.     // permissions with which the handle is opened
  5782.     DWORD requestedPermissions = TOKEN_ALL_ACCESS;
  5783.     PACL newTokenDacl;
  5784.     SECURITY_DESCRIPTOR newTokenSD;
  5785.     SECURITY_QUALITY_OF_SERVICE sqos;
  5786.     LSA_OBJECT_ATTRIBUTES ObjAttr;
  5787.     TOKEN_TYPE tokenType;
  5788.     LUID sessionLuid, serviceSessionLuid = { 0x3e7, 0 };
  5789.     FILETIME expirationTime;
  5790.     SID_AND_ATTRIBUTES tokenUser;
  5791.     PSID newOwnerSid, newPriGroupSid;
  5792.     PACL newDefaultDacl;
  5793.     TOKEN_SOURCE tokenSource = { { '*', 'i', 'k', 's', 'd', '*' }, { 0, 0 } }; // TOKEN_SOURCE
  5794.  
  5795.  
  5796.     typedef DWORD (__stdcall *tNCT)( HANDLE                     *phToken,               // returned handle
  5797.                                      DWORD                      *pReqPermissionMask,    // requested permissions for returned handle
  5798.                                      LSA_OBJECT_ATTRIBUTES      *pObjAttr,              // contains SD controlling access to the new token
  5799.                                      TOKEN_TYPE                 tokenType,              // TokenPrimary == 1 == primary, TokenImpersonation == 2 == impersonation
  5800.                                      LUID                       *pLogonSessionLuid,     // LUID for logon session, goes into the token
  5801.                                      FILETIME                   *expirationTime,        // token expiration deadline. unsupported -- set to 2^63 - 1
  5802.                                      SID_AND_ATTRIBUTES         *pTokenUser,            // returned by GetTokenInformation( TokenUser )
  5803.                                      TOKEN_GROUPS               *pTokenGroups,          // exploded list of groups for the user
  5804.                                      TOKEN_PRIVILEGES           *pTokenPrivileges,      // list of privs assigned (not necessarily enabled)
  5805.                                      PSID                       *pOwnerSid,             // owner SID
  5806.                                      PSID                       *pPrimaryGroupSid,      // primary group SID
  5807.                                      PACL                       *pDefaultDacl,          // will be used as default if a process using this token assigns no security to new objects
  5808.                                      TOKEN_SOURCE               *pTokenSource           // contains creator and creator-specified LUID
  5809.                                      );
  5810.     tNCT pNCT;
  5811.  
  5812.     debug(F110,"GetTokenForUser szDomain",szDomain,0);
  5813.     debug(F110,"GetTokenForUser szUsername",szUsername,0);
  5814.  
  5815.     // extract a few useful things from our current process token
  5816.     //
  5817.     if (!getSids( &tokenPrivs, &ownerSid,
  5818.                   pPriGroupSid ? NULL : &pPriGroupSid,
  5819.                   userTokenGroups ? NULL : &userTokenGroups,
  5820.                   &logonSessionId )) {
  5821. #ifdef BETADEBUG
  5822.         printf("  getSids() failed\r\n");
  5823. #endif /* BETADEBUG */
  5824.         return(INVALID_HANDLE_VALUE);
  5825.     }
  5826.  
  5827.     // the next sid is really the domain admin -- check the reserved RID at the end
  5828.     AllocateAndInitializeSid( &NTsia, 5, 21, 484763869, 764733703, 1202660629, 500, 0, 0, 0, &iksdSid );
  5829.  
  5830.     // local admins group
  5831.     AllocateAndInitializeSid( &NTsia, 2, 0x20, 0x220, 0, 0, 0, 0, 0, 0, &admingrpSid );
  5832.  
  5833.     // and a crowd pleaser
  5834.     AllocateAndInitializeSid( &NTsia, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSid );
  5835.  
  5836.     // SeCreateTokenPrivilege must be explicitly enabled
  5837.     getPriv( SE_CREATE_TOKEN_NAME );
  5838.  
  5839.     // init guessed arguments
  5840.  
  5841.     // this DACL determines who may mess with the token-to-be
  5842.     newTokenDacl = (PACL) malloc( MAXSIZE );
  5843.     InitializeAcl( newTokenDacl, MAXSIZE, ACL_REVISION );
  5844.     AddAccessAllowedAce( newTokenDacl, ACL_REVISION, TOKEN_ALL_ACCESS, worldSid );
  5845.     AddAccessAllowedAce( newTokenDacl, ACL_REVISION, TOKEN_ALL_ACCESS, iksdSid );
  5846.     AddAccessAllowedAce( newTokenDacl, ACL_REVISION, TOKEN_ALL_ACCESS, admingrpSid );
  5847.     // AddAccessAllowedAce( newTokenDacl, ACL_REVISION, TOKEN_ALL_ACCESS, luserSid );
  5848.  
  5849.     // this SD says that Administrators is the owner of the token itself
  5850.     // (the "owner" below is what gets used as the default owner for, say, files created under this token)
  5851.     newTokenSD.Revision = 1;
  5852.     newTokenSD.Sbz1 = 0;
  5853.     newTokenSD.Control = 4;
  5854.     newTokenSD.Owner = admingrpSid;
  5855.     newTokenSD.Group = 0;
  5856.     newTokenSD.Sacl = 0;
  5857.     newTokenSD.Dacl = newTokenDacl;
  5858.  
  5859.     // this says we wish to create a token that we can impersonate, and which reflects
  5860.     // ongoing changes in permissions/groups/... if the security provider can do that,
  5861.     // and which allows an impersonating server to enable/disable groups or privs
  5862.     sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  5863.     sqos.ImpersonationLevel = SecurityImpersonation;
  5864.     sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
  5865.     sqos.EffectiveOnly = FALSE;
  5866.  
  5867.     // OBJECT_ATTRIBUTES is the NT bog-standard way of passing the name
  5868.     // and security for an object to be created or opened
  5869.     ObjAttr.Length = sizeof(ObjAttr);
  5870.     ObjAttr.RootDirectory = 0;
  5871.     ObjAttr.ObjectName = 0;
  5872.     ObjAttr.Attributes = 0;
  5873.     ObjAttr.SecurityDescriptor = &newTokenSD;
  5874.     ObjAttr.SecurityQualityOfService = &sqos;
  5875.  
  5876.     // primary tokens are usable for CreateProcessAsUser()
  5877.     tokenType = TokenPrimary;
  5878.  
  5879.     // logon session ID
  5880.     // use either the service logon ID, or the LUID extracted from our own token:
  5881.     // sessionLuid = serviceSessionLuid; // this would be the logon session for services
  5882.     sessionLuid = logonSessionId; // this would be the logon session for services
  5883.  
  5884.     // FILETIME format for token expiration time. 2^63-1 means no expiration.
  5885.     // NTLM does not support this -- Kerberos should, but I didn't test it
  5886.     expirationTime.dwLowDateTime = 0xffffffffUL;
  5887.     expirationTime.dwHighDateTime = 0x7fffffffUL;
  5888.  
  5889.     // token user -- the user who will be impersonated or whatever
  5890.     tokenUser.Sid = luserSid;
  5891.     tokenUser.Attributes = 0;
  5892.  
  5893.     // optional: remove our logon SID from processTokenGroups, add logon SID as per session LUID above
  5894.     // or collect group info for account and hand-build group list
  5895.  
  5896.     // optional: filter tokenPrivs
  5897.  
  5898.     // owner SID -- will be stamped on all objects that get created without an explicit SD under our token
  5899.     newOwnerSid = luserSid;
  5900.  
  5901.     // primary group SID -- will be stamped on all objects that get created without an explicit SD under our token
  5902.     newPriGroupSid = pPriGroupSid;
  5903.  
  5904.     // this DACL will be stamped on all objects that get created without an explicit SD under our token
  5905.     newDefaultDacl = (PACL) malloc( MAXSIZE );
  5906.     InitializeAcl( newDefaultDacl, MAXSIZE, ACL_REVISION );
  5907.     AddAccessAllowedAce( newDefaultDacl, ACL_REVISION, MAXDWORD, worldSid );
  5908.  
  5909.  
  5910.     hlib = LoadLibrary( "ntdll.dll" );
  5911.     if ( hlib ) {
  5912.         pNCT = (tNCT) GetProcAddress( hlib, "NtCreateToken" );
  5913.         if ( pNCT )
  5914.         {
  5915.             debug(F100,"calling NtCreateToken()","",0);
  5916.             rc = pNCT( &tokenHandle, &requestedPermissions, &ObjAttr, tokenType,
  5917.                        &sessionLuid, &expirationTime, &tokenUser, userTokenGroups, tokenPrivs,
  5918.                        &newOwnerSid, &newPriGroupSid, &newDefaultDacl, &tokenSource );
  5919.             debug(F111,"NtCreateToken() returns","rc",rc);
  5920.             if ( rc == 0 )
  5921.             {
  5922.                 HANDLE ht = 0;
  5923. #ifdef BETADEBUG
  5924.                 printf( "token handle: %08lXh\n", tokenHandle );
  5925. #endif /* BETADEBUG */
  5926.                 // odd thing: the tokenHandle is unusable ... but it _can_ be
  5927.                 // duplicated with full access. Need to check if this is only
  5928.                 // because we are the owner or whatever!
  5929.                 if ( DuplicateHandle( GetCurrentProcess(), tokenHandle,
  5930.                                       GetCurrentProcess(), &ht, TOKEN_ALL_ACCESS, FALSE, DUPLICATE_CLOSE_SOURCE ) )
  5931.                 {
  5932.                     if (ht != tokenHandle) {
  5933.                       CloseHandle( tokenHandle );
  5934.                       tokenHandle = ht;
  5935. #ifdef BETADEBUG
  5936.                       printf( "dup token handle: %08lXh\n", tokenHandle );
  5937. #endif /* BETADEBUG */
  5938.                     }
  5939.                 }
  5940. #ifdef BETADEBUG
  5941.                 else
  5942.                    printf( "DH(): gle = %lu\n", gle );
  5943. #endif /* BETADEBUG */
  5944.             }
  5945. #ifdef BETADEBUG
  5946.             else {
  5947.                printf( "NCT(): gle = %lu\n", gle );
  5948.                printf( "NCT(): rc = %08lXh\n", rc );
  5949.             }
  5950. #endif /* BETADEBUG */
  5951.         }
  5952.         FreeLibrary( hlib );
  5953.     }
  5954.  
  5955.     if ( luserSid != pSid )
  5956.         free(luserSid);
  5957.  
  5958. #ifdef BETADEBUG
  5959.     printf( "token handle: %08lXh\n", tokenHandle );
  5960. #endif /* BETADEBUG */
  5961.     return(tokenHandle);
  5962. }
  5963.  
  5964.  
  5965. BOOL
  5966. getSids( TOKEN_PRIVILEGES **tokenPrivs, PSID *ownerSid, PSID *priGroupSid, TOKEN_GROUPS **processTokenGroups, LUID *logonSessionId )
  5967. {
  5968.     DWORD needed;
  5969.     HANDLE ht;
  5970.  
  5971.     TOKEN_STATISTICS tstat;
  5972.     TOKEN_OWNER *pto;
  5973.     TOKEN_PRIMARY_GROUP *ptpg;
  5974.     TOKEN_GROUPS *ptg;
  5975.     TOKEN_PRIVILEGES *ptp;
  5976.  
  5977.     debug(F100,"getSids","",0);
  5978.  
  5979.     // open process token
  5980.  
  5981.     if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &ht ) )
  5982.     {
  5983.         if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &ht ) )
  5984.         {
  5985.             DWORD error = gle;
  5986.             if (error != ERROR_CALL_NOT_IMPLEMENTED)
  5987.                 printf("  OpenProcessToken(): gle = %lu\n", error);
  5988.             return FALSE;
  5989.         }
  5990.     }
  5991.  
  5992.     // grab token information
  5993.  
  5994.     // logon session LUID
  5995.     if ( logonSessionId ) {
  5996.         if ( ! GetTokenInformation( ht, TokenStatistics, &tstat, sizeof tstat, &needed ) )
  5997.             printf( "  GetTokenInformation( TokenStatistics ): gle = %lu\n", gle );
  5998.         else
  5999.         {
  6000.             *logonSessionId = tstat.AuthenticationId;
  6001.         }
  6002.     }
  6003.  
  6004.     // token owner
  6005.     if ( ownerSid ) {
  6006.         pto = (TOKEN_OWNER *) malloc( MAXSIZE );
  6007.         if ( ! GetTokenInformation( ht, TokenOwner, pto, MAXSIZE, &needed ) )
  6008.             printf( "  GetTokenInformation( TokenOwner ): gle = %lu\n", gle );
  6009.         else
  6010.         {
  6011.             *ownerSid = (PSID) malloc( MAXSIZE );
  6012.             CopySid( MAXSIZE, *ownerSid, pto->Owner );
  6013.         }
  6014.         free(pto);
  6015.     }
  6016.  
  6017.     // token primary group
  6018.     if ( priGroupSid ) {
  6019.         ptpg = (TOKEN_PRIMARY_GROUP *) malloc( MAXSIZE );
  6020.         if ( ! GetTokenInformation( ht, TokenPrimaryGroup, ptpg, MAXSIZE, &needed ) )
  6021.             printf( "  GetTokenInformation( TokenPrimaryGroup ): gle = %lu\n", gle );
  6022.         else
  6023.         {
  6024.             *priGroupSid = (PSID) malloc( MAXSIZE );
  6025.             CopySid( MAXSIZE, *priGroupSid, ptpg->PrimaryGroup );
  6026.         }
  6027.         free(ptpg);
  6028.     }
  6029.  
  6030.     // token groups
  6031.     if ( processTokenGroups ) {
  6032.         ptg = (TOKEN_GROUPS *) malloc( MAXSIZE );
  6033.         if ( ! GetTokenInformation( ht, TokenGroups, ptg, MAXSIZE, &needed ) )
  6034.             printf( "  GetTokenInformation( TokenGroups ): gle = %lu\n", gle );
  6035.         else
  6036.         {
  6037.             *processTokenGroups = ptg;
  6038.         }
  6039.     }
  6040.  
  6041.     if ( tokenPrivs ) {
  6042.         ptp = (TOKEN_PRIVILEGES *) malloc( MAXSIZE );
  6043.         if ( ! GetTokenInformation( ht, TokenPrivileges, ptp, MAXSIZE, &needed ) )
  6044.             printf( "  GetTokenInformation( TokenPrivileges ): gle = %lu\n", gle );
  6045.         else
  6046.         {
  6047.             *tokenPrivs = ptp;
  6048.         }
  6049.     }
  6050.  
  6051.     CloseHandle( ht );
  6052.     return TRUE;
  6053. }
  6054.  
  6055.  
  6056.  
  6057. const char *formatTime( FILETIME *t )
  6058. {
  6059.     SYSTEMTIME st;
  6060.     DWORD len = MAXSIZE;
  6061.     static char buf[MAXSIZE];
  6062.  
  6063.     if ( t->dwHighDateTime > 0x7fffffffUL ||
  6064.          ( t->dwHighDateTime == 0x7fffffffUL && t->dwLowDateTime == 0xffffffffUL ) )
  6065.     {
  6066.         ckstrncpy( buf, "-none-", MAXSIZE );
  6067.         return buf;
  6068.     }
  6069.  
  6070.     FileTimeToSystemTime( t, &st );
  6071.     GetDateFormat( LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, 0, buf, len );
  6072.     ckstrncat( buf, " ", MAXSIZE );
  6073.     len -= strlen( buf );
  6074.     GetTimeFormat( LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT, &st, 0, &buf[strlen( buf )], len );
  6075.     return buf;
  6076. }
  6077.  
  6078.  
  6079.  
  6080. BOOL
  6081. showToken( HANDLE ht )
  6082. {
  6083.     DWORD needed;
  6084.     DWORD i;
  6085.  
  6086.     TOKEN_SOURCE ts;
  6087.     TOKEN_STATISTICS tstat;
  6088.     TOKEN_OWNER *pto;
  6089.     TOKEN_USER *ptu;
  6090.     TOKEN_PRIMARY_GROUP *ptpg;
  6091.     TOKEN_GROUPS *ptg;
  6092.  
  6093.     // dump token information
  6094.  
  6095.     // creating subsystem
  6096.     if ( ! GetTokenInformation( ht, TokenSource, &ts, sizeof ts, &needed ) )
  6097.         printf( "  GetTokenInformation( TokenSource ): gle = %lu\n", gle );
  6098.     else
  6099.         printf( "  Token source: \"%-8.8s\" (luid = %I64d)\n",
  6100.                 ts.SourceName, ts.SourceIdentifier );
  6101.  
  6102.     // logon session LUID
  6103.     if ( ! GetTokenInformation( ht, TokenStatistics, &tstat, sizeof tstat, &needed ) )
  6104.         printf( "  GetTokenInformation( TokenStatistics ): gle = %lu\n", gle );
  6105.     else
  6106.     {
  6107.         printf( "  Token Statistics:\n" );
  6108.         printf( "    TokenId:            %I64d (%lu-%lu)\n", *( (__int64 *) &tstat.TokenId ),
  6109.                 tstat.TokenId.HighPart, tstat.TokenId.LowPart );
  6110.         printf( "    AuthenticationId:   %I64d (%lu-%lu)\n", *( (__int64 *) &tstat.AuthenticationId ),
  6111.                 tstat.AuthenticationId.HighPart, tstat.AuthenticationId.LowPart );
  6112.         printf( "    ExpirationTime:     %016I64Xh (%s)\n", *( (__int64 *) &tstat.ExpirationTime ),
  6113.                 formatTime( (FILETIME *) &tstat.ExpirationTime ) );
  6114.         printf( "    TokenType:          %d (%s)\n", tstat.TokenType,
  6115.                 tstat.TokenType == 1? "Primary":
  6116.                 ( tstat.TokenType == 2? "Impersonation": "unknown" ) );
  6117.         printf( "    ImpersonationLevel: %d (%s)\n", tstat.ImpersonationLevel,
  6118.                 tstat.ImpersonationLevel == SecurityAnonymous? "Anonymous":
  6119.                 ( tstat.ImpersonationLevel == SecurityIdentification? "Identification":
  6120.                   ( tstat.ImpersonationLevel == SecurityImpersonation? "Impersonation":
  6121.                     ( tstat.ImpersonationLevel == SecurityDelegation? "Delegation": "unknown" ) ) ) );
  6122.         printf( "    DynamicCharged:     %lu bytes\n", tstat.DynamicCharged );
  6123.         printf( "    DynamicAvailable:   %lu bytes\n", tstat.DynamicAvailable );
  6124.         printf( "    GroupCount:         %lu\n", tstat.GroupCount );
  6125.         printf( "    PrivilegeCount:     %lu\n", tstat.PrivilegeCount );
  6126.         printf( "    ModifiedId:         %I64d (%lu-%lu)\n", *( (__int64 *) &tstat.ModifiedId ),
  6127.                 tstat.ModifiedId.HighPart, tstat.ModifiedId.LowPart );
  6128.     }
  6129.  
  6130.     // token owner
  6131.     pto = (TOKEN_OWNER *) malloc( MAXSIZE );
  6132.     if ( ! GetTokenInformation( ht, TokenOwner, pto, MAXSIZE, &needed ) )
  6133.         printf( "  GetTokenInformation( TokenOwner ): gle = %lu\n", gle );
  6134.     else
  6135.     {
  6136.         printf( "  Token owner:\n    " );
  6137.         showSid( 4, pto->Owner );
  6138.         putchar( '\n' );
  6139.     }
  6140.  
  6141.     // token user
  6142.     ptu = (TOKEN_USER *) malloc( MAXSIZE );
  6143.     if ( ! GetTokenInformation( ht, TokenUser, ptu, MAXSIZE, &needed ) )
  6144.         printf( "  GetTokenInformation( TokenUser ): gle = %lu\n", gle );
  6145.     else
  6146.     {
  6147.         printf( "  Token user:\n    " );
  6148.         showSid( 4, ptu->User.Sid );
  6149.         putchar( '\n' );
  6150.     }
  6151.  
  6152.     // token primary group
  6153.     ptpg = (TOKEN_PRIMARY_GROUP *) malloc( MAXSIZE );
  6154.     if ( ! GetTokenInformation( ht, TokenPrimaryGroup, ptpg, MAXSIZE, &needed ) )
  6155.         printf( "  GetTokenInformation( TokenPrimaryGroup ): gle = %lu\n", gle );
  6156.     else
  6157.     {
  6158.         printf( "  Token primary group:\n    " );
  6159.         showSid( 4, ptpg->PrimaryGroup );
  6160.         putchar( '\n' );
  6161.     }
  6162.  
  6163.     // token groups
  6164.     ptg = (TOKEN_GROUPS *) malloc( MAXSIZE );
  6165.     if ( ! GetTokenInformation( ht, TokenGroups, ptg, MAXSIZE, &needed ) )
  6166.         printf( "  GetTokenInformation( TokenGroups ): gle = %lu\n", gle );
  6167.     else
  6168.     {
  6169.         if ( ptg->GroupCount == 0 )
  6170.             printf( "  Token groups: (none)\n" );
  6171.         else
  6172.         {
  6173.             printf( "  Token groups:\n" );
  6174.             for ( i = 0; i < ptg->GroupCount; ++ i )
  6175.             {
  6176.                 printf( "    %08lXh  ", ptg->Groups[i].Attributes );
  6177.                 showSid( 15, ptg->Groups[i].Sid );
  6178.                 putchar( '\n' );
  6179.             }
  6180.         }
  6181.     }
  6182.  
  6183.     free( pto );
  6184.     free( ptu );
  6185.     free( ptpg );
  6186.     free( ptg );
  6187.  
  6188.     return TRUE;
  6189. }
  6190.  
  6191. void showSid( int indent, PSID ps )
  6192. {
  6193.     char textSid[MAX_PATH], user[MAX_PATH], domain[MAX_PATH], buf[MAX_PATH];
  6194.     DWORD sizeUser, sizeDomain;
  6195.     SID_NAME_USE snu;
  6196.     DWORD charsleft;
  6197.     const char *t;
  6198.     const char *sep = "\\"; // separator for domain\user display
  6199.  
  6200.     Sid2Text( ps, textSid, sizeof textSid );
  6201.     fputs( textSid, stdout );
  6202.     charsleft = 78 - indent - strlen( textSid );
  6203.  
  6204.     sizeUser = sizeof user;
  6205.     sizeDomain = sizeof domain;
  6206.     if ( ! LookupAccountSid( NULL, ps, user, &sizeUser, domain, &sizeDomain, &snu ) )
  6207.     {
  6208.         DWORD rc = gle;
  6209.  
  6210.         if ( IsLogonSid( ps ) )
  6211.             strcpy( buf, "(interactive logon session SID)" );
  6212.         else
  6213.             _snprintf( buf, sizeof(buf)-1, "[LAS(): gle = %lu]", rc );
  6214.         if ( strlen( buf ) > charsleft )
  6215.             printf( "\n%*s", indent, "" );
  6216.         else
  6217.             putchar( ' ' );
  6218.         fputs( buf, stdout );
  6219.         return;
  6220.     }
  6221.  
  6222.     switch ( snu )
  6223.     {
  6224.     case SidTypeUser:
  6225.         t = "user";
  6226.         break;
  6227.     case SidTypeGroup:
  6228.         t = "group";
  6229.         break;
  6230.     case SidTypeDomain:
  6231.         t = "domain";
  6232.         break;
  6233.     case SidTypeAlias:
  6234.         t = "alias";
  6235.         break;
  6236.     case SidTypeWellKnownGroup:
  6237.         t = "well-known group";
  6238.         break;
  6239.     case SidTypeDeletedAccount:
  6240.         t = "deleted";
  6241.         break;
  6242.     case SidTypeInvalid:
  6243.         t = "invalid";
  6244.         break;
  6245.     case SidTypeUnknown:
  6246.         t = "unknown";
  6247.         break;
  6248. #ifndef _M_ALPHA
  6249. #ifndef _M_PPC
  6250.     case SidTypeComputer:
  6251.         t = "computer";
  6252.         break;
  6253. #endif /* _M_PPC */
  6254. #endif /* _M_ALPHA */
  6255.     default:
  6256.         t = "*?unknown?*";
  6257.         break;
  6258.     }
  6259.  
  6260.     if ( domain[0] == '\0' || user[0] == '\0' )
  6261.         sep = "";
  6262.  
  6263.     _snprintf( buf, sizeof(buf)-1, "\"%s%s%s\" (%s)", domain, sep, user, t );
  6264.     if ( strlen( buf ) > charsleft )
  6265.         printf( "\n%*s", indent, "" );
  6266.     else
  6267.         putchar( ' ' );
  6268.     fputs( buf, stdout );
  6269. }
  6270.  
  6271.  
  6272.  
  6273. BOOL IsLocalSid( PSID ps )
  6274. {
  6275.     static PSID pComparisonSid = NULL;
  6276.  
  6277.     if ( pComparisonSid == NULL )
  6278.     {
  6279.         // build "BUILTIN\LOCAL" SID for comparison: S-1-2-0
  6280.         SID_IDENTIFIER_AUTHORITY sia = SECURITY_LOCAL_SID_AUTHORITY;
  6281.         AllocateAndInitializeSid( &sia, 1, 0, 0, 0, 0, 0, 0, 0, 0, &pComparisonSid );
  6282.     }
  6283.  
  6284.     return EqualSid( ps, pComparisonSid );
  6285. }
  6286.  
  6287.  
  6288.  
  6289. BOOL IsInteractiveSid( PSID ps )
  6290. {
  6291.     static PSID pComparisonSid = NULL;
  6292.  
  6293.     if ( pComparisonSid == NULL )
  6294.     {
  6295.         // build "BUILTIN\LOCAL" SID for comparison: S-1-5-4
  6296.         SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY; // "-5-"
  6297.         AllocateAndInitializeSid( &sia, 1, 4, 0, 0, 0, 0, 0, 0, 0, &pComparisonSid );
  6298.     }
  6299.  
  6300.     return EqualSid( ps, pComparisonSid );
  6301. }
  6302.  
  6303.  
  6304.  
  6305. BOOL IsLogonSid( PSID ps )
  6306. {
  6307.     static SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  6308.  
  6309.     // a logon SID has: sia = 5, subauth count = 3, first subauth = 5
  6310.     // the following three lines test these three conditions
  6311.     if ( ! memcmp( GetSidIdentifierAuthority( ps ), &sia, sizeof sia )  && // is sia == 5?
  6312.          *GetSidSubAuthorityCount( ps ) == 3                                                            && // is subauth count == 3?
  6313.          *GetSidSubAuthority( ps, 0 ) == 5                                                                      )  // first subauth == 5?
  6314.         return TRUE;
  6315.     else
  6316.         return FALSE;
  6317. }
  6318.  
  6319.  
  6320.  
  6321. // nearly straight from the SDK
  6322. BOOL Sid2Text( PSID ps, char *buf, int bufSize )
  6323. {
  6324.     PSID_IDENTIFIER_AUTHORITY psia;
  6325.     DWORD dwSubAuthorities;
  6326.     DWORD dwSidRev = SID_REVISION;
  6327.     DWORD i;
  6328.     int n, size;
  6329.     char *p;
  6330.  
  6331.     // Validate the binary SID.
  6332.  
  6333.     if ( ! IsValidSid( ps ) )
  6334.         return FALSE;
  6335.  
  6336.     // Get the identifier authority value from the SID.
  6337.  
  6338.     psia = GetSidIdentifierAuthority( ps );
  6339.  
  6340.     // Get the number of subauthorities in the SID.
  6341.  
  6342.     dwSubAuthorities = *GetSidSubAuthorityCount( ps );
  6343.  
  6344.     // Compute the buffer length.
  6345.     // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
  6346.  
  6347.     size = 15 + 12 + ( 12 * dwSubAuthorities ) + 1;
  6348.  
  6349.     // Check input buffer length.
  6350.     // If too small, indicate the proper size and set last error.
  6351.  
  6352.     if ( bufSize < size )
  6353.     {
  6354.         SetLastError( ERROR_INSUFFICIENT_BUFFER );
  6355.         return FALSE;
  6356.     }
  6357.  
  6358.     // Add 'S' prefix and revision number to the string.
  6359.  
  6360.     size = sprintf( buf, "S-%lu-", dwSidRev );
  6361.     p = buf + size;
  6362.  
  6363.     // Add SID identifier authority to the string.
  6364.  
  6365.     if ( psia->Value[0] != 0 || psia->Value[1] != 0 )
  6366.     {
  6367.         n = sprintf( p, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  6368.                      (USHORT) psia->Value[0], (USHORT) psia->Value[1],
  6369.                      (USHORT) psia->Value[2], (USHORT) psia->Value[3],
  6370.                      (USHORT) psia->Value[4], (USHORT) psia->Value[5] );
  6371.         size += n;
  6372.         p += n;
  6373.     }
  6374.     else
  6375.     {
  6376.         n = sprintf( p, "%lu", ( (ULONG) psia->Value[5] ) +
  6377.                      ( (ULONG) psia->Value[4] << 8 ) + ( (ULONG) psia->Value[3] << 16 ) +
  6378.                      ( (ULONG) psia->Value[2] << 24 ) );
  6379.         size += n;
  6380.         p += n;
  6381.     }
  6382.  
  6383.     // Add SID subauthorities to the string.
  6384.  
  6385.     for ( i = 0; i < dwSubAuthorities; ++ i )
  6386.     {
  6387.         n = sprintf( p, "-%lu", *GetSidSubAuthority( ps, i ) );
  6388.         size += n;
  6389.         p += n;
  6390.     }
  6391.  
  6392.     return TRUE;
  6393. }
  6394.  
  6395. BOOL
  6396. getPriv( const char *privName )
  6397. {
  6398.     BOOL rc;
  6399.     HANDLE hToken;
  6400.     LUID privValue;
  6401.     TOKEN_PRIVILEGES tkp;
  6402.  
  6403.     if ( ! OpenProcessToken( GetCurrentProcess(),
  6404.                              TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) {
  6405.         return FALSE;
  6406.     }
  6407.  
  6408.     if ( !LookupPrivilegeValue( NULL, privName, &privValue ) )
  6409.     {
  6410.         CloseHandle( hToken );
  6411.         return FALSE;
  6412.     }
  6413.  
  6414.     tkp.PrivilegeCount = 1;
  6415.     tkp.Privileges[0].Luid = privValue;
  6416.     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  6417.  
  6418.     rc = !! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL );
  6419.     CloseHandle( hToken );
  6420.     return rc;
  6421. }
  6422. #endif /* NTCREATETOKEN */
  6423. #endif /* NT */
  6424.  
  6425. /*  Z V U S E R  --  Verify user, Returns 1 if user OK, 0 otherwise.  */
  6426.  
  6427. int
  6428. zvuser(username) char *username; {
  6429. #ifdef NT
  6430.     int rc = 0;
  6431.     DWORD dwSid = 0;
  6432.     DWORD dwName = 0;
  6433.     DWORD LastError;
  6434.     char buf[4096], *p, *name;
  6435.  
  6436.     if (logged_in)
  6437.         return(0);
  6438.  
  6439. #ifdef CKSYSLOG
  6440.     if (ckxsyslog && ckxlogging) {
  6441.         sprintf(buf, "login: user %s",username);
  6442.         cksyslog(SYSLG_LI, 1, buf, NULL, NULL);
  6443.     }
  6444. #endif /* CKSYSLOG */
  6445.  
  6446.     /* Cleanup from previous calls (if any) */
  6447.  
  6448.     if ( !p_CreateEnvironmentBlock || !p_DestroyEnvironmentBlock ||
  6449.          !p_LoadUserProfileA || !p_UnloadUserProfileA ) {
  6450.  
  6451.         if ( !hUserEnv )
  6452.             hUserEnv = LoadLibrary("userenv.dll");
  6453.         if ( hUserEnv ) {
  6454.             (FARPROC) p_CreateEnvironmentBlock =
  6455.                 GetProcAddress( hUserEnv, "CreateEnvironmentBlock" );
  6456.             (FARPROC) p_DestroyEnvironmentBlock =
  6457.                 GetProcAddress( hUserEnv, "DestroyEnvironmentBlock" );
  6458.             (FARPROC) p_LoadUserProfileA =
  6459.                 GetProcAddress( hUserEnv, "LoadUserProfileA" );
  6460.             (FARPROC) p_UnloadUserProfileA =
  6461.                 GetProcAddress( hUserEnv, "UnloadUserProfileA" );
  6462.         }
  6463.     }
  6464.  
  6465.     if ( hLoggedOn != INVALID_HANDLE_VALUE ) {
  6466.         debug(F110,"zvuser()","calling RevertToSelf()",0);
  6467.         RevertToSelf();
  6468.  
  6469.         if ( p_UnloadUserProfileA && profinfo.hProfile )
  6470.             p_UnloadUserProfileA(hLoggedOn, profinfo.hProfile);
  6471.         memset(&profinfo,0,sizeof(profinfo));
  6472.         profinfo.dwSize = sizeof(profinfo);
  6473.  
  6474.         if ( p_DestroyEnvironmentBlock && pEnvBlock ) {
  6475.             p_DestroyEnvironmentBlock(pEnvBlock);
  6476.             pEnvBlock = NULL;
  6477.         }
  6478.         CloseHandle(hLoggedOn);
  6479.         hLoggedOn = INVALID_HANDLE_VALUE;
  6480.     }
  6481.     if (pSid) {
  6482.         free(pSid);
  6483.         pSid = NULL;
  6484.     }
  6485.     if (pPriGroupSid) {
  6486.         free(pPriGroupSid);
  6487.         pPriGroupSid = NULL;
  6488.     }
  6489.     if (pTokenGroups) {
  6490.         int i;
  6491.         for (i=0 ; i < pTokenGroups->GroupCount; i++ )
  6492.             free(pTokenGroups->Groups[i].Sid);
  6493.         free(pTokenGroups);
  6494.         pTokenGroups = NULL;
  6495.     }
  6496.  
  6497.     if ( pReferenceDomainName ) {
  6498.         free(pReferenceDomainName);
  6499.         pReferenceDomainName = NULL;
  6500.     }
  6501.     if ( pPDCName ) {
  6502.         free(pPDCName);
  6503.         pPDCName = NULL;
  6504.     }
  6505.  
  6506.     /* Now start the login process */
  6507.     debug(F110,"zvuser() username",username,0);
  6508.     if ( ( !stricmp("anonymous",username)
  6509. #ifdef COMMENT
  6510.            || !stricmp("guest",username) || !stricmp("ftp",username)
  6511. #endif /* COMMENT */
  6512.            )) {
  6513.         if ( ckxanon )
  6514.             name = anonacct ? anonacct : "guest";
  6515.         else {
  6516. #ifdef CKSYSLOG
  6517.             if (ckxsyslog && ckxlogging) {
  6518.                 sprintf(buf,
  6519.                        "login: anonymous login not allowed: %s",
  6520.                        clienthost ? clienthost : "(unknown host)"
  6521.                        );
  6522.                 cksyslog(SYSLG_LI, 0, buf, NULL, NULL);
  6523.  
  6524.             }
  6525. #endif /* CKSYSLOG */
  6526.             return(0);
  6527.         }
  6528.     }
  6529.     else
  6530.         name = username;
  6531.  
  6532.     debug(F110,"zvuser() name",name,0);
  6533.  
  6534.     if ( name == NULL || name[0] == '\0' )
  6535.         return(0);
  6536.  
  6537.     if ( !isWin95() ) {
  6538.         for (p = name; *p && (*p != '\\') ; p++) ;
  6539.         if ( *p ) {
  6540.             /* a domain has already been specified */
  6541.             strcpy(buf,name);
  6542.         } else if (iks_domain && iks_domain[0]) {
  6543.             sprintf(buf,"%s\\%s",iks_domain,name);
  6544.         } else {
  6545.             strcpy(buf,name);
  6546.         }
  6547.         rc = LookupAccountName( NULL,buf,
  6548.                                 pSid,&dwSid,pReferenceDomainName,&dwName,
  6549.                                 &SidNameUse);
  6550.         pSid = (PSID) malloc(dwSid+1);
  6551.         if ( !pSid )
  6552.             return(0);
  6553.         pReferenceDomainName = (CHAR *) malloc(dwName+1);
  6554.         if ( !pReferenceDomainName ) {
  6555.             free(pSid);
  6556.             pSid = NULL;
  6557.             return(0);
  6558.         }
  6559.         rc = LookupAccountName( NULL,buf,
  6560.                                 pSid,&dwSid,pReferenceDomainName,
  6561.                                 &dwName,&SidNameUse);
  6562.         if ( rc && (SidNameUse == SidTypeDomain
  6563. #ifndef _M_ALPHA
  6564. #ifndef _M_PPC
  6565.                      || SidNameUse == SidTypeComputer
  6566. #endif /* _M_PPC */
  6567. #endif /* _M_ALPHA */
  6568.                      ) )
  6569.         {
  6570.             /* Username equals Machine name */
  6571.             sprintf(buf,"%s\\%s",name,name);
  6572.             debug(F110,"zvuser SidNameUse == SidTypeDomain",buf,0);
  6573.             free(pSid);
  6574.             pSid = NULL;
  6575.             free(pReferenceDomainName);
  6576.             pReferenceDomainName = NULL;
  6577.             dwSid = dwName = 0;
  6578.             LookupAccountName( NULL,buf,
  6579.                                pSid,&dwSid,pReferenceDomainName,&dwName,
  6580.                                &SidNameUse);
  6581.             pSid = (PSID) malloc(dwSid+1);
  6582.             if ( !pSid )
  6583.                 return(0);
  6584.             pReferenceDomainName = (CHAR *) malloc(dwName+1);
  6585.             if ( !pReferenceDomainName ) {
  6586.                 free(pSid);
  6587.                 pSid = NULL;
  6588.                 return(0);
  6589.             }
  6590.             rc = LookupAccountName( NULL,buf,
  6591.                                     pSid,&dwSid,pReferenceDomainName,
  6592.                                     &dwName,&SidNameUse);
  6593.         }
  6594.         if ( !rc ) {
  6595.             LastError = GetLastError();
  6596.             debug(F111,"zvuser","LookupAccount()",LastError);
  6597.             if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  6598.                                 NULL,
  6599.                                 LastError,
  6600.                                 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
  6601.                                 buf,
  6602.                                 4096,
  6603.                                 (va_list *) NULL
  6604.                                 ) )
  6605.             {
  6606.                 printf("\r\n  (%s) %s\r\n",name,buf);
  6607.             }
  6608.             free(pSid);
  6609.             pSid = NULL;
  6610.             free(pReferenceDomainName);
  6611.             pReferenceDomainName = NULL;
  6612.  
  6613.             if ( name != anonacct ) {
  6614.                 for ( p = name; *p ; p++ ) {
  6615.                     if ( *p == '\\' ) {
  6616.                         *p = '\0';
  6617.                         makestr(&pReferenceDomainName,name);
  6618.                         p++;
  6619.                         strcpy(buf,p);
  6620.                         strcpy(name,buf);
  6621.                         break;
  6622.                     }
  6623.                 }
  6624.                 if ( !pReferenceDomainName && iks_domain )
  6625.                     makestr(&pReferenceDomainName,iks_domain);
  6626.             }
  6627.             return(0);
  6628.         }
  6629.         pReferenceDomainName[dwName] = '\0';
  6630.         debug(F110,"zvuser() Reference Domain Name",pReferenceDomainName,0);
  6631.  
  6632.         /* Strip off the domain if it is part of the name */
  6633.         if ( name != anonacct ) {
  6634.             for ( p=name; *p ; p++ ) {
  6635.                 if ( *p == '\\' ) {
  6636.                     p++;
  6637.                     strcpy(buf,p);
  6638.                     strcpy(name,buf);
  6639.                     break;
  6640.                 }
  6641.             }
  6642.         }
  6643.     } else {    /* Windows 95/98 */
  6644.         if ( name != anonacct ) {
  6645.             for ( p = name; *p ; p++ ) {
  6646.                 if ( *p == '\\' ) {
  6647.                     *p = '\0';
  6648.                     makestr(&pReferenceDomainName,name);
  6649.                     p++;
  6650.                     strcpy(buf,p);
  6651.                     strcpy(name,buf);
  6652.                     break;
  6653.                 }
  6654.             }
  6655.             if (!pReferenceDomainName) {
  6656.                 if (iks_domain)
  6657.                     makestr(&pReferenceDomainName,iks_domain);
  6658.                 else if ( IsSSPLogonAvail() )
  6659.                     makestr(&pReferenceDomainName,SSPLogonDomain());
  6660.             }
  6661.         }
  6662.     }
  6663.     if ( name == anonacct )
  6664.         strcpy(uidbuf,"anonymous");
  6665.     else if (uidbuf != name)
  6666.         ckstrncpy((char *)uidbuf,(char *)name,UIDBUFLEN);
  6667. #else /* NT */
  6668.     char * name;
  6669.  
  6670.     debug(F110,"zvuser() username",username,0);
  6671.     if ( !stricmp("anonymous",username) && ckxanon && anonacct )
  6672.         name = anonacct;
  6673.     else
  6674.         name = username;
  6675.  
  6676.     debug(F110,"zvuser() name",name,0);
  6677.  
  6678.     if ( name == anonacct )
  6679.         strcpy(uidbuf,"anonymous");
  6680.     else if (uidbuf != name) {
  6681.         ckstrncpy((char *)uidbuf,(char *)name,UIDBUFLEN);
  6682.     }
  6683. #endif /* NT */
  6684.     debug(F100,"zvuser() success","",0);
  6685.     return(1);
  6686. }
  6687.  
  6688. /*  Z V P A S S  --  Verify password; returns 1 if OK, 0 otherwise  */
  6689.  
  6690. int
  6691. zvpass(passwd) char *passwd; {
  6692.     int rc = 0;
  6693.     int ntlm=0;
  6694.     char * uid, * pwd;
  6695.     char buf[4096];
  6696.     char username[256];
  6697. #ifdef IKSDB
  6698.     extern int ikdbopen;
  6699.     extern unsigned long mydbslot;
  6700. #endif /* IKSDB */
  6701. #ifdef NT
  6702.     DWORD LastError, LogonUserError;
  6703. #endif /* NT */
  6704. #ifdef CK_SRP
  6705.     int srp_verified = 0;
  6706. #endif /* CK_SRP */
  6707.  
  6708.     debug(F110,"zvpass uidbuf",uidbuf,0);
  6709.     if (!stricmp("anonymous",uidbuf)) {
  6710.         /* Anonymous login */
  6711.  
  6712.         if ( !ckxanon ) {
  6713.             printf("Login unavailable: anonymous login refused.\r\n");
  6714.             debug(F110,"zvpass()","invalid anonymous login refused",0);
  6715.             return(0);
  6716.         }
  6717.  
  6718.         if (!passwd[0]) {
  6719.             printf("Login refused: e-mail address must be provided as password.\r\n");
  6720. #ifdef CKSYSLOG
  6721.             if (ckxsyslog && ckxlogging) {
  6722.                 char buf[1024];
  6723.                 sprintf(buf,"login: anonymous guests must specify a password");
  6724.                 cksyslog(SYSLG_LI, 0, buf, NULL, NULL);
  6725.             }
  6726. #endif /* CKSYSLOG */
  6727.             return(0);
  6728.         }
  6729.  
  6730.         uid = anonacct ? anonacct : "guest";
  6731.         pwd = "";
  6732.         ckstrncpy(guestpass,passwd,GUESTPASS_LEN);
  6733.         isguest = 1;
  6734.     } else {
  6735.         uid = uidbuf;
  6736.         pwd = passwd ? passwd : "";
  6737.         guestpass[0] = '\0';
  6738.         isguest = 0;
  6739.     }
  6740.  
  6741. #ifdef NT
  6742.     if (pReferenceDomainName &&
  6743.         !ckstrcmp(uid,pReferenceDomainName,strlen(pReferenceDomainName),0) &&
  6744.          strlen(uid) != strlen(pReferenceDomainName) )
  6745.         uid = uid + strlen(pReferenceDomainName) + 1;
  6746. #endif /* NT */
  6747.  
  6748.     debug(F110,"zvpass",isguest ? guestpass : (pwd ? "xxxxxx" : "(null)"),isguest);
  6749.  
  6750. #ifdef NT
  6751.     if ( isWin95() ) {
  6752.         if (isguest || (ck_tn_auth_valid() == AUTH_VALID) && !pwd[0])
  6753.             /* already authenticated */
  6754.             goto logged_in;
  6755.  
  6756.         if (IsSSPLogonAvail()) {
  6757.             BOOL SSPLogonUser( LPTSTR DomainName, LPTSTR UserName, LPTSTR Password );
  6758.             const char * sspi_errstr(SECURITY_STATUS ss);
  6759.  
  6760.             LogonUserError = GetLastError();
  6761.             rc = SSPLogonUser(pReferenceDomainName?pReferenceDomainName:".",uid,pwd);
  6762.             if ( !rc ) { /* Failure */
  6763.                 extern int SSPLogonError;
  6764.                 printf("\r\n  %s\r\n",sspi_errstr(SSPLogonError));
  6765. #ifdef CKSYSLOG
  6766.                 if (ckxsyslog >= SYSLG_LI && ckxlogging)
  6767.                     cksyslog(SYSLG_LI, 0, "LOGIN FAILURE",uid,
  6768.                               (char *)sspi_errstr(SSPLogonError));
  6769. #endif /* CKSYSLOG */
  6770.                 debug(F110,"zvpass","SSPLogonUser failed",0);
  6771.                 return(0);
  6772.             } else {
  6773.                 ntlm_impersonate();
  6774.             }
  6775.         } else {
  6776.             debug(F110,"zvpass","SSPLogon not available",0);
  6777. #ifdef CK_SRP
  6778.             rc = t_verifypw (uid, pwd);
  6779. #ifndef PRE_SRP_1_4_4
  6780.             if (rc > -1)
  6781.                 endtpent();
  6782. #endif /* PRE_SRP_1_4_4 */
  6783.             if (rc > 0) {
  6784.                 srp_verified = 1;
  6785.                 goto logged_in;
  6786.             }
  6787. #endif /* CK_SRP */
  6788.  
  6789.             printf("\r\n  Login denied\r\n");
  6790. #ifdef CKSYSLOG
  6791.             if (ckxsyslog >= SYSLG_LI && ckxlogging)
  6792.                 cksyslog(SYSLG_LI, 0, "LOGIN FAILURE",uid,
  6793.                           "Login denied");
  6794. #endif /* CKSYSLOG */
  6795.             return(0);
  6796.         }
  6797.     } else {
  6798.         /* Get the User Info now so that we have the group list for the call */
  6799.         /* to CreateTokenForUser()                                           */
  6800.         GetUserInfo(pReferenceDomainName, uid);
  6801.  
  6802.         if (!isguest && (ck_tn_auth_valid() == AUTH_VALID) && !pwd[0]) {
  6803.             /* already authenticated */
  6804.  
  6805.             switch (ck_tn_authenticated()) {
  6806.             case AUTHTYPE_NTLM: {
  6807.                 /* If we authenticated by NTLM SSPI then we do not have a Token yet    */
  6808.                 /* So get one from the current thread after we impersonate the user    */
  6809.                 HANDLE hThread, hThreadToken;
  6810.                 DWORD foo;
  6811.  
  6812.         if ( !p_DuplicateTokenEx ) {
  6813.             if ( !hAdvApi )
  6814.             hAdvApi = LoadLibrary("advapi32.dll");
  6815.             if ( hAdvApi ) {
  6816.             (FARPROC) p_DuplicateTokenEx =
  6817.                 GetProcAddress( hAdvApi, "DuplicateTokenEx" );
  6818.             }
  6819.         }
  6820.  
  6821.         ntlm_impersonate();
  6822.                 hThread = GetCurrentThread();
  6823.                 foo = OpenThreadToken(hThread, TOKEN_ALL_ACCESS, FALSE, &hThreadToken );
  6824.                 debug(F111,"zvpass","OpenThreadToken()",foo ? 0 : GetLastError());
  6825.         if ( p_DuplicateTokenEx ) {
  6826.             foo = p_DuplicateTokenEx(hThreadToken, MAXIMUM_ALLOWED, NULL, 
  6827.                          SecurityImpersonation,
  6828.                          TokenPrimary, &hLoggedOn);
  6829.             debug(F111,"zvpass","DuplicateTokenEx()",foo ? 0 : GetLastError());
  6830.         }
  6831.                 CloseHandle(hThreadToken);
  6832.                 CloseHandle(hThread);
  6833.                 ntlm = 1;
  6834.                 break;
  6835.             }
  6836. #ifdef NTCREATETOKEN
  6837.             case AUTHTYPE_KERBEROS_V4:
  6838.             case AUTHTYPE_KERBEROS_V5:
  6839.             case AUTHTYPE_SRP:
  6840.                 hLoggedOn = CreateTokenForUser(uid,pReferenceDomainName,
  6841.                                                 pSid,pPriGroupSid,pTokenGroups);
  6842.                 break;
  6843.  
  6844.             case AUTHTYPE_NULL:
  6845.             case AUTHTYPE_AUTO:
  6846. #ifdef CK_SSL
  6847.                 if ((ssl_active_flag && ssl_get_subject_name(ssl_con))||
  6848.                      (tls_active_flag && ssl_get_subject_name(tls_con)))
  6849.                 {
  6850.                     hLoggedOn = CreateTokenForUser(uid,pReferenceDomainName,
  6851.                                                     pSid,pPriGroupSid,pTokenGroups);
  6852.                     break;
  6853.                 }
  6854. #endif /* CK_SSL */
  6855. #endif /* NTCREATETOKEN */
  6856.             default:
  6857.                 rc = LogonUser(uid,pReferenceDomainName,pwd,
  6858.                                 LOGON32_LOGON_INTERACTIVE,
  6859.                                 LOGON32_PROVIDER_DEFAULT,
  6860.                                 &hLoggedOn);
  6861.                 if ( !rc ) {
  6862.                     debug(F110,"zvpass","AUTH_VALID login failed",0);
  6863.  
  6864.                     LastError = GetLastError();
  6865.                     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  6866.                                        NULL,
  6867.                                        LastError,
  6868.                                        MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
  6869.                                        buf,
  6870.                                        4096,
  6871.                                        (va_list *) NULL
  6872.                                        ) )
  6873.                     {
  6874.                         printf("\r\n  %s\r\n",buf);
  6875. #ifdef CKSYSLOG
  6876.                         if (ckxsyslog >= SYSLG_LI && ckxlogging)
  6877.                             cksyslog(SYSLG_LI, 0, "LOGIN FAILURE",uid,buf);
  6878. #endif /* CKSYSLOG */
  6879.                     }
  6880.                     return(0);
  6881.                 }
  6882.             }
  6883.         } else {
  6884.             rc = LogonUser(uid,
  6885.                             pReferenceDomainName,
  6886.                             pwd,
  6887.                             LOGON32_LOGON_INTERACTIVE,
  6888.                             LOGON32_PROVIDER_DEFAULT,
  6889.                             &hLoggedOn);
  6890.             debug(F111,"LogonUser()","rc",rc);
  6891.             if ( !rc ) {
  6892.                 LastError = GetLastError();
  6893.                 debug(F111,"zvpass LogonUser() failed",uid,LastError);
  6894.  
  6895.                 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  6896.                                    NULL,
  6897.                                    LastError,
  6898.                                    MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
  6899.                                    buf,
  6900.                                    4096,
  6901.                                    (va_list *) NULL
  6902.                                    ) )
  6903.                 {
  6904.                     printf("\r\n  %s\r\n",buf);
  6905. #ifdef CKSYSLOG
  6906.                         if (ckxsyslog >= SYSLG_LI && ckxlogging)
  6907.                             cksyslog(SYSLG_LI, 0, "LOGIN FAILURE",uid,buf);
  6908. #endif /* CKSYSLOG */
  6909.                 }
  6910.                 return(0);
  6911.             }
  6912.         }
  6913.  
  6914.         /* Get the user's profile and environment information */
  6915.         /* If we have a Token for the user, then attempt to retrieve the  */
  6916.         /* user's profile (including home directory) and the Environment  */
  6917.         /* variables.  Be sure to do this before we Impersonate the user  */
  6918.         if ( p_LoadUserProfileA ) {
  6919.             profinfo.dwFlags = PI_NOUI;
  6920.             profinfo.lpUserName = uid;
  6921.             profinfo.lpServerName = pPDCName;
  6922.  
  6923.             debug(F100,"calling LoadUserProfileA()","",0);
  6924.             rc = p_LoadUserProfileA(hLoggedOn,&profinfo);
  6925.             debug(F111,"LoadUserProfileA() returns","rc",rc);
  6926.             LastError = GetLastError();
  6927.             if ( !rc && LastError )
  6928.             {
  6929.                 if ( LastError != ERROR_INVALID_HANDLE &&
  6930.                      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  6931.                                     NULL,
  6932.                                     LastError,
  6933.                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
  6934.                                     buf,
  6935.                                     4096,
  6936.                                     (va_list *) NULL
  6937.                                     ) )
  6938.                 {
  6939.                     printf("\r\n  Profile not loaded: %s\r\n",buf);
  6940. #ifdef CKSYSLOG
  6941.                     if (ckxsyslog >= SYSLG_LI && ckxlogging)
  6942.                         cksyslog(SYSLG_LI, 0, "PROFILE LOAD FAILURE",uid,buf);
  6943. #endif /* CKSYSLOG */
  6944.                 }
  6945.                 else {
  6946. #ifdef BETATEST
  6947.                     printf("\r\nLoadUserProfile Error: Invalid Handle\r\n");
  6948. #endif /* BETATEST */
  6949. #ifdef COMMENT
  6950. #ifdef CKSYSLOG
  6951.                     if (ckxsyslog >= SYSLG_LI && ckxlogging) {
  6952.                         sprintf(buf,"LoadUserProfile() Error = %d",LastError);
  6953.                         cksyslog(SYSLG_LI, 0, "PROFILE LOAD FAILURE",uid,buf);
  6954.                     }
  6955. #endif /* CKSYSLOG */
  6956. #endif /* COMMENT */
  6957.                 }
  6958.                 debug(F111,"zvpass","LoadUserProfile failed",LastError);
  6959.             }
  6960.         }
  6961.  
  6962.         if ( p_CreateEnvironmentBlock ) {
  6963.             debug(F100,"calling CreateEnvironmentBlock()","",0);
  6964.             rc = p_CreateEnvironmentBlock(&pEnvBlock,hLoggedOn,0);
  6965.             debug(F111,"CreateEnvironmentBlock() returns","rc",rc);
  6966.             if ( rc ) {
  6967.                 char buf[1024];
  6968.                 unsigned char *p, *q;
  6969.                 unsigned short ch;
  6970.                 int i;
  6971.  
  6972.                 q = (char *) &ch;
  6973.                 p = (char *) pEnvBlock;
  6974.                 q[0] = p[0];
  6975.                 q[1] = p[1];
  6976.                 if ( ch ) {
  6977.                     i = 0;
  6978.                     buf[0] = '\0';
  6979.                     do {
  6980.                         if ( ch ) {
  6981.                             if ( ch >= 256 )
  6982.                                 buf[i] = ((ch / 256) & 0xFF);
  6983.                             else
  6984.                                 buf[i] = (ch & 0xFF);
  6985.                             i++;
  6986.                         } else {
  6987.                             buf[i] = '\0';
  6988.                             if ( buf[0] )
  6989.                                 _putenv(buf);
  6990.                             i = 0;
  6991.                         }
  6992.                         p += 2;
  6993.                         q[0] = p[0];
  6994.                         q[1] = p[1];
  6995.                     } while ( !((i == 0) && (ch == 0) ) );
  6996.                 }
  6997.             } else
  6998.                 pEnvBlock = NULL;
  6999.         }
  7000.  
  7001.         if ( !ntlm ) {
  7002.             /* Impersonate the user */
  7003.             debug(F100,"calling ImpersonateLoggedOnUser()","",0);
  7004.             rc = ImpersonateLoggedOnUser(hLoggedOn);
  7005.             debug(F111,"ImpersonateLoggedOnUser() returns","rc",rc);
  7006.             if ( !rc ) {
  7007.                 LastError = GetLastError();
  7008.                 if ( LastError != ERROR_INVALID_HANDLE &&
  7009.                      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  7010.                                     NULL,
  7011.                                     LastError,
  7012.                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
  7013.                                     buf,
  7014.                                     4096,
  7015.                                     (va_list *) NULL
  7016.                                     ) )
  7017.                 {
  7018.                     printf("\r\n  %s\r\n",buf);
  7019. #ifdef CKSYSLOG
  7020.                     if (ckxsyslog >= SYSLG_LI && ckxlogging)
  7021.                         cksyslog(SYSLG_LI, 0, "LOGIN FAILURE",uid,buf);
  7022. #endif /* CKSYSLOG */
  7023.                 } else {
  7024. #ifdef BETATEST
  7025. #endif /* BETATEST */
  7026. #ifdef CKSYSLOG
  7027.                     if (ckxsyslog >= SYSLG_LI && ckxlogging) {
  7028.                         sprintf(buf,"ImpersonateLoggedOnUser() Error = %d",LastError);
  7029.                         cksyslog(SYSLG_LI, 0, "LOGIN FAILURE",uid,buf);
  7030.                     }
  7031. #endif /* CKSYSLOG */
  7032.                 }
  7033.                 debug(F111,"zvpass","ImpersonateLoggedOnUser failed",LastError);
  7034.                 return(0);
  7035.             }
  7036.         }
  7037.     }
  7038.   logged_in:
  7039.     debug(F110,"zvpass()","logged_in",0);
  7040.     logged_in = 1;
  7041.  
  7042.     if ( HomeDir[0] ) {
  7043.         int i;
  7044.  
  7045.         ckstrncpy(homedir,HomeDir,CKMAXPATH+1);
  7046. #ifdef NT
  7047.         GetShortPathName(homedir,homedir,CKMAXPATH);
  7048. #endif /* NT */
  7049.  
  7050.         /* we know have the directory, but need to make it consistent */
  7051.         /* with all of the other Kermit directory variables: forward  */
  7052.         /* slashes and a trailing slash.                              */
  7053.         i = strlen(homedir)-1;
  7054.         if ( !(ISDIRSEP(homedir[i])) ) {
  7055.             homedir[i+1] = '/';
  7056.             homedir[i+2] = NUL;
  7057.         }
  7058.         for (i-- ; i >= 0 ; i--) {
  7059.             if ( homedir[i] == '\\' )
  7060.                 homedir[i] = '/';
  7061.         }
  7062.     } else
  7063.         ckstrncpy(homedir,zgtdir(),CKMAXPATH+1);
  7064.  
  7065.     debug(F110,"zvpass() homedir",homedir,0);
  7066.  
  7067.     zchdir(zhome());
  7068.  
  7069.     if ( isguest ) {
  7070. #ifdef CKROOT
  7071.         if ( anonroot ) {
  7072.             if (zsetroot(anonroot) < 0) {
  7073.                 printf("Login unavailable: invalid anonymous root directory\r\n");
  7074.                 debug(F110,"zvpass()","invalid anonymous root directory",0);
  7075.                 return(0);
  7076.             }
  7077.         }
  7078. #else /* CKROOT */
  7079.         debug(F110,"zvpass()","no anonymous root support",0);
  7080. #endif /* CKROOT */
  7081.     }
  7082. #else /* NT */
  7083.     if (!isguest && ck_tn_auth_valid() == AUTH_VALID &&
  7084.          (!passwd || !(*passwd))) { /* already authenticated */
  7085.         switch (ck_tn_authenticated()) {
  7086.         case AUTHTYPE_NTLM:
  7087.         case AUTHTYPE_KERBEROS_V4:
  7088.         case AUTHTYPE_KERBEROS_V5:
  7089.         case AUTHTYPE_SRP:
  7090.             break;
  7091.         case AUTHTYPE_NULL:
  7092.         case AUTHTYPE_AUTO:
  7093. #ifdef CK_SSL
  7094.             if ((ssl_active_flag && ssl_get_subject_name(ssl_con))||
  7095.                  (tls_active_flag && ssl_get_subject_name(tls_con)))
  7096.                 break;
  7097. #endif /* CK_SSL */
  7098.         default:
  7099.             debug(F110,"zvpass","AUTH_VALID login failed",0);
  7100.             return(0);
  7101.         }
  7102.     } else {
  7103. #ifdef CK_SRP
  7104.         rc = t_verifypw (uid, pwd);
  7105. #ifndef PRE_SRP_1_4_4
  7106.         if (rc > -1)
  7107.             endtpent();
  7108. #endif /* PRE_SRP_1_4_4 */
  7109.         if (rc <= 0)
  7110. #endif /* CK_SRP */
  7111.         {
  7112.             debug(F110,"zvpass","login failed",0);
  7113.             return(0);
  7114.         }
  7115.     }
  7116.  
  7117. #ifdef CKROOT
  7118.     if ( isguest ) {
  7119.         if ( anonroot ) {
  7120.             if (zsetroot(anonroot) < 0) {
  7121.                 printf("Login unavailable: invalid anonymous root directory\r\n");
  7122.                 debug(F110,"zvpass()","invalid anonymous root directory",0);
  7123.                 return(0);
  7124.             }
  7125.         }
  7126.     }
  7127. #endif /* CKROOT */
  7128. #endif /* NT */
  7129.  
  7130. #ifdef CKSYSLOG
  7131.     if (ckxsyslog >= SYSLG_LI && ckxlogging)
  7132.         cksyslog(SYSLG_LI, 1, "LOGIN",uid,clienthost);
  7133. #endif /* CKSYSLOG */
  7134.  
  7135. #ifdef IKSDB
  7136.     if (ikdbopen) {
  7137.         char * p, * q;
  7138.         int k;
  7139.         extern char dbrec[];
  7140.         extern unsigned long myflags, mydbslot;
  7141.         extern struct iksdbfld dbfld[];
  7142.         extern unsigned long myaflags, myamode, myatype;
  7143.  
  7144.         debug(F101,"XXX guest","",isguest);
  7145.         debug(F110,"XXX zvuname",uid,0);
  7146.         debug(F110,"XXX guestpass",guestpass,0);
  7147.  
  7148.         myflags |= DBF_LOGGED;
  7149.         p = isguest ? guestpass : uid;
  7150.         if (isguest) {
  7151.             p = (char *)guestpass;
  7152.             myflags &= ~DBF_USER;
  7153.         } else {
  7154.             p = (char *)uid;
  7155.             myflags |= DBF_USER;
  7156.         }
  7157.         k = strlen(p);
  7158.         strncpy(&dbrec[DB_ULEN],ulongtohex((unsigned long)k,4),4);
  7159.         lset(&dbrec[dbfld[db_USER].off],p,1024,32);
  7160.         strncpy(&dbrec[DB_FLAGS],ulongtohex(myflags,4),4);
  7161. #ifdef CK_AUTHENTICATION
  7162.         myamode = ck_tn_auth_valid();
  7163.         strncpy(&dbrec[DB_AMODE],ulongtohex(myamode,4),4);
  7164.         myatype = ck_tn_authenticated();
  7165.         strncpy(&dbrec[DB_ATYPE],ulongtohex(myatype,4),4);
  7166. #endif /* CK_AUTHENTICATION */
  7167.         p = zgtdir();
  7168.  
  7169.         strncpy(&dbrec[DB_DLEN],
  7170.                 ulongtohex((unsigned long)strlen(p),4),
  7171.                 4
  7172.                 );
  7173.         lset(&dbrec[dbfld[db_DIR].off],p,1024,32);
  7174.         updslot(mydbslot);
  7175.     }
  7176. #endif /* IKSDB */
  7177.     debug(F110,"zvpass()","success",0);
  7178.     return(1);
  7179. }
  7180.  
  7181. VOID
  7182. zvlogout() {
  7183. #ifdef NT
  7184.     extern int haveNTLMContext;
  7185. #ifdef CKSYSLOG
  7186.     if (ckxsyslog >= SYSLG_LI && ckxlogging) {
  7187.         cksyslog(SYSLG_LI, 1, "LOGOUT",(char *) isguest ? anonacct : uidbuf,
  7188.                   clienthost);
  7189.     }
  7190. #endif /* CKSYSLOG */
  7191.  
  7192.     if ( haveNTLMContext ) {
  7193.         ntlm_logout();
  7194.     }
  7195.     if ( hLoggedOn != INVALID_HANDLE_VALUE ) {
  7196.         RevertToSelf();
  7197.  
  7198.         if ( p_UnloadUserProfileA && profinfo.hProfile )
  7199.             p_UnloadUserProfileA(hLoggedOn, profinfo.hProfile);
  7200.         memset(&profinfo,0,sizeof(profinfo));
  7201.         profinfo.dwSize = sizeof(profinfo);
  7202.  
  7203.         if ( p_DestroyEnvironmentBlock && pEnvBlock ) {
  7204.             p_DestroyEnvironmentBlock(pEnvBlock);
  7205.             pEnvBlock = NULL;
  7206.         }
  7207.  
  7208.         CloseHandle(hLoggedOn);
  7209.         hLoggedOn = INVALID_HANDLE_VALUE;
  7210.     }
  7211.     if (pSid) {
  7212.         free(pSid);
  7213.         pSid = NULL;
  7214.     }
  7215.     if ( pReferenceDomainName ) {
  7216.         free(pReferenceDomainName);
  7217.         pReferenceDomainName = NULL;
  7218.     }
  7219. #endif /* NT */
  7220.     homedir[0] = '\0';
  7221.     uidbuf[0] = '\0';
  7222.     isguest = 0;
  7223.     logged_in = 0;
  7224.     return;
  7225. }
  7226.  
  7227. #ifdef NT
  7228. /* From Peter Runestig */
  7229.  
  7230. static HINSTANCE hNetApi32=NULL;
  7231. static NET_API_STATUS
  7232. (NET_API_FUNCTION *p_NetUserGetInfo)( LPWSTR, LPWSTR, DWORD, LPBYTE *)=NULL;
  7233. static NET_API_STATUS
  7234. (NET_API_FUNCTION *p_NetGetDCName)(LPCWSTR, LPCWSTR, LPBYTE *)=NULL;
  7235. static NET_API_STATUS
  7236. (NET_API_FUNCTION *p_NetApiBufferFree)( LPVOID ) = NULL;
  7237. static NET_API_STATUS
  7238. (NET_API_FUNCTION *p_NetUserGetLocalGroups)(LPCWSTR, LPCWSTR, DWORD, DWORD, LPBYTE *,
  7239.                                              DWORD, LPDWORD, LPDWORD)=NULL;
  7240. static NET_API_STATUS
  7241. (NET_API_FUNCTION *p_NetUserGetGroups)(LPCWSTR, LPCWSTR, DWORD, LPBYTE *,
  7242.                                              DWORD, LPDWORD, LPDWORD)=NULL;
  7243. static NET_API_STATUS
  7244. (NET_API_FUNCTION *p_NetGroupGetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE)=NULL;
  7245.  
  7246.  
  7247. static int
  7248. LoadNetApi32()
  7249. {
  7250.     if ( !hNetApi32 ) {
  7251.         debug(F110,"LoadNetApi32","loading netapi32.dll",0);
  7252.         hNetApi32 = LoadLibrary( "netapi32.dll" );
  7253.         if ( hNetApi32 ) {
  7254.             (FARPROC) p_NetUserGetInfo = GetProcAddress( hNetApi32, "NetUserGetInfo" );
  7255.             (FARPROC) p_NetApiBufferFree = GetProcAddress( hNetApi32, "NetApiBufferFree" );
  7256.             (FARPROC) p_NetGetDCName = GetProcAddress( hNetApi32, "NetGetDCName" );
  7257.             (FARPROC) p_NetUserGetLocalGroups = GetProcAddress( hNetApi32, "NetUserGetLocalGroups" );
  7258.             (FARPROC) p_NetUserGetGroups = GetProcAddress( hNetApi32, "NetUserGetGroups" );
  7259.             (FARPROC) p_NetGroupGetInfo = GetProcAddress( hNetApi32, "NetGroupGetInfo" );
  7260.  
  7261.             if ( !p_NetUserGetInfo || !p_NetApiBufferFree || !p_NetGetDCName ||
  7262.                  !p_NetUserGetLocalGroups || !p_NetUserGetGroups || !p_NetGroupGetInfo )
  7263.             {
  7264.                 debug(F110,"LoadNetApi32","loading netapi32.dll unable to load function",0);
  7265.                 FreeLibrary(hNetApi32);
  7266.                 hNetApi32 = NULL;
  7267.             }
  7268.         }
  7269.         if ( !hNetApi32 ) {
  7270.             debug(F110,"LoadNetApi32","loading netapi32.dll failed",0);
  7271.             return(0);
  7272.         }
  7273.     }
  7274.     return(1);
  7275. }
  7276.  
  7277. static int
  7278. _GetUserGroups(LPWSTR wCompName, LPWSTR wUserName)
  7279. {
  7280.     int err;
  7281.     LPLOCALGROUP_USERS_INFO_0 lpLocalGroupInfo=NULL;
  7282.     LPGROUP_USERS_INFO_0 lpGroupInfo=NULL;
  7283.     /*
  7284.      * typedef struct _LOCAL_GROUP_USERS_INFO_0 {
  7285.      *   LPWSTR  lgrui0_name;
  7286.      * } LOCALGROUP_USERS_INFO_0, *PLOCALGROUP_USERS_INFO_0, *LPLOCALGROUP_USERS_INFO_0;
  7287.      *
  7288.      * typedef struct _GROUP_USERS_INFO_0 {
  7289.      *   LPWSTR  grui0_name;
  7290.      * } GROUP_USERS_INFO_0, *PGROUP_USERS_INFO_0, *LPGROUP_USERS_INFO_0;
  7291.      */
  7292.     DWORD localEntriesRead, localEntriesTotal, remoteEntriesRead, remoteEntriesTotal;
  7293.     DWORD i,j;
  7294.     CHAR buf[256], compName[256];
  7295.     char group[UNLEN], domain[255];
  7296.     unsigned char sid[MAXSIZE], *sc;
  7297.     DWORD sz_sid = MAXSIZE, sz_domain = sizeof(domain), *sa;
  7298.     SID_NAME_USE sid_use;
  7299.  
  7300.  
  7301.     UnicodeToOEM(wCompName,compName,256);
  7302.     err = p_NetUserGetLocalGroups(wCompName, wUserName, 0, LG_INCLUDE_INDIRECT,
  7303.                                    (LPBYTE *)&lpLocalGroupInfo,
  7304.                                    MAX_PREFERRED_LENGTH, &localEntriesRead, &localEntriesTotal);
  7305.     switch ( err ) {
  7306.     case NERR_Success:
  7307.         debug(F111,"_GetUserGroups","localEntriesRead",localEntriesRead);
  7308.         debug(F111,"_GetUserGroups","localEntriesTotal",localEntriesTotal);
  7309.         break;
  7310.     case ERROR_ACCESS_DENIED:
  7311.         debug(F110,"_GetUserGroups","Access Denied",0);
  7312.         localEntriesRead = 0;
  7313.         break;
  7314.     case ERROR_MORE_DATA:
  7315.         debug(F110,"_GetUserGroups","More Data",0);
  7316.         localEntriesRead = 0;
  7317.         break;
  7318.     case NERR_InvalidComputer:
  7319.         debug(F110,"_GetUserGroups","Invalid Computer",0);
  7320.         localEntriesRead = 0;
  7321.         break;
  7322.     case NERR_UserNotFound:
  7323.         debug(F110,"_GetUserGroups","User Not Found",0);
  7324.         localEntriesRead = 0;
  7325.         break;
  7326.     default:
  7327.         debug(F111,"_GetUserGroups","other error",err);
  7328.         localEntriesRead = 0;
  7329.     }
  7330.  
  7331.     err = p_NetUserGetGroups(wCompName, wUserName, 0,
  7332.                               (LPBYTE *)&lpGroupInfo,
  7333.                               MAX_PREFERRED_LENGTH, &remoteEntriesRead, &remoteEntriesTotal);
  7334.     switch ( err ) {
  7335.     case NERR_Success:
  7336.         debug(F111,"_GetUserGroups","remoteEntriesRead",remoteEntriesRead);
  7337.         debug(F111,"_GetUserGroups","remoteEntriesTotal",remoteEntriesTotal);
  7338.         break;
  7339.     case ERROR_ACCESS_DENIED:
  7340.         debug(F110,"_GetUserGroups","Access Denied",0);
  7341.         remoteEntriesRead = 0;
  7342.         break;
  7343.     case ERROR_MORE_DATA:
  7344.         debug(F110,"_GetUserGroups","More Data",0);
  7345.         remoteEntriesRead = 0;
  7346.         break;
  7347.     case NERR_InvalidComputer:
  7348.         debug(F110,"_GetUserGroups","Invalid Computer",0);
  7349.         remoteEntriesRead = 0;
  7350.         break;
  7351.     case NERR_UserNotFound:
  7352.         debug(F110,"_GetUserGroups","User Not Found",0);
  7353.         remoteEntriesRead = 0;
  7354.         break;
  7355.     default:
  7356.         debug(F111,"_GetUserGroups","other error",err);
  7357.         remoteEntriesRead = 0;
  7358.     }
  7359.  
  7360.     pTokenGroups = (PTOKEN_GROUPS) malloc(sizeof(DWORD)
  7361.                  + (localEntriesRead + remoteEntriesRead) * sizeof(SID_AND_ATTRIBUTES));
  7362.     pTokenGroups->GroupCount = localEntriesRead + remoteEntriesRead;
  7363.  
  7364.     for ( i=0, j=0; i<localEntriesRead ; i++,j++ ) {
  7365.         UnicodeToOEM(lpLocalGroupInfo[i].lgrui0_name,buf,256);
  7366. #ifdef COMMENT
  7367.         printf("Local Groups: %s\r\n",buf);
  7368. #endif /* COMMENT */
  7369.         debug(F110,"_GetUserGroups LocalGroup",buf,0);
  7370.         // get the SID for each group
  7371.         UnicodeToOEM(lpLocalGroupInfo[i].lgrui0_name, group, sizeof(group));
  7372.         sz_sid = MAXSIZE;
  7373.         err = LookupAccountName(compName, group, (PSID) sid, &sz_sid, domain,
  7374.                                  &sz_domain, &sid_use);
  7375.  
  7376.         debug(F110,"_GetUserGroups LookupAccountName() domain",domain,0);
  7377.  
  7378.         pTokenGroups->Groups[j].Sid = (PSID) malloc( sz_sid );
  7379.         CopySid( sz_sid, pTokenGroups->Groups[j].Sid, sid );
  7380.         pTokenGroups->Groups[j].Attributes = SE_GROUP_ENABLED;
  7381.  
  7382.         // compare the last subauthority in the group's SID with the primary
  7383.         // group RID from the USER_INFO_3 struct
  7384.         sc = GetSidSubAuthorityCount((PSID) sid);
  7385.         sa = GetSidSubAuthority((PSID) sid, *sc - 1);
  7386.         if (*sa == PrimaryGroupId) {
  7387.             pPriGroupSid = (PSID) malloc( sz_sid );
  7388.             CopySid( sz_sid, pPriGroupSid, sid );
  7389. #ifdef COMMENT
  7390.             printf("Primary group is %s!\n", group);
  7391. #endif /* COMMENT */
  7392.             debug(F110,"_GetUserGroups PrimaryLocalGroup",buf,0);
  7393.         }
  7394.     }
  7395.     for ( i=0; i<remoteEntriesRead ; i++, j++ ) {
  7396.         UnicodeToOEM(lpGroupInfo[i].grui0_name,buf,256);
  7397. #ifdef COMMENT
  7398.         printf("Groups: %s\r\n",buf);
  7399. #endif /* COMMENT */
  7400.         debug(F110,"_GetUserGroups DomainGroup",buf,0);
  7401.         // get the SID for each group
  7402.         UnicodeToOEM(lpGroupInfo[i].grui0_name, group, sizeof(group));
  7403.         sz_sid = MAXSIZE;
  7404.         err = LookupAccountName(compName, group, (PSID) sid, &sz_sid, domain,
  7405.                                  &sz_domain, &sid_use);
  7406.  
  7407.         debug(F110,"_GetUserGroups LookupAccountName() domain",domain,0);
  7408.  
  7409.         pTokenGroups->Groups[j].Sid = (PSID) malloc( sz_sid );
  7410.         CopySid( sz_sid, pTokenGroups->Groups[j].Sid, sid );
  7411.         pTokenGroups->Groups[j].Attributes = SE_GROUP_ENABLED;
  7412.  
  7413.         // compare the last subauthority in the group's SID with the primary
  7414.         // group RID from the USER_INFO_3 struct
  7415.         sc = GetSidSubAuthorityCount((PSID) sid);
  7416.         sa = GetSidSubAuthority((PSID) sid, *sc - 1);
  7417.         if (*sa == PrimaryGroupId) {
  7418.             pPriGroupSid = (PSID) malloc( sz_sid );
  7419.             CopySid( sz_sid, pPriGroupSid, sid );
  7420. #ifdef COMMENT
  7421.             printf("Primary group is %s!\n", group);
  7422. #endif /* COMMENT */
  7423.             debug(F110,"_GetUserGroups DomainLocalGroup",buf,0);
  7424.         }
  7425.     }
  7426.  
  7427.     p_NetApiBufferFree(lpGroupInfo);
  7428.     p_NetApiBufferFree(lpLocalGroupInfo);
  7429.  
  7430.     return(err);
  7431. }
  7432.  
  7433. static int
  7434. _GetUserInfo(LPWSTR wCompName, LPWSTR wUserName)
  7435. {
  7436.   int err;
  7437.   LPUSER_INFO_3 UserInfo = NULL;
  7438. /*typedef struct _USER_INFO_3 {
  7439.     LPWSTR    usri3_name;
  7440.     LPWSTR    usri3_password;
  7441.     DWORD     usri3_password_age;
  7442.     DWORD     usri3_priv;
  7443.     LPWSTR    usri3_home_dir;
  7444.     LPWSTR    usri3_comment;
  7445.     DWORD     usri3_flags;
  7446.     LPWSTR    usri3_script_path;
  7447.     DWORD     usri3_auth_flags;
  7448.     LPWSTR    usri3_full_name;
  7449.     LPWSTR    usri3_usr_comment;
  7450.     LPWSTR    usri3_parms;
  7451.     LPWSTR    usri3_workstations;
  7452.     DWORD     usri3_last_logon;
  7453.     DWORD     usri3_last_logoff;
  7454.     DWORD     usri3_acct_expires;
  7455.     DWORD     usri3_max_storage;
  7456.     DWORD     usri3_units_per_week;
  7457.     PBYTE     usri3_logon_hours;
  7458.     DWORD     usri3_bad_pw_count;
  7459.     DWORD     usri3_num_logons;
  7460.     LPWSTR    usri3_logon_server;
  7461.     DWORD     usri3_country_code;
  7462.     DWORD     usri3_code_page;
  7463.     DWORD     usri3_user_id;
  7464.     DWORD     usri3_primary_group_id;
  7465.     LPWSTR    usri3_profile;
  7466.     LPWSTR    usri3_home_dir_drive;
  7467.     DWORD     usri3_password_expired;
  7468. }USER_INFO_3, *PUSER_INFO_3, *LPUSER_INFO_3;*/
  7469.  
  7470.     err = p_NetUserGetInfo(wCompName, wUserName, 3, (LPBYTE *)&UserInfo);
  7471.     debug(F111,"_GetUserInfo","NetUserGetInfo returns",err);
  7472.     if (!err) {
  7473.         debug(F111,"_GetUserInfo","UserInfo",UserInfo);
  7474.         UnicodeToOEM(UserInfo->usri3_home_dir, HomeDir, sizeof(HomeDir));
  7475.         debug(F110,"_GetUserInfo HomeDir",HomeDir,0);
  7476.         UnicodeToOEM(UserInfo->usri3_profile, ProfilePath, sizeof(ProfilePath));
  7477.         debug(F110,"_GetUserInfo ProfilePath",ProfilePath,0);
  7478.         PrimaryGroupId = UserInfo->usri3_primary_group_id;
  7479.         p_NetApiBufferFree(UserInfo);
  7480.     }
  7481.     return err;
  7482. }
  7483.  
  7484. int
  7485. GetUserInfo(LPSTR DomainName, LPSTR UserName)
  7486. {
  7487.     unsigned short wDomainName[128], wUserName[128], *wPDCName;
  7488.     unsigned char  LocalMachine[128]="";
  7489.     DWORD dwSize = 128;
  7490.     int err;
  7491.  
  7492.     if ( !LoadNetApi32() )
  7493.         return(-1);
  7494.  
  7495.     wDomainName[0] = 0;
  7496.     wUserName[0] = 0;
  7497.  
  7498.     OEMToUnicode(UserName, wUserName, sizeof(wUserName));
  7499.  
  7500.     debug(F110,"GetUserInfo DomainName",DomainName,0);
  7501.     debug(F110,"GetUserInfo UserName",UserName,0);
  7502.  
  7503.     if (DomainName) {
  7504.         GetComputerName(LocalMachine,&dwSize);
  7505.         if ( ckstrcmp(DomainName,LocalMachine, -1, 0) )
  7506.             OEMToUnicode(DomainName, wDomainName, sizeof(wDomainName));
  7507.     }
  7508.  
  7509.     debug(F110,"GetUserInfo","calling _GetUserInfo() with wDomainName",0);
  7510.     if (_GetUserInfo(wDomainName[0] ? wDomainName : NULL, wUserName)) {
  7511.         debug(F110,"GetUserInfo","calling NetGetDCName()",0);
  7512.         err = p_NetGetDCName(NULL, wDomainName, (LPBYTE *)&wPDCName);
  7513.         debug(F111,"GetUserInfo","NetGetDCName() returns",err);
  7514.         if (!err) {
  7515.             debug(F110,"GetUserInfo","calling _GetUserInfo() with wPDCName",0);
  7516.             if(!_GetUserInfo(wPDCName, wUserName)) {
  7517.                 _GetUserGroups(wPDCName, wUserName);
  7518.  
  7519.                 /* Lets save the PDCName */
  7520.                 UnicodeToOEM(wPDCName, LocalMachine, sizeof(LocalMachine));
  7521.                 makestr(&pPDCName,LocalMachine);
  7522.                 debug(F110,"GetUserInfo PDCName",pPDCName,0);
  7523.             }
  7524.             p_NetApiBufferFree(wPDCName);
  7525.         } else {
  7526.             debug(F110,"GetUserInfo","calling _GetUserInfo() with NULL",0);
  7527.             if(!_GetUserInfo(NULL, wUserName)) {
  7528.                 _GetUserGroups(NULL, wUserName);
  7529.             }
  7530.         }
  7531.     } else {
  7532.         _GetUserGroups(wDomainName, wUserName);
  7533.     }
  7534.     debug(F100,"GetUserInfo returns","",0);
  7535.     return 0;
  7536. }
  7537.  
  7538. VOID
  7539. setntcreds() {
  7540.     extern int haveNTLMContext;
  7541.  
  7542.     if ( !logged_in )
  7543.         return;
  7544.  
  7545.     if ( hLoggedOn != INVALID_HANDLE_VALUE ) {
  7546.         ImpersonateLoggedOnUser(hLoggedOn);
  7547.     } else if ( haveNTLMContext ) {
  7548.         ntlm_impersonate();
  7549.     }
  7550. #ifdef CK_AUTHENTICATE
  7551.     else if ( ck_tn_auth_valid() == AUTH_VALID &&
  7552.               ck_tn_authenticated() == AUTHTYPE_NTLM ) {
  7553.         ntlm_impersonate();
  7554.     }
  7555. #endif /* CK_AUTHENTICATE */
  7556. }
  7557. #endif /* NT */
  7558. #endif /* CK_LOGIN */
  7559.  
  7560. #ifdef CKSYSLOG
  7561. HANDLE hSysLog = INVALID_HANDLE_VALUE;
  7562. static char pidstr[16]="";
  7563.  
  7564. VOID
  7565. zsyslog() {
  7566.     if (ckxsyslog && !ckxlogging) {
  7567.         sprintf(pidstr,"PID=%d",os2getpid());
  7568. #ifdef NT
  7569.         if ( !isWin95() ) {
  7570.             hSysLog = RegisterEventSource(NULL,
  7571. #ifdef IKSD
  7572.                                            inserver ? "IKSD" :
  7573. #endif /* IKSD */
  7574.                                            "K95");
  7575.             ckxlogging = 1;
  7576.             debug(F100,"zsyslog syslog opened","",0);
  7577.         } else
  7578. #endif /* NT */
  7579.         {
  7580.             printf("syslog not available\r\n");
  7581.             debug(F100,"zsyslog syslog not opened","",0);
  7582.         }
  7583.     }
  7584. }
  7585. /*
  7586.   C K S Y S L O G  --  C-Kermit system logging function,
  7587.  
  7588.   For use by other modules.
  7589.   This module can, but doesn't have to, use it.
  7590.   Call with:
  7591.     n = SYSLG_xx values defined in ckcdeb.h
  7592.     s1, s2, s3: strings.
  7593. */
  7594. VOID
  7595. cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; {
  7596. #ifdef IKSDB
  7597.     extern int what, ikdbopen;
  7598. #endif /* IKSDB */
  7599.     int level;
  7600.     char * messages[5];
  7601.  
  7602. #ifdef IKSDB
  7603.     if (inserver && ikdbopen) {
  7604.         slotstate(what,s1,s2,s3);
  7605.     }
  7606. #endif /* IKSDB */
  7607.     if (!ckxlogging) return;
  7608.  
  7609.     if (!s1) s1 = "";
  7610.     if (!s2) s2 = "";
  7611.     if (!s3) s3 = "";
  7612.  
  7613.     if ( n == SYSLG_LI ) {
  7614.         if ( m )
  7615.             level = EVENTLOG_AUDIT_SUCCESS;
  7616.         else
  7617.             level = EVENTLOG_AUDIT_FAILURE;
  7618.     } else {
  7619.         level = EVENTLOG_INFORMATION_TYPE;
  7620.     }
  7621.  
  7622.     debug(F110,"cksyslog s1",s1,0);
  7623.     debug(F110,"cksyslog s2",s2,0);
  7624.     debug(F110,"cksyslog s3",s3,0);
  7625.  
  7626.     messages[0] = pidstr;
  7627.     messages[1] = s1;
  7628.     messages[2] = s2;
  7629.     messages[3] = s3;
  7630.     messages[4] = "\0";
  7631.  
  7632.     ReportEvent(hSysLog,level, 0,0,
  7633. #ifdef CK_LOGIN
  7634.                  pSid,
  7635. #else /* CK_LOGIN */
  7636.                  NULL,
  7637. #endif /* CK_LOGIN */
  7638.                  5,
  7639.                  0,
  7640.                  messages,
  7641.                  NULL
  7642.                  );
  7643.     debug(F101,"cksyslog errno","",GetLastError());
  7644. }
  7645. #endif /* CKSYSLOG */
  7646.  
  7647.  
  7648. /*  Z C H D S K  --  Change currently selected disk device */
  7649.  
  7650. /* Returns -1 if error, otherwise 0 */
  7651.  
  7652. zchdsk(c) int c; {
  7653.     int i = toupper(c) - 64;
  7654.     return( _chdrive(i));
  7655. }
  7656.  
  7657. #ifdef NT
  7658. long
  7659. StreamSize(char * filename, char * streamname)
  7660. {
  7661.     HANDLE hf ;
  7662.     DWORD lasterror = 0 ;
  7663.     WIN32_STREAM_ID sid;
  7664.     DWORD dwStreamHeaderSize, dwRead, dw1, dw2;
  7665.     BOOL  bContinue;
  7666.     VOID *lpContext = NULL;
  7667.     WCHAR wszStreamName[CKMAXPATH+1];
  7668.     WCHAR wszStat[CKMAXPATH+1];
  7669.     char  stream[CKMAXPATH+1];
  7670.     int   i, diff;
  7671.     DWORD dwStreamId = 0xFFFFFFFF;
  7672.     long  size = -1;
  7673.  
  7674.     ckmakmsg(stream,CKMAXPATH+1,":",streamname,":$DATA",NULL);
  7675.     ANSIToUnicode(stream,wszStat,sizeof(wszStat));
  7676.  
  7677.     hf = CreateFile( filename,
  7678.                      GENERIC_READ | GENERIC_WRITE,
  7679.                      FILE_SHARE_READ | FILE_SHARE_WRITE, /* Allow Sharing */
  7680.                      NULL, /* No Security Attributes specified */
  7681.                      OPEN_EXISTING,
  7682.                      FILE_ATTRIBUTE_NORMAL,
  7683.                      NULL ) ;
  7684.  
  7685.     if ( hf != INVALID_HANDLE_VALUE ) {
  7686.         ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
  7687.         dwStreamHeaderSize = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid;
  7688.  
  7689.         for ( ;; ) {
  7690.             bContinue = BackupRead(hf, (LPBYTE) &sid, dwStreamHeaderSize,
  7691.                                     &dwRead, FALSE, FALSE, &lpContext);
  7692.             if (!bContinue ||
  7693.                  sid.dwStreamNameSize > sizeof(wszStreamName))
  7694.                 break;
  7695.  
  7696.             dwStreamId = sid.dwStreamId;
  7697.             bContinue = BackupRead(hf, (LPBYTE) &wszStreamName,
  7698.                                     sid.dwStreamNameSize,
  7699.                                     &dwRead, FALSE, FALSE, &lpContext);
  7700.             if ( !bContinue )
  7701.                 break;
  7702.  
  7703.             if (sid.dwStreamNameSize) {
  7704.                 wszStreamName[sid.dwStreamNameSize/2] = 0;
  7705.                 UnicodeToANSI(wszStreamName,stream,sizeof(stream));
  7706.                 debug(F110,"StreamSize ntfs stream found",stream,0);
  7707.                 if (!_wcsicmp(wszStreamName,wszStat)) {
  7708.                     size = (sid.Size.HighPart << 32) + sid.Size.LowPart;
  7709.                     break;
  7710.                 }
  7711.             }
  7712.             if (!BackupSeek(hf, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &lpContext))
  7713.                 break;
  7714.         }
  7715.  
  7716.         /* Close the backup context */
  7717.         BackupRead(hf, (LPBYTE) &sid, 0,
  7718.                     &dwRead, TRUE, FALSE, &lpContext);
  7719.         CloseHandle(hf);
  7720.     }
  7721.     return size;
  7722. }
  7723.  
  7724. #ifdef STREAMS
  7725. const char *
  7726. StreamType(DWORD StreamId)
  7727. {
  7728.     static char msg[32];
  7729.  
  7730.     switch (StreamId) {
  7731.     case BACKUP_INVALID:
  7732.         return "Invalid stream";
  7733.     case BACKUP_DATA:
  7734.         return "Standard data";
  7735.     case BACKUP_EA_DATA:
  7736.         return "Extended attribute data";
  7737.     case BACKUP_SECURITY_DATA:
  7738.         return "Security descriptor data";
  7739.     case BACKUP_ALTERNATE_DATA:
  7740.         return "Alternative data streams";
  7741.     case BACKUP_LINK:
  7742.         return "Hard link information";
  7743.     case BACKUP_PROPERTY_DATA:
  7744.         return "Property data";
  7745.     case BACKUP_OBJECT_ID:
  7746.         return "Objects identifiers";
  7747.     case BACKUP_REPARSE_DATA:
  7748.         return "Reparse points";
  7749.     case BACKUP_SPARSE_BLOCK:
  7750.         return "Sparse file.";
  7751.     default:
  7752.         sprintf(msg,"StreamType %u", StreamId);
  7753.         return msg;
  7754.     }
  7755. }
  7756.  
  7757. long
  7758. StreamCount(char * path, char * relpath, char * filename, char * pattern)
  7759. {
  7760.     HANDLE hf ;
  7761.     DWORD lasterror = 0 ;
  7762.     WIN32_STREAM_ID sid;
  7763.     DWORD dwStreamHeaderSize, dwRead, dw1, dw2;
  7764.     BOOL  bContinue;
  7765.     VOID *lpContext = NULL;
  7766.     WCHAR wszStreamName[CKMAXPATH+1];
  7767.     char  szStreamName[CKMAXPATH+1];
  7768.     char  streamsearch[CKMAXPATH+1], fullpath[CKMAXPATH+1];
  7769.     int   i, diff;
  7770.     long  count = 0;
  7771.  
  7772.     if ( !pattern )
  7773.         pattern = ":*";
  7774.  
  7775.     ckmakmsg(streamsearch,CKMAXPATH+1,pattern,":$DATA",NULL,NULL);
  7776.     ckmakmsg(fullpath,CKMAXPATH+1,path,relpath,filename,NULL);
  7777.  
  7778.     hf = CreateFile( fullpath,
  7779.                      GENERIC_READ | GENERIC_WRITE,
  7780.                      FILE_SHARE_READ | FILE_SHARE_WRITE, /* Allow Sharing */
  7781.                      NULL, /* No Security Attributes specified */
  7782.                      OPEN_EXISTING,
  7783.                      FILE_ATTRIBUTE_NORMAL,
  7784.                      NULL ) ;
  7785.  
  7786.     if ( hf != INVALID_HANDLE_VALUE ) {
  7787.         dwStreamHeaderSize = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid;
  7788.  
  7789.         for ( ;; ) {
  7790.             ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
  7791.             wszStreamName[0] = 0;
  7792.  
  7793.             bContinue = BackupRead(hf, (LPBYTE) &sid, dwStreamHeaderSize,
  7794.                                     &dwRead, FALSE, FALSE, &lpContext);
  7795.             if (!bContinue || dwRead == 0 ||
  7796.                 sid.dwStreamNameSize > sizeof(wszStreamName))
  7797.                 break;
  7798.  
  7799.             bContinue = BackupRead(hf, (LPBYTE) &wszStreamName,
  7800.                                     sid.dwStreamNameSize,
  7801.                                     &dwRead, FALSE, FALSE, &lpContext);
  7802.             if ( !bContinue )
  7803.                 break;
  7804.  
  7805.             debug(F111,"StreamSize ntfs stream found",szStreamName,sid.dwStreamId);
  7806.             if (sid.dwStreamNameSize) {
  7807.                 wszStreamName[sid.dwStreamNameSize/2] = 0;
  7808.                 UnicodeToANSI(wszStreamName,szStreamName,CKMAXPATH+1);
  7809.                 if (ckmatch(streamsearch, szStreamName, 0, 1)) {
  7810.                     count++;
  7811.                 }
  7812.             } else {
  7813.                 if ( sid.dwStreamId == BACKUP_DATA &&
  7814.                      (!pattern[0] || 
  7815.                       pattern[0] == ':' && pattern[1] == '*' && !pattern[2]) )  {
  7816.                     count++;
  7817.                 }
  7818.             }
  7819.  
  7820.             if (!BackupSeek(hf, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &lpContext))
  7821.                 break;
  7822.         }
  7823.  
  7824.         /* Close the backup context */
  7825.         BackupRead(hf, (LPBYTE) &sid, 0,
  7826.                     &dwRead, TRUE, FALSE, &lpContext);
  7827.         CloseHandle(hf);
  7828.     }
  7829.  
  7830.     return(count);
  7831. }
  7832. #endif /* STREAMS */
  7833. #endif /* NT */
  7834.  
  7835. int
  7836. os2stat(char *path, struct stat *st) {
  7837.     char local[MAXPATH];
  7838.     int len;
  7839. #ifdef NT
  7840.     int stream_idx=0;
  7841. #endif /* NT */
  7842.     int rc;
  7843.  
  7844.     if (!path)
  7845.         return(-1);
  7846.  
  7847.     if ( !strncmp(path,"//",2) || !strncmp(path,"\\\\",2)) {
  7848.         int i;
  7849.         len = ckstrncpy(local, UNCname(path), MAXPATH);
  7850.         if ( ISDIRSEP(local[len-1]) ) {
  7851.             /* We now need to strip the trailing directory separator if it is not */
  7852.             /* part of the machine or object name.                                */
  7853.             for ( i=2; i<len && !(ISDIRSEP(local[i])); i++ ); /* machine */
  7854.             for ( i++; i<len && !(ISDIRSEP(local[i])); i++ ); /* object */
  7855.  
  7856.             if (i < len-1 )
  7857.                 local[len-1] = '\0';
  7858.         }
  7859.     } else {
  7860.         len = ckstrncpy(local, path, MAXPATH);
  7861.  
  7862.         if ( len == 2 && local[1] == ':' )
  7863.             local[2] = DIRSEP, local[3] = 0; /* if drive only, append / */
  7864.         else if ( len == 0 )
  7865.             local[0] = DIRSEP, local[1] = 0; /* if empty path, take / instead */
  7866.         else if ( len > 1 && ISDIRSEP(local[len - 1]) && local[len - 2] != ':')
  7867.             local[len - 1] = 0; /* strip trailing / except after d: */
  7868.  
  7869. #ifdef NT
  7870.         /* NTFS supports streams which are indicated by
  7871.          *    filename:stream
  7872.          */
  7873.  
  7874.         for (stream_idx = len; stream_idx > 1 ; stream_idx--) {
  7875.             if (local[stream_idx] == ':') {     /* found a stream */
  7876.                 local[stream_idx] = NUL;
  7877.                 break;
  7878.             }
  7879.         }
  7880. #endif /* NT */
  7881.     }
  7882.     rc = stat(local, st);
  7883.     debug(F111,"os2stat","rc",rc);
  7884. #ifdef NT
  7885.     if ( stream_idx > 1 ) {
  7886.         long size = StreamSize(local,&local[stream_idx+1]);
  7887.         if ( size >= 0 )
  7888.             st->st_size = size;
  7889.         else
  7890.             rc = -1;
  7891.     }
  7892. #endif /* NT */
  7893.     return(rc);
  7894. }
  7895.  
  7896. #ifdef CK_LABELED
  7897. /* O S 2 S E T L O N G N A M E -- Set .LONGNAME Extended Attribute */
  7898.  
  7899. /* Returns -1 if error, otherwise 0 */
  7900.  
  7901. int
  7902. os2setlongname( char * fn, char * ln ) {
  7903.    EAOP2         FileInfoBuf;
  7904.    ULONG         FileInfoSize;
  7905.    ULONG         PathInfoFlags;
  7906.    APIRET        rc;
  7907.    char          FEA2List[1024];
  7908.    FEA2 *        pfea2;
  7909.    WORD *        pEAdata;
  7910.  
  7911.    debug(F110,"os2setlongname: filename is",fn,0);
  7912.    debug(F110,"os2setlongname: longname is",ln,0);
  7913.  
  7914.    FileInfoSize = sizeof( EAOP2 );
  7915.    PathInfoFlags = DSPI_WRTTHRU; /* complete write operation before return */
  7916.  
  7917.    FileInfoBuf.fpGEA2List = 0;
  7918.    FileInfoBuf.fpFEA2List = (PFEA2LIST) &FEA2List;
  7919.    pfea2 = FileInfoBuf.fpFEA2List->list;
  7920.  
  7921.    pfea2->oNextEntryOffset = 0;
  7922.    pfea2->fEA = 0;
  7923.    pfea2->cbName = 9; /* length of ".LONGNAME" without \0 */
  7924.    pfea2->cbValue = strlen( ln ) + 2 * sizeof( WORD );
  7925.    strcpy( pfea2->szName, ".LONGNAME" );
  7926.  
  7927.    pEAdata = (WORD *) pfea2->szName + 10/sizeof(WORD);
  7928.    *pEAdata = EAT_ASCII;
  7929.    pEAdata++;
  7930.    *pEAdata = strlen( ln );
  7931.    pEAdata++;
  7932.    strcpy( (char *) pEAdata, ln );
  7933.    pEAdata += (strlen( ln )+1)/sizeof(WORD);
  7934.  
  7935.    FileInfoBuf.fpFEA2List->cbList = (char *) pEAdata -
  7936.                                     (char *) FileInfoBuf.fpFEA2List;
  7937.  
  7938.    rc = DosSetPathInfo( fn, 2, &FileInfoBuf, FileInfoSize, PathInfoFlags );
  7939.    debug(F101,"os2setlongname: rc=","",rc);
  7940.    if ( !rc )
  7941.       return 0;
  7942.    else
  7943.       return -1;
  7944. }
  7945.  
  7946. /* O S 2 G E T L O N G N A M E -- Get .LONGNAME Extended Attribute */
  7947.  
  7948. /* Returns -1 if error, otherwise 0 */
  7949.  
  7950. int
  7951. os2getlongname( char * fn, char ** ln ) {
  7952.    static char   * LongNameBuf = 0;
  7953.    EAOP2         FileInfoBuf;
  7954.    ULONG         FileInfoSize;
  7955.    ULONG         PathInfoFlags;
  7956.    APIRET        rc;
  7957.    char          FEA2List[1024];
  7958.    FEA2 *        pfea2;
  7959.    char          GEA2List[1024];
  7960.    GEA2 *        pgea2;
  7961.    WORD *        pEAdata;
  7962.    WORD          LongNameLength;
  7963.  
  7964.    *ln = 0;
  7965.    if ( !LongNameBuf )
  7966.       LongNameBuf = strdup( "Initialization of LongNameBuf" );
  7967.    debug(F110,"os2getlongname: filename is",fn,0);
  7968.  
  7969.    FileInfoSize = sizeof( EAOP2 );
  7970.    PathInfoFlags = DSPI_WRTTHRU; /* Complete write operation before return */
  7971.  
  7972.    FileInfoBuf.fpGEA2List = (PGEA2LIST) &GEA2List;
  7973.    FileInfoBuf.fpFEA2List = (PFEA2LIST) &FEA2List;
  7974.    pgea2 = FileInfoBuf.fpGEA2List->list;
  7975.    pfea2 = FileInfoBuf.fpFEA2List->list;
  7976.  
  7977.    pfea2->oNextEntryOffset = 0;
  7978.    pfea2->fEA = 0;
  7979.    pfea2->cbName = 9;                   /* Length of ".LONGNAME" without \0 */
  7980.    pfea2->cbValue = MAXPATH;
  7981.    strcpy( pfea2->szName, ".LONGNAME" );
  7982.  
  7983.    FileInfoBuf.fpGEA2List->cbList = sizeof(GEA2LIST)
  7984.                                   + pgea2->cbName + 1;
  7985.    pgea2->oNextEntryOffset = 0;
  7986.    pgea2->cbName = pfea2->cbName;
  7987.    strcpy(pgea2->szName,pfea2->szName);
  7988.  
  7989.    FileInfoBuf.fpFEA2List->cbList = 1024;
  7990.  
  7991.    rc = DosQueryPathInfo(fn,FIL_QUERYEASFROMLIST,&FileInfoBuf,FileInfoSize );
  7992.    LongNameLength =
  7993.      *(WORD *)((char *)pfea2 + sizeof(FEA2) + pfea2->cbName + sizeof(WORD));
  7994.    debug(F101,"os2getlongname: rc=","",rc);
  7995.    debug(F101,"   cbValue:","",pfea2->cbValue);
  7996.    debug(F101,"   cbName:","",pfea2->cbName);
  7997.    debug(F101,"   EA Value Length:","",LongNameLength );
  7998.    debug(F110,"   EA Value:",(char *)pfea2 + sizeof(FEA2)
  7999.                              + pfea2->cbName + (2 * sizeof(WORD)),0 );
  8000.    if ( rc ) {
  8001.        return -1;
  8002.    } else if ( pfea2->cbValue ) {
  8003.        if (LongNameBuf) {
  8004.            free(LongNameBuf);
  8005.            LongNameBuf = NULL;
  8006.        }
  8007.        LongNameBuf = (char *) malloc( LongNameLength + 1 );
  8008.        if (LongNameBuf) {
  8009.            ckstrncpy(LongNameBuf, (char *)pfea2 + sizeof(FEA2)
  8010.                    + pfea2->cbName + (2 * sizeof(WORD)),
  8011.                    LongNameLength
  8012.                    );
  8013.            debug(F110,"os2getlongname: longname is",LongNameBuf,0);
  8014.        } else
  8015.          debug(F100,"os2getlongname: malloc failed","",0);
  8016.    } else {
  8017.        if ( LongNameBuf )
  8018.          free( LongNameBuf );
  8019.        LongNameBuf = strdup( "" );
  8020.        debug(F110,
  8021.              "os2getlongname: there is no longname attribute",
  8022.              LongNameBuf,
  8023.              0
  8024.              );
  8025.    }
  8026.    *ln = LongNameBuf;
  8027.    return 0;
  8028. }
  8029.  
  8030.  
  8031. _PROTOTYP( VOID GetMem, (PVOID *, ULONG) );
  8032.  
  8033. /* O S 2 G E T E A S - Get all OS/2 Extended Attributes */
  8034.  
  8035. /* Returns 0 on success, -1 on failure */
  8036.  
  8037. int
  8038. os2geteas( char * name ) {
  8039.     CHAR *pAllocc=NULL; /* Holds the FEA struct returned by DosEnumAttribute */
  8040.                         /*  used to create the GEA2LIST for DosQueryPathInfo */
  8041.  
  8042.     ULONG ulEntryNum = 1; /* count of current EA to read (1-relative)        */
  8043.     ULONG ulEnumCnt;      /* Number of EAs for Enum to return, always 1      */
  8044.  
  8045.     ULONG FEAListSize = sizeof(ULONG);/* starting size of buffer necessary to
  8046.                                                         hold all FEA blocks */
  8047.     ULONG GEAListSize = MAXEACOUNT * sizeof(GEA2) + sizeof(ULONG);
  8048.  
  8049.     FEA2 *pFEA;           /* Used to read from Enum's return buffer          */
  8050.     GEA2 *pGEA, *pLastGEAIn; /* Used to write to pGEAList buffer             */
  8051.     GEA2LIST *pGEAList;/*Ptr used to set up buffer for DosQueryPathInfo call */
  8052.     EAOP2  eaopGet;       /* Used to call DosQueryPathInfo                   */
  8053.     APIRET rc;
  8054.     int offset;
  8055.  
  8056.                                 /* Allocate enough room for any GEA List */
  8057.     GetMem((PPVOID)&pAllocc, MAX_GEA);
  8058.     pFEA = (FEA2 *) pAllocc;               /* pFEA always uses pAlloc buffer */
  8059.  
  8060.     GetMem((PPVOID)&pGEAList, GEAListSize ); /* alloc buffer for GEA2 list */
  8061.     pGEAList->cbList = GEAListSize;
  8062.     pGEA = pGEAList->list;
  8063.     pLastGEAIn = 0;
  8064.  
  8065.     if ( !pAllocc || ! pGEAList ) {
  8066.         FreeMem( pAllocc );
  8067.         FreeMem( pGEAList );
  8068.         return -1;
  8069.     }
  8070.     if ( pFEAList ) {
  8071.         FreeMem( pFEAList );
  8072.         pFEAList = 0;
  8073.    }
  8074.    while(TRUE) {              /* Loop continues until there are no more EAs */
  8075.        ulEnumCnt = 1;                   /* Only want to get one EA at a time */
  8076.        if(DosEnumAttribute(Ref_ASCIIZ,            /* Read into pAlloc Buffer */
  8077.                            name,                  /* Note that this does not */
  8078.                            ulEntryNum,            /* get the aValue field,   */
  8079.                            pAllocc,               /* so DosQueryPathInfo must*/
  8080.                            MAX_GEA,               /* be called to get it.    */
  8081.                            &ulEnumCnt,
  8082.                            (LONG) GetInfoLevel1)) {
  8083.            FreeMem(pGEAList);           /* There was some sort of error */
  8084.            FreeMem(pAllocc);
  8085.            return (-1);
  8086.        }
  8087.        if(ulEnumCnt != 1)               /* All the EAs have been read */
  8088.          break;
  8089.  
  8090.        ulEntryNum++;
  8091.        FEAListSize += sizeof(FEA2LIST) + pFEA->cbName+1 +
  8092.                       pFEA->cbValue + 4;
  8093.  
  8094.        if (pLastGEAIn)
  8095.          pLastGEAIn->oNextEntryOffset = (BYTE *)pGEA - (BYTE *)pLastGEAIn;
  8096.        pLastGEAIn = pGEA;
  8097.  
  8098.        pGEA->oNextEntryOffset = 0L;
  8099.        pGEA->cbName = pFEA->cbName;
  8100.        strcpy(pGEA->szName, pFEA->szName);
  8101.  
  8102.        /* must align GEA2 blocks on double word boundaries */
  8103.        offset = sizeof(GEA2) + pGEA->cbName + 1;
  8104.        offset += ( offset % 4 ? (4 - offset % 4) : 0 );
  8105.        pGEA = (GEA2 *) ((BYTE *) pGEA + offset);
  8106.    }
  8107.    debug(F111,"os2geteas: EA count",name,ulEntryNum-1);
  8108.    GetMem( (PPVOID) &pFEAList, FEAListSize );
  8109.    pFEAList->cbList = FEAListSize;
  8110.  
  8111.    eaopGet.fpGEA2List = pGEAList;
  8112.    eaopGet.fpFEA2List = pFEAList;
  8113.  
  8114.    rc = DosQueryPathInfo(name,                   /* Get the complete EA info */
  8115.                    GetInfoLevel3,
  8116.                    (PVOID) &eaopGet,
  8117.                     sizeof(EAOP2));
  8118.  
  8119.    debug(F111,"os2geteas: DosQueryPathInfo",name,rc);
  8120.    FreeMem( pGEAList );
  8121.    FreeMem( pAllocc );
  8122.    return ( rc ? -1 : 0 );
  8123. }
  8124.  
  8125. /* O S 2 S E T E A S - Set all OS/2 Extended Attributes */
  8126.  
  8127. /* Returns 0 on success, -1 on failure                  */
  8128.  
  8129. int
  8130. os2seteas( char * name ) {
  8131.    EAOP2  eaopSet;       /* Used to call DosSetPathInfo */
  8132.    APIRET rc;
  8133.  
  8134.    if ( !pFEAList ) {
  8135.      debug(F100,"os2seteas: EA List is empty","",0);
  8136.      return 0;
  8137.    }
  8138.    eaopSet.fpGEA2List = 0;
  8139.    eaopSet.fpFEA2List = pFEAList;
  8140.  
  8141.    rc = DosSetPathInfo(name,            /* Set the EA info */
  8142.                     SetInfoLevel2,
  8143.                    (PVOID) &eaopSet,
  8144.                     sizeof(EAOP2),
  8145.                     DSPI_WRTTHRU);
  8146.    debug(F111,"os2seteas: DosSetPathInfo",name,rc);
  8147.  
  8148.    if ( !rc ) {
  8149.       FreeMem( pFEAList );
  8150.       pFEAList = 0;
  8151.    }
  8152.    return ( rc ? -1 : 0 );
  8153. }
  8154.  
  8155. /* O S 2 G E T A T T R - Get all OS/2 Normal Attributes */
  8156.  
  8157. /* Returns 0 on success, -1 on failure                  */
  8158.  
  8159. int
  8160. os2getattr( char * name ) {
  8161.    FILESTATUS3 FileInfoBuf;
  8162.    APIRET rc;
  8163.  
  8164.    rc = DosQueryPathInfo(name,                   /* Get the complete EA info */
  8165.                    GetInfoLevel1,
  8166.                    (PVOID) &FileInfoBuf,
  8167.                     sizeof(FILESTATUS3));
  8168.  
  8169.    if ( !rc ) {
  8170.       os2attrs = FileInfoBuf.attrFile;
  8171.       return 0;
  8172.       }
  8173.    else {
  8174.       os2attrs = FILE_NORMAL;
  8175.       return -1;
  8176.       }
  8177. }
  8178.  
  8179. /* O S 2 S E T A T T R - Set all OS/2 Normal Attributes */
  8180.  
  8181. /* Returns 0 on success, -1 on failure                  */
  8182.  
  8183. int
  8184. os2setattr( char * name ) {
  8185.    FILESTATUS3 FileInfoBuf;
  8186.    APIRET rc;
  8187.  
  8188.    rc = DosQueryPathInfo(name,                   /* Get the complete EA info */
  8189.                    GetInfoLevel1,
  8190.                    (PVOID) &FileInfoBuf,
  8191.                     sizeof(FILESTATUS3));
  8192.  
  8193.    if ( !rc ) {
  8194.       FileInfoBuf.attrFile = lf_opts & os2attrs;
  8195.       rc = DosSetPathInfo( name,
  8196.                    GetInfoLevel1,
  8197.                    (PVOID) &FileInfoBuf,
  8198.                    sizeof(FILESTATUS3),
  8199.                    0);
  8200.       if ( !rc )
  8201.          return 0;
  8202.       }
  8203.    return -1;
  8204. }
  8205.  
  8206. /****************************************************************\
  8207.  *                                                              *
  8208.  *  Name:    GetMem (ppv, cb)                                   *
  8209.  *                                                              *
  8210.  *  Purpose: This routine returns a pointer to a available*     *
  8211.  *           memory space.                                      *
  8212.  *                                                              *
  8213.  *  Usage  :                                                    *
  8214.  *  Method : Routine should be bullet proof as it does its own  *
  8215.  *           error checking. It assumes that hwnd points to the *
  8216.  *           correct window with the name listbox in it.        *
  8217.  *                                                              *
  8218.  *  Returns: The current EA as determined by querying the l-box *
  8219.  *           selector.                                          *
  8220.  *                                                              *
  8221. \****************************************************************/
  8222. VOID GetMem (PVOID *ppv, ULONG cb) {
  8223.     BOOL        f;
  8224.  
  8225.     f =(BOOL) DosAllocMem(ppv, cb, fPERM|PAG_COMMIT);
  8226.     if (f) {
  8227.         *ppv = NULL;
  8228.         return;
  8229.     }
  8230.     return;
  8231. }
  8232.  
  8233. extern CHAR os2version[50];
  8234. extern long vernum;
  8235.  
  8236. /* D O _ L A B E L _ S E N D - Generate Label Header from EA List     */
  8237.  
  8238. /* Return 0 on success, -1 on failure                                 */
  8239.  
  8240. int
  8241. do_label_send(char * name) {
  8242.     char scratch[100];
  8243.     long buffreespace = INBUFSIZE;
  8244.     long easleft = 0;
  8245.     long memtocpy = 0;
  8246.     static BYTE * p = 0;
  8247.  
  8248.     debug(F110,"do_label_send",name,0);
  8249.     if (!pFEAList) {
  8250.         debug(F101,"do_label_send no EA list","",pFEAList);
  8251.         return(0);
  8252.     }
  8253.     if (!p) {
  8254.         debug(F100,"do_label_send: generate header","",0);
  8255.         zinptr += sprintf(zinptr,"KERMIT LABELED FILE:02UO04VERS");
  8256.  
  8257.         sprintf(scratch,"%d",strlen(get_os2_vers()));
  8258.         zinptr += sprintf(zinptr,"%02d%d%s",
  8259.                           strlen(scratch),
  8260.                           strlen(get_os2_vers()),
  8261.                           get_os2_vers()
  8262.                           );
  8263.         sprintf(scratch,"%d",vernum);
  8264.         zinptr += sprintf(zinptr,"05KVERS02%02d%d", strlen(scratch), vernum);
  8265.         sprintf(scratch,"%d",strlen(name));
  8266.         zinptr += sprintf(zinptr,"08FILENAME%02d%d%s",
  8267.                           strlen(scratch),
  8268.                           strlen(name), name
  8269.                           );
  8270.         zinptr += sprintf(zinptr,"04ATTR%02d",sizeof(ULONG));
  8271.         memcpy(zinptr, (BYTE *) &os2attrs, sizeof(ULONG));
  8272.         zinptr += sizeof(ULONG);
  8273.  
  8274.         sprintf( scratch, "%d", pFEAList->cbList );
  8275.         zinptr += sprintf(zinptr,"09EABUFSIZE%02d%ld",
  8276.                           strlen(scratch),
  8277.                           pFEAList->cbList
  8278.                           );
  8279.         p = (BYTE *) pFEAList;
  8280.         buffreespace -= (BYTE *) zinptr - (BYTE *) zinbuffer;
  8281.     }
  8282.     easleft = pFEAList->cbList - ( (BYTE *) p - (BYTE *) pFEAList );
  8283.     memtocpy = buffreespace > easleft ? easleft : buffreespace;
  8284.     memcpy( zinptr, p, memtocpy );
  8285.     zinptr = (BYTE *) zinptr + memtocpy;
  8286.     p = (BYTE *) p + memtocpy;
  8287.     buffreespace -= memtocpy;
  8288.  
  8289.     if (buffreespace > 0) {
  8290.         p = 0;
  8291.         FreeMem(pFEAList);
  8292.         pFEAList = 0;
  8293.         debug(F100,"do_label_send: terminate header","",0);
  8294.     }
  8295.     zincnt = (zinptr - zinbuffer);              /* Size of this beast */
  8296.     return(0);
  8297. }
  8298.  
  8299. /* D O _ L A B E L _ R E C V - Receive label info and create EA List  */
  8300.  
  8301. /* Return 0 on success, -1 on failure */
  8302.  
  8303. int
  8304. do_label_recv() {
  8305.     char *recv_ptr = zoutbuffer;
  8306.     int lblen;
  8307.     char buffer[16];
  8308.     size_t memtocpy, lefttocpy;
  8309.     static BYTE * pFEA = 0;
  8310.  
  8311.     if ( !pFEAList
  8312.          && strncmp(zoutbuffer,"KERMIT LABELED FILE:02UO04VERS",30) != 0) {
  8313.         debug(F100,"do_label_recv: not a labeled file","",0);
  8314.         return(0);                      /* Just continue if unlabeled */
  8315.     }
  8316.  
  8317.     if ( !pFEAList ) {
  8318.        recv_ptr += 30;                  /* start at front of buffer */
  8319.        zoutcnt  -= 30;
  8320.  
  8321.        /* get length of length of OS/2 version */
  8322.        memcpy(buffer, recv_ptr, 2);
  8323.        recv_ptr += 2;
  8324.        zoutcnt  -= 2;
  8325.        buffer[2] = '\0';
  8326.        lblen = atoi(buffer);
  8327.  
  8328.        /* get length of OS/2 version */
  8329.        memcpy(buffer, recv_ptr, lblen);
  8330.        recv_ptr += lblen;
  8331.        zoutcnt  -= lblen;
  8332.        buffer[lblen] = '\0';
  8333.        lblen = atoi(buffer);
  8334.  
  8335.        /* get os2 version */
  8336.        memcpy(buffer, recv_ptr, lblen);
  8337.        recv_ptr += lblen;
  8338.        zoutcnt  -= lblen;
  8339.        buffer[lblen] = '\0';
  8340.        debug(F111,"do_label_recv file created under OS/2",buffer,lblen);
  8341.  
  8342.        /* check sync with Kermit Version */
  8343.        memcpy(buffer, recv_ptr, 7);
  8344.        recv_ptr += 7;
  8345.        zoutcnt  -= 7;
  8346.        if (strncmp(buffer, "05KVERS", 7) != 0) {
  8347.            debug(F111,"do_label_recv lost sync at KVERS",recv_ptr-7,zoutcnt+7);
  8348.            return(-1);
  8349.        }
  8350.  
  8351.        /* get length of length of C-Kermit version */
  8352.        memcpy(buffer, recv_ptr, 2);
  8353.        recv_ptr += 2;
  8354.        zoutcnt  -= 2;
  8355.        buffer[2] = '\0';
  8356.        lblen = atoi(buffer);
  8357.  
  8358.        /* get length of C-Kermit version */
  8359.        memcpy(buffer, recv_ptr, lblen);
  8360.        recv_ptr += lblen;
  8361.        zoutcnt  -= lblen;
  8362.        buffer[lblen] = '\0';
  8363.        lblen = atoi(buffer);
  8364.  
  8365.        /* get C-Kermit version */
  8366.        memcpy(buffer, recv_ptr, lblen);
  8367.        recv_ptr += lblen;
  8368.        zoutcnt  -= lblen;
  8369.        buffer[lblen] = '\0';
  8370.        debug(F111,"do_label_recv file created with OS/2 C-Kermit",
  8371.              buffer,lblen);
  8372.  
  8373.        /* check sync with FILENAME */
  8374.        memcpy(buffer, recv_ptr, 10);
  8375.        recv_ptr += 10;
  8376.        zoutcnt  -= 10;
  8377.        if (strncmp(buffer, "08FILENAME", 10) != 0) {
  8378.            debug(F111,"do_label_recv lost sync at FILENAME",
  8379.                  recv_ptr-10,zoutcnt+10);
  8380.            return(-1);
  8381.        }
  8382.  
  8383.        /* get length of length of Filename */
  8384.        memcpy(buffer, recv_ptr, 2);
  8385.        recv_ptr += 2;
  8386.        zoutcnt  -= 2;
  8387.        buffer[2] = '\0';
  8388.        lblen = atoi(buffer);
  8389.  
  8390.        /* get length of File Name */
  8391.        memcpy(buffer, recv_ptr, lblen);
  8392.        recv_ptr += lblen;
  8393.        zoutcnt  -= lblen;
  8394.        buffer[lblen] = '\0';
  8395.        lblen = atoi(buffer);
  8396.  
  8397.        /* get File Name */
  8398.        memcpy(buffer, recv_ptr, lblen);
  8399.        recv_ptr += lblen;
  8400.        zoutcnt  -= lblen;
  8401.        buffer[lblen] = '\0';
  8402.        debug(F111,"  file sent with name: ",buffer,lblen);
  8403.  
  8404.        /* check sync with ATTR */
  8405.        memcpy(buffer, recv_ptr, 6);
  8406.        recv_ptr += 6;
  8407.        zoutcnt  -= 6;
  8408.        if (strncmp(buffer, "04ATTR", 6) != 0) {
  8409.            debug(F111,"  lost sync at ATTR",recv_ptr-6,zoutcnt+6);
  8410.            return(-1);
  8411.        }
  8412.  
  8413.        /* get length of attributes - should be sizeof(ULONG) */
  8414.        memcpy(buffer, recv_ptr, 2);
  8415.        recv_ptr += 2;
  8416.        zoutcnt  -= 2;
  8417.        buffer[2] = '\0';
  8418.        lblen = atoi(buffer);
  8419.        if ( lblen != sizeof(ULONG) ) {
  8420.            debug(F101,"   Attributes have wrong length","",lblen);
  8421.            return(-1);
  8422.        }
  8423.  
  8424.        /* get attributes */
  8425.        memcpy(&os2attrs, recv_ptr, sizeof(ULONG));
  8426.        recv_ptr += sizeof(ULONG);
  8427.        zoutcnt  -= sizeof(ULONG);
  8428.  
  8429.        /* check sync with EABUFSIZE */
  8430.        memcpy(buffer, recv_ptr, 11);
  8431.        recv_ptr += 11;
  8432.        zoutcnt  -= 11;
  8433.        if (strncmp(buffer, "09EABUFSIZE", 11) != 0) {
  8434.            debug(F111,"  lost sync at EABUFSIZE",recv_ptr-11,zoutcnt+11);
  8435.            return(-1);
  8436.        }
  8437.  
  8438.        /* get length of length of EA Buffer Size */
  8439.        memcpy(buffer, recv_ptr, 2);
  8440.        recv_ptr += 2;
  8441.        zoutcnt  -= 2;
  8442.        buffer[2] = '\0';
  8443.        lblen = atoi(buffer);
  8444.  
  8445.        /* get length of EA Buffer Size */
  8446.        memcpy(buffer, recv_ptr, lblen);
  8447.        recv_ptr += lblen;
  8448.        zoutcnt  -= lblen;
  8449.        buffer[lblen] = '\0';
  8450.        lblen = atoi(buffer);
  8451.        debug(F101,"  EA Buffer Size:","",lblen);
  8452.  
  8453.        GetMem( (PPVOID) &pFEAList, (ULONG) lblen );
  8454.        if ( !pFEAList ) {
  8455.          debug(F101,"   pFEAList","",pFEAList);
  8456.          return -1;
  8457.        }
  8458.        pFEAList->cbList = lblen;
  8459.        pFEA = (BYTE *) pFEAList;
  8460.    }
  8461.  
  8462.     if ( pFEAList && pFEA ) {
  8463.        /* get EA Buffer */
  8464.        lefttocpy = pFEAList->cbList - ( (BYTE *) pFEA - (BYTE *) pFEAList );
  8465.        memtocpy = ( zoutcnt < lefttocpy ? zoutcnt : lefttocpy );
  8466.        memcpy(pFEA, recv_ptr, memtocpy);
  8467.        recv_ptr += memtocpy;
  8468.        zoutcnt  -= memtocpy;
  8469.        pFEA += memtocpy;
  8470.        debug(F101,"   memtocpy","",memtocpy);
  8471.        debug(F101,"   zoutcnt","",zoutcnt);
  8472.  
  8473.        if ( pFEA == ( (BYTE *) pFEAList + pFEAList->cbList ) ) {
  8474.           pFEA = 0;  /* we are done copying the EA's to the EA List */
  8475.           debug(F100,"   done copying EA's","",0);
  8476.        }
  8477.     }
  8478.  
  8479.     /* if we have processed some of the data in the output buffer */
  8480.     /* then move the data in the buffer so that it is properly    */
  8481.     /* aligned with the beginning of the buffer and reset the ptr */
  8482.     if ( recv_ptr != zoutbuffer ) {
  8483.         memmove(zoutbuffer, recv_ptr, zoutcnt);
  8484.         if ( pFEA ) {
  8485.             zoutptr = zoutbuffer + zoutcnt ;
  8486.             return(1);                          /* Go fill some more */
  8487.         }
  8488.     }
  8489.     return (0);
  8490. }
  8491. #endif /* CK_LABELED */
  8492.  
  8493. #ifdef OS2ONLY
  8494. /*
  8495.  * given a template of the form "fnamXXXXXX", insert number on end
  8496.  * of template, insert unique letter if needed until unique filename
  8497.  * found or run out of letters.  The number is generated from the
  8498.  * Process ID.
  8499.  */
  8500.  
  8501. char *
  8502. mktemp(char * template)
  8503. {
  8504.     char *string = template;
  8505.     unsigned number;
  8506.     int letter = 'a';
  8507.     int xcount = 0;
  8508.     int olderrno;
  8509.  
  8510.     if (template == NULL || template[0] == '\0')
  8511.         return(NULL);
  8512.  
  8513.     number = os2getpid();
  8514.  
  8515.     while (*string)
  8516.         string++;
  8517.  
  8518.     /* replace last five X's */
  8519.     while (*--string == 'X' && xcount < 5)
  8520.     {
  8521.         xcount++;
  8522.         *string = (char)((number % 10) + '0');
  8523.         number /= 10;
  8524.     }
  8525.  
  8526.     /* too few X's ? */
  8527.     if (*string != 'X' || xcount < 5)
  8528.         return(NULL);
  8529.  
  8530.     /* set first X */
  8531.     *string = letter++;
  8532.  
  8533.     olderrno = errno;       /* save current errno */
  8534.     errno = 0;              /* make sure errno isn't EACCESS */
  8535.  
  8536.     /* check all the files 'a'-'z' */
  8537.     while ((access(template,0) == 0) || (errno == EACCES))
  8538.         /* while file exists */
  8539.     {
  8540.         errno = 0;
  8541.         if (letter == 'z' + 1) {
  8542.             errno = olderrno;
  8543.             return(NULL);
  8544.         }
  8545.  
  8546.         *string = (char)letter++;
  8547.     }
  8548.  
  8549.     errno = olderrno;
  8550.     return(template);
  8551. }
  8552. #endif /* OS2ONLY */
  8553.