home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit60 / ckufio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  138KB  |  5,101 lines

  1. #ifdef OS2
  2. #ifdef NT
  3. char *ckzv = "Win32 File support, 6.0.115 19 Nov 96";
  4. #else /* NT */
  5. char *ckzv = "OS/2 File support, 6.0.115 19 Nov 96";
  6. #endif /* NT */
  7. #else
  8. #ifdef aegis
  9. char *ckzv = "Aegis File support, 6.0.115 6 Sep 96";
  10. #else
  11. #ifdef Plan9
  12. char *ckzv = "Plan 9 File support, 6.0.115 6 Sep 96";
  13. #else
  14. char *ckzv = "UNIX File support, 6.0.115 6 Sep 96";
  15. #endif /* Plan9 */
  16. #endif /* aegis */
  17. #endif /* OS2 */
  18.  
  19. /* C K U F I O  --  Kermit file system support for UNIX, OS/2, and Aegis */
  20.  
  21.  
  22. /*
  23.   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
  24.   compatible with C preprocessors that support only #ifdef, #else, #endif,
  25.   #define, and #undef.  Please do not use #if, logical operators, or other
  26.   preprocessor features in any of the portable C-Kermit modules.  You can,
  27.   of course, use these constructions in system-specific modules when you they
  28.   are supported.
  29. */
  30.  
  31. /*
  32.   Author: Frank da Cruz (fdc@columbia.edu),
  33.   Columbia University Academic Information Systems, New York City,
  34.   and others noted below.
  35.  
  36.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  37.   York.  All rights reserved.
  38. */
  39.  
  40. /* Include Files */
  41.  
  42. #include "ckcsym.h"
  43. #include "ckcdeb.h"
  44. #include "ckcasc.h"
  45. #ifdef OS2
  46. #include "ckuusr.h"
  47. #include <stdio.h>
  48. _PROTOTYP( int os2settitle, (char *, int) );
  49. extern int priority;
  50. #ifdef NT
  51. #define timezone _timezone
  52. #define write _write
  53. #define fileno _fileno
  54. #ifndef SEM_INDEFINITE_WAIT
  55. #define SEM_INDEFINITE_WAIT INFINITE
  56. #endif /* SEM_INDEFINITE_WAIT */
  57. #endif /* NT */
  58. #endif /* OS2 */
  59. #include <signal.h>
  60.  
  61. #ifdef MINIX
  62. #include <limits.h>
  63. #else
  64. #ifdef POSIX
  65. #include <limits.h>
  66. #else
  67. #ifdef SVR3
  68. #include <limits.h>
  69. #endif /* SVR3 */
  70. #endif /* POSIX */
  71. #endif /* MINIX */
  72.  
  73. /* Directory structure header file */
  74.  
  75. #ifdef OS2
  76. /*
  77.  
  78.   C-Kermit's OS/2 support originally by Chris Adie <C.Adie@uk.ac.edinburgh>
  79.   Edinburgh University Computing Service, Scotland, for C-Kermit 4F.  Adapted
  80.   to C-Kermit 5A and integrated into the UNIX support module by Kai Uwe Rommel
  81.   <rommel@informatik.tu-muenchen.de>, Muenchen, Germany, December 1991.
  82. */
  83.  
  84. /*
  85.   Directory Separator macros, to allow this module to work with both UNIX and
  86.   OS/2: Because of ambiguity with the command line editor escape \ character,
  87.   the directory separator is currently left as / for OS/2 too, because the
  88.   OS/2 kernel also accepts / as directory separator.  But this is subject to
  89.   change in future versions to conform to the normal OS/2 style.
  90. */
  91. #define DIRSEP       '/'
  92. /* #define DIRSEP       '\\' */
  93. #define ISDIRSEP(c)  ((c)=='/'||(c)=='\\')
  94. #else /* not OS2 */
  95. #define DIRSEP       '/'
  96. #define ISDIRSEP(c)  ((c)=='/')
  97. #endif /* OS2 */
  98.  
  99. #ifdef SDIRENT
  100. #define DIRENT
  101. #endif /* SDIRENT */
  102.  
  103. #ifdef XNDIR
  104. #include <sys/ndir.h>
  105. #else /* !XNDIR */
  106. #ifdef NDIR
  107. #include <ndir.h>
  108. #else /* !NDIR, !XNDIR */
  109. #ifdef RTU
  110. #include "/usr/lib/ndir.h"
  111. #else /* !RTU, !NDIR, !XNDIR */
  112. #ifdef DIRENT
  113. #ifdef SDIRENT
  114. #include <sys/dirent.h>
  115. #else
  116. #include <dirent.h>
  117. #endif /* SDIRENT */
  118. #else
  119. #ifdef OS2
  120. #define OPENDIR
  121. #define DIRENT
  122. #include "ckodir.h"
  123. #else/* !RTU, !NDIR, !XNDIR, !DIRENT, !OS2, i.e. all others */
  124. #include <sys/dir.h>
  125. #endif /* OS2 */
  126. #endif /* DIRENT */
  127. #endif /* RTU */
  128. #endif /* NDIR */
  129. #endif /* XNDIR */
  130.  
  131. #ifdef OS2                /* OS/2 file system interface */
  132. #define BSD4                /* is like Berkeley UNIX */
  133. #define NOFILEH                /* with no <file.h> */
  134. #include <sys/utime.h>
  135. #include <stdlib.h>
  136. #include <process.h>
  137. #include <share.h>
  138. extern int binary;            /* We need to know this for open() */
  139. extern int fncact;            /* Need this for zchkspa()         */
  140. extern int tlevel, cmdlvl ;        /* Need this for external commands */
  141. #ifdef __IBMC__
  142. extern FILE *popen(char *, char *);
  143. extern int pclose(FILE *);
  144. #else
  145. #ifndef __EMX__
  146. #define popen    _popen
  147. #define pclose   _pclose
  148. #define fopen(n, m)  _fsopen(n, m, SH_DENYWR)
  149. #endif /* __EMX__ */
  150. #endif /* __IBMC__ */
  151. #ifdef NT
  152. #include <io.h>
  153. #endif /* NT */
  154. #else /* OS2 */
  155. #include <pwd.h>            /* Password file for shell name */
  156. #endif /* OS2 */
  157.  
  158. #ifdef POSIX
  159. #define UTIMEH
  160. #endif /* POSIX */
  161.  
  162. #ifndef OS2
  163. #ifdef SYSUTIMEH            /* <sys/utime.h> if requested,  */
  164. #include <sys/utime.h>            /* for extra fields required by */
  165. #else                    /* 88Open spec. */
  166. #ifdef UTIMEH                /* or <utime.h> if requested */
  167. #include <utime.h>            /* (SVR4, POSIX) */
  168. #define SYSUTIMEH            /* Use this for both cases. */
  169. #endif /* UTIMEH */
  170. #endif /* SYSUTIMEH */
  171. #endif /* OS2 */
  172.  
  173. #ifdef POSIX
  174. #define TIMESTAMP
  175. #endif /* POSIX */
  176.  
  177. #ifdef BSD44                /* BSD 4.4 */
  178. #ifndef TIMESTAMP
  179. #define TIMESTAMP            /* Can do file dates */
  180. #endif /* TIMESTAMP */
  181. #include <sys/time.h>
  182. #include <sys/timeb.h>
  183.  
  184. #else  /* Not BSD44 */
  185.  
  186. #ifdef BSD4                /* BSD 4.3 and below */
  187. #define TIMESTAMP            /* Can do file dates */
  188. #include <time.h>            /* Need this */
  189. #include <sys/timeb.h>            /* Need this if really BSD */
  190.  
  191. #else  /* Not BSD 4.3 and below */
  192.  
  193. #ifdef SVORPOSIX            /* System V or POSIX */
  194. #ifndef TIMESTAMP
  195. #define TIMESTAMP
  196. #endif /* TIMESTAMP */
  197. #include <time.h>
  198.  
  199. /* void tzset(); (the "void" type upsets some compilers) */
  200. #ifndef IRIX60
  201. #ifndef ultrix
  202. #ifndef CONVEX9
  203. /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
  204. #ifndef Plan9
  205. extern long timezone;
  206. #endif /* Plan9 */
  207. #endif /* CONVEX9 */
  208. #endif /* ultrix */
  209. #endif /* IRIX60 */
  210. #endif /* SVORPOSIX */
  211. #endif /* BSD4 */
  212. #endif /* BSD44 */
  213.  
  214. /* Is `y' a leap year? */
  215. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  216.  
  217. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  218. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  219.  
  220. #ifdef CIE
  221. #include <stat.h>            /* File status */
  222. #else
  223. #include <sys/stat.h>
  224.  
  225. #ifdef OS2
  226. #include <sys/types.h>
  227.  
  228. /* Because standard stat has trouble with trailing /'s we have to wrap it */
  229.  
  230. #ifdef NT
  231. int os2stat(char *, struct _stat *);
  232. #else /* NT */
  233. int os2stat(char *, struct stat *);
  234. #endif /* NT */
  235.  
  236. #ifdef __IBMC__
  237. #ifdef system
  238. #undef system
  239. #endif
  240. #ifdef stat
  241. #undef stat
  242. #define __IBMC__STAT
  243. #endif
  244. #endif
  245. #define stat(path, buf) os2stat(path, buf)
  246. #endif /* OS2 */
  247. #endif /* CIE */
  248.  
  249. /*
  250.   Functions (n is one of the predefined file numbers from ckcker.h):
  251.  
  252.    zopeni(n,name)   -- Opens an existing file for input.
  253.    zopeno(n,name,attr,fcb) -- Opens a new file for output.
  254.    zclose(n)        -- Closes a file.
  255.    zchin(n,&c)      -- Gets the next character from an input file.
  256.    zsinl(n,&s,x)    -- Read a line from file n, max len x, into address s.
  257.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  258.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  259.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  260.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  261.    zchki(name)      -- Check if named file exists and is readable, return size.
  262.    zchko(name)      -- Check if named file can be created.
  263.    zchkspa(name,n)  -- Check if n bytes available to create new file, name.
  264.    znewn(name,s)    -- Make a new unique file name based on the given name.
  265.    zdelet(name)     -- Delete the named file.
  266.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  267.    znext(string)    -- Returns the next file from the list in "string".
  268.    zxcmd(n,cmd)     -- Execute the command in a lower fork on file number n.
  269.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  270.    zrtol(n1,n2)     -- Convert remote filename into local form.
  271.    zltor(n1,n2)     -- Convert local filename into remote form.
  272.    zchdir(dirnam)   -- Change working directory.
  273.    zhome()          -- Return pointer to home directory name string.
  274.    zkself()         -- Kill self, log out own job.
  275.    zsattr(struct zattr *) -- Return attributes for file which is being sent.
  276.    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
  277.    zrename(old, new) -- Rename a file.
  278.    zcopy(source,destination) -- Copy a file.
  279.    zmkdir(path)       -- Create the directory path if possible  
  280.    zfnqfp(fname,len,fullpath) - Determine full path for file name.
  281. */
  282.  
  283. /* Kermit-specific includes */
  284. /*
  285.   Definitions here supersede those from system include files.
  286.   ckcdeb.h is included above.
  287. */
  288. #include "ckcker.h"            /* Kermit definitions */
  289. #include "ckucmd.h"            /* For sys-dependent keyword tables */
  290. #include "ckuver.h"            /* Version herald */
  291.  
  292. char *ckzsys = HERALD;
  293.  
  294. /*
  295.   File access checking ...  There are two calls to access() in this module.
  296.   If this program is installed setuid or setgid on a Berkeley-based UNIX
  297.   system that does NOT incorporate the saved-original-effective-uid/gid
  298.   feature, then, when we have swapped the effective and original uid/gid,
  299.   access() fails because it uses what it thinks are the REAL ids, but we have
  300.   swapped them.  This occurs on systems where ANYBSD is defined, NOSETREU
  301.   is NOT defined, and SAVEDUID is NOT defined.  So, in theory, we should take
  302.   care of this situation like so:
  303.  
  304.     ifdef ANYBSD
  305.     ifndef NOSETREU
  306.     ifndef SAVEDUID
  307.     define SW_ACC_ID
  308.     endif
  309.     endif
  310.     endif
  311.  
  312.   But we can't test such a general scheme everywhere, so let's only do this
  313.   when we know we have to...
  314. */
  315. #ifdef NEXT                /* NeXTSTEP 1.0-3.0 */
  316. #define SW_ACC_ID
  317. #endif /* NEXT */
  318.  
  319. /* Support for tilde-expansion in file and directory names */
  320.  
  321. #ifdef POSIX
  322. #define NAMEENV "LOGNAME"
  323. #endif /* POSIX */
  324.  
  325. #ifdef BSD4
  326. #define NAMEENV "USER"
  327. #endif /* BSD4 */
  328.  
  329. #ifdef ATTSV
  330. #define NAMEENV "LOGNAME"
  331. #endif /* ATTSV */
  332.  
  333. /* Berkeley Unix Version 4.x */
  334. /* 4.1bsd support from Charles E Brooks, EDN-VAX */
  335.  
  336. #ifdef BSD4
  337. #ifdef MAXNAMLEN
  338. #define BSD42
  339. #endif /* MAXNAMLEN */
  340. #endif /* BSD4 */
  341.  
  342. /* Definitions of some system commands */
  343.  
  344. #ifdef OS2
  345. char *CPYCMD = "copy ";         /* For file copy */
  346. char *DELCMD = "del ";            /* For file deletion */
  347. char *RENCMD = "rename ";       /* For file rename */
  348. char *PWDCMD = "chdir ";        /* For saying where I am */
  349. char *TYPCMD = "type ";            /* For typing a file */
  350. char *DIRCMD = "dir ";            /* For directory listing */
  351. char *DIRCM2 = "dir ";            /* For directory listing, no args */
  352. #ifdef NT
  353. char *WHOCMD = "@echo  Kermit 95 Server"; /* Who's there? */
  354. #else /* NT */
  355. char *WHOCMD = "@echo  K/2 Server"; /* Who's there? */
  356. #endif /* NT */
  357. char *SPACMD = "dir | find \"bytes free\""; /* For space on disk */
  358. char *SPACM2 = "dir | find \"bytes free\""; /* For space on disk */
  359.  
  360. #else /* Not OS2, ergo UNIX (or Aegis) */
  361.  
  362. char *DELCMD = "rm -f ";        /* For file deletion */
  363. char *CPYCMD = "cp ";           /* For file copy */
  364. char *RENCMD = "mv ";           /* For file rename */
  365. char *PWDCMD = "pwd ";            /* For saying where I am */
  366.  
  367. #ifdef COMMENT
  368. #ifdef HPUX10
  369. char *DIRCMD = "/usr/bin/ls -l ";    /* For directory listing */
  370. char *DIRCM2 = "/usr/bin/ls -l ";    /* For directory listing, no args */
  371. #else
  372. char *DIRCMD = "/bin/ls -l ";        /* For directory listing */
  373. char *DIRCM2 = "/bin/ls -l ";        /* For directory listing, no args */
  374. #endif /* HPUX10 */
  375. #else
  376. char *DIRCMD = "ls -l ";        /* For directory listing */
  377. char *DIRCM2 = "ls -l ";        /* For directory listing, no args */
  378. #endif /* COMMENT */
  379.  
  380. char *TYPCMD = "cat ";            /* For typing a file */
  381.  
  382. #ifdef FT18                /* Fortune For:Pro 1.8 */
  383. #undef BSD4
  384. #endif /* FT18 */
  385.  
  386. #ifdef BSD4
  387. char *SPACMD = "pwd ; df .";        /* Space in current directory */
  388. #else
  389. #ifdef FT18
  390. char *SPACMD = "pwd ; du ; df .";
  391. #else
  392. char *SPACMD = "df ";
  393. #endif /* FT18 */
  394. #endif /* BSD4 */
  395.  
  396. char *SPACM2 = "df ";            /* For space in specified directory */
  397.  
  398. #ifdef FT18
  399. #define BSD4
  400. #endif /* FT18 */
  401.  
  402. #ifdef BSD4
  403. char *WHOCMD = "finger ";
  404. #else
  405. char *WHOCMD = "who ";
  406. #endif /* BSD4 */
  407.  
  408. #endif /* OS2 */
  409.  
  410. #ifdef DTILDE                /* For tilde expansion */
  411. _PROTOTYP( char * tilde_expand, (char *) );
  412. #endif /* DTILDE */
  413.  
  414. /* More system-dependent includes, which depend on symbols defined */
  415. /* in the Kermit-specific includes.  Oh what a tangled web we weave... */
  416.  
  417. #ifdef COHERENT                /* <sys/file.h> */
  418. #define NOFILEH
  419. #endif /* COHERENT */
  420.  
  421. #ifdef MINIX
  422. #define NOFILEH
  423. #endif /* MINIX */
  424.  
  425. #ifdef aegis
  426. #define NOFILEH
  427. #endif /* aegis */
  428.  
  429. #ifdef unos
  430. #define NOFILEH
  431. #endif /* unos */
  432.  
  433. #ifndef NOFILEH
  434. #include <sys/file.h>
  435. #endif /* NOFILEH */
  436.  
  437. #ifndef is68k                /* Whether to include <fcntl.h> */
  438. #ifndef BSD41                /* All but a couple UNIXes have it. */
  439. #ifndef FT18
  440. #ifndef COHERENT
  441. #include <fcntl.h>
  442. #endif /* COHERENT */
  443. #endif /* FT18  */
  444. #endif /* BSD41 */
  445. #endif /* not is68k */
  446.  
  447. #ifdef COHERENT
  448. #ifdef _I386
  449. #include <fcntl.h>
  450. #else
  451. #include <sys/fcntl.h>
  452. #endif /* _I386 */
  453. #endif /* COHERENT */
  454.  
  455. /*
  456.   Change argument to "(const char *)" if this causes trouble.
  457.   Or... if it causes trouble, then maybe it was already declared 
  458.   in a header file after all, so you can remove this prototype.
  459. */
  460. #ifndef NDGPWNAM /* If not defined No Declare getpwnam... */
  461. #ifndef _POSIX_SOURCE
  462. #ifndef NEXT
  463. #ifndef SVR4
  464. /* POSIX <pwd.h> already gave prototypes for these. */
  465. #ifdef IRIX40
  466. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  467. #else
  468. #ifdef IRIX51
  469. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  470. #else
  471. #ifdef M_UNIX
  472. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  473. #else
  474. #ifdef HPUX9
  475. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  476. #else
  477. #ifdef HPUX10
  478. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  479. #else
  480. #ifdef DCGPWNAM
  481. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  482. #else
  483. _PROTOTYP( struct passwd * getpwnam, (char *) );
  484. #endif /* DCGPWNAM */
  485. #endif /* HPUX10 */
  486. #endif /* HPUX9 */
  487. #endif /* M_UNIX */
  488. #endif /* IRIX51 */
  489. #endif /* IRIX40 */
  490. #ifndef SUNOS4
  491. #ifndef HPUX9
  492. #ifndef HPUX10
  493. #ifndef _SCO_DS
  494. _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
  495. #endif /* _SCO_DS */
  496. #endif /* HPUX10 */
  497. #endif /* HPUX9 */
  498. #endif /* SUNOS4 */
  499. _PROTOTYP( struct passwd * getpwent, (void) );
  500. #endif /* SVR4 */
  501. #endif /* NEXT */
  502. #endif /* _POSIX_SOURCE */
  503. #endif /* NDGPWNAM */
  504.  
  505. /* Define macros for getting file type */
  506.  
  507. #ifdef OXOS
  508. /*
  509.   Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
  510.   incorrectly, so we force their redefinition.
  511. */
  512. #undef S_ISREG
  513. #undef S_ISDIR
  514. #endif /* OXOS */
  515.  
  516. #ifdef UTSV                /* Same deal for Amdahl UTSV */
  517. #undef S_ISREG
  518. #undef S_ISDIR
  519. #endif /* UTSV */
  520.  
  521. #ifdef UNISYS52                /* And for UNISYS UTS V 5.2 */
  522. #undef S_ISREG
  523. #undef S_ISDIR
  524. #endif /* UNISYS52 */
  525.  
  526. #ifdef ICLSVR3                /* And for old ICL versions */
  527. #undef S_ISREG
  528. #undef S_ISDIR
  529. #endif /* ICLSVR3 */
  530.  
  531. #ifdef ISDIRBUG                /* Also allow this from command line */
  532. #ifdef S_ISREG
  533. #undef S_ISREG
  534. #endif /* S_ISREG */
  535. #ifdef S_ISDIR
  536. #undef S_ISDIR
  537. #endif /*  S_ISDIR */
  538. #endif /* ISDIRBUG */
  539.  
  540. #ifndef S_ISREG
  541. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  542. #endif /* S_ISREG */
  543. #ifndef S_ISDIR
  544. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  545. #endif /* S_ISDIR */
  546.  
  547. /* Define maximum length for a file name if not already defined */
  548.  
  549. #ifdef QNX
  550. #ifdef _MAX_FNAME
  551. #define MAXNAMLEN _MAX_FNAME
  552. #else
  553. #define MAXNAMLEN 48
  554. #endif /* _MAX_FNAME */
  555. #else
  556. #ifndef MAXNAMLEN
  557. #ifdef sun
  558. #define MAXNAMLEN 255
  559. #else
  560. #ifdef FILENAME_MAX
  561. #define MAXNAMLEN FILENAME_MAX
  562. #else
  563. #ifdef NAME_MAX
  564. #define MAXNAMLEN NAME_MAX
  565. #else
  566. #ifdef _POSIX_NAME_MAX
  567. #define MAXNAMLEN _POSIX_NAME_MAX
  568. #else
  569. #ifdef _D_NAME_MAX
  570. #define MAXNAMLEN _D_NAME_MAX
  571. #else
  572. #ifdef DIRSIZ
  573. #define MAXNAMLEN DIRSIZ
  574. #else
  575. #define MAXNAMLEN 14
  576. #endif /* DIRSIZ */
  577. #endif /* _D_NAME_MAX */
  578. #endif /* _POSIX_NAME_MAX */
  579. #endif /* NAME_MAX */
  580. #endif /* FILENAME_MAX */
  581. #endif /* sun */
  582. #endif /* MAXNAMLEN */
  583. #endif /* QNX */
  584.  
  585. /* Longest pathname ... */
  586. /*
  587.   Beware: MAXPATHLEN is one of UNIX's dirty little secrets.  Where is it
  588.   defined?  Who knows...  <param.h>, <mod.h>, <unistd.h>, <limits.h>, ...
  589.   There is not necessarily even a definition for it anywhere, or it might have
  590.   another name.  If you get it wrong, bad things happen with getcwd() and/or
  591.   getwd().  If you allocate a buffer that is too short, getwd() might write
  592.   over memory and getcwd() will fail with ERANGE.  The definitions of these
  593.   functions (e.g. in SVID or POSIX.1) do not tell you how to determine the
  594.   maximum path length in order to allocate a buffer that is the right size.
  595. */
  596. #ifdef BSD44
  597. #include <sys/param.h>            /* For MAXPATHLEN */
  598. #endif /* BSD44 */
  599.  
  600. #ifdef COHERENT
  601. #include <sys/param.h>    /* for MAXPATHLEN, needed for -DDIRENT */
  602. #endif /* COHERENT */
  603.  
  604. #ifdef MAXPATHLEN
  605. #ifdef MAXPATH
  606. #undef MAXPATH
  607. #endif /* MAXPATH */
  608. #define MAXPATH MAXPATHLEN
  609. #else
  610. #ifdef PATH_MAX
  611. #define MAXPATH PATH_MAX
  612. #else
  613. #ifdef _POSIX_PATH_MAX
  614. #define MAXPATH _POSIX_PATH_MAX
  615. #else
  616. #ifdef BSD42
  617. #define MAXPATH 1024
  618. #else
  619. #ifdef SVR4  
  620. #define MAXPATH 1024
  621. #else
  622. #define MAXPATH 255
  623. #endif /* SVR4 */
  624. #endif /* BSD42 */
  625. #endif /* _POSIX_PATH_MAX */
  626. #endif /* PATH_MAX */
  627. #endif /* MAXPATHLEN */
  628.  
  629. /* Maximum number of filenames for wildcard expansion */
  630.  
  631. #ifdef PROVX1
  632. #define MAXWLD 50
  633. #else
  634. #ifdef pdp11
  635. #define MAXWLD 50
  636. #else
  637. #ifdef BIGBUFOK
  638. #define MAXWLD 4096
  639. #else
  640. #define MAXWLD 1000
  641. #endif /* BIGBUFOK */
  642. #endif /* pdp11 */
  643. #endif /* PROVX1 */
  644.  
  645. /* More internal function prototypes */
  646. /*
  647.  * The path structure is used to represent the name to match.
  648.  * Each slash-separated segment of the name is kept in one
  649.  * such structure, and they are linked together, to make
  650.  * traversing the name easier.
  651.  */
  652. struct path {
  653.     char npart[MAXNAMLEN+4];        /* name part of path segment */
  654.     struct path *fwd;            /* forward ptr */
  655. };
  656. #ifndef NOPUSH
  657. _PROTOTYP( int shxpand, (char *, char *[], int ) );
  658. extern int nopush;
  659. #endif /* NOPUSH */
  660. _PROTOTYP( static int fgen, (char *, char *[], int ) );
  661. _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
  662. _PROTOTYP( static VOID addresult, (char *) );
  663. _PROTOTYP( static int match, (char *, char *) );
  664. _PROTOTYP( static char * whoami, (void) );
  665. #ifdef aegis
  666. _PROTOTYP( static char * xindex, (char *, char) );
  667. #endif /* aegis */
  668. _PROTOTYP( UID_T real_uid, (void) );
  669. _PROTOTYP( struct path *splitpath, (char *p) );
  670. _PROTOTYP( char * zdtstr, (time_t) );
  671. _PROTOTYP( time_t zstrdt, (char *, int) );
  672.  
  673. /* Some systems define these symbols in include files, others don't... */
  674.  
  675. #ifndef R_OK
  676. #define R_OK 4                /* For access */
  677. #endif /* R_OK */
  678.  
  679. #ifndef W_OK
  680. #define W_OK 2
  681. #endif /* W_OK */
  682.  
  683. #ifndef O_RDONLY
  684. #define O_RDONLY 000
  685. #endif /* O_RDONLY */
  686.  
  687. /* Declarations */
  688.  
  689. int maxnam = MAXNAMLEN;            /* Available to the outside */
  690. int maxpath = MAXPATH;
  691. int ck_znewn = -1;
  692.  
  693. FILE *fp[ZNFILS] = {             /* File pointers */
  694.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  695. #ifdef OS2
  696. int ispipe[ZNFILS];            /* Flag for file is a pipe */
  697. #endif /* OS2 */
  698.  
  699. /* Buffers and pointers used in buffered file input and output. */
  700. #ifdef DYNAMIC
  701. extern char *zinbuffer, *zoutbuffer;
  702. #else
  703. extern char zinbuffer[], zoutbuffer[];
  704. #endif /* DYNAMIC */
  705. extern char *zinptr, *zoutptr;
  706. extern int zincnt, zoutcnt;
  707. extern int wildxpand;
  708.  
  709. extern UID_T real_uid();
  710.  
  711. static long iflen = -1L;        /* Input file length */
  712.  
  713. static PID_T pid = 0;            /* pid of child fork */
  714. static int fcount;            /* Number of files in wild group */
  715. static char nambuf[MAXNAMLEN+4];    /* Buffer for a filename */
  716. #ifndef NOFRILLS
  717. static char zmbuf[200];            /* For mail, remote print strings */
  718. #endif /* NOFRILLS */
  719.  
  720. #ifndef OS2
  721. /* static */                /* Not static, must be global now. */
  722. char **mtchs = NULL;            /* Matches found for filename */
  723. char **mtchptr = NULL;            /* Pointer to current match */
  724. #endif /* OS2 */
  725.  
  726. #ifdef OS2
  727. #ifndef NT
  728. #define INCL_KBD
  729. #define INCL_DOSERRORS
  730. #define INCL_DOSFILEMGR
  731. #define INCL_DOSPROCESS
  732. #define INCL_DOSSEMAPHORES
  733. #include <os2.h>
  734. typedef unsigned short WORD;
  735. #undef COMMENT
  736.  
  737. /* Get/Set All Extended Attributes support */ 
  738.  
  739. #define FreeMem(p) DosFreeMem(p)
  740.  
  741. #define MAX_GEA            500L  /* Max size for a GEA List */
  742. #define MAXEACOUNT          128  /* Max number of EA's supported */
  743. #define Ref_ASCIIZ            1  /* Reference type for DosEnumAttribute */
  744.  
  745. /* Definition of level specifiers, required for File Info */
  746.  
  747. #define GetInfoLevel1         1            /* Get info from SFT */
  748. #define GetInfoLevel2         2            /* Get size of FEAlist */
  749. #define GetInfoLevel3         3            /* Get FEAlist given the GEAlist */
  750. #define GetInfoLevel4         4            /* Get whole FEAlist */
  751. #define GetInfoLevel5         5            /* Get FSDname */
  752.  
  753. #define SetInfoLevel1         1            /* Set info in SFT */
  754. #define SetInfoLevel2         2            /* Set FEAlist */
  755.  
  756. FEA2LIST *pFEAList = 0;     /* Pointer to buffer containing all EA information */
  757. ULONG os2attrs = FILE_NORMAL;
  758. extern unsigned int lf_opts;
  759.  
  760. #else /* NT */
  761.  
  762. #include <windows.h>
  763. #endif /* NT */
  764. char os2filename[MAXPATH];
  765. #endif /* OS2 */
  766.  
  767. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  768.  
  769. /* Note, should get current pid, but if your system doesn't have */
  770. /* getppid(), then just kill(0,9)...  */
  771.  
  772. #ifndef SVR3
  773. #ifndef POSIX
  774. #ifndef OSFPC
  775. /* Already declared in unistd.h for SVR3 and POSIX */
  776. #ifdef CK_ANSIC
  777. extern PID_T getppid(void);
  778. #else
  779. #ifndef PS2AIX10
  780. extern PID_T getppid();
  781. #endif /* PS2AIX10 */
  782. #endif /* CK_ANSIC */
  783. #endif /* OSFPC */
  784. #endif /* POSIX */
  785. #endif /* SVR3 */
  786.  
  787. int
  788. zkself() {                /* For "bye", but no guarantee! */
  789. #ifdef PROVX1
  790.     return(kill(0,9));
  791. #else
  792. #ifdef V7
  793.     return(kill(0,9));
  794. #else
  795. #ifdef TOWER1
  796.     return(kill(0,9));
  797. #else
  798. #ifdef FT18
  799.     return(kill(0,9));
  800. #else
  801. #ifdef aegis
  802.     return(kill(0,9));
  803. #else
  804. #ifdef COHERENT
  805.     return(kill((PID_T)getpid(),1));
  806. #else
  807. #ifdef OS2
  808.     exit(3);
  809.     return(0);
  810. #else
  811. #ifdef PID_T
  812.     exit(kill((PID_T)getppid(),1));
  813.     return(0);
  814. #else
  815.     exit(kill(getppid(),1));
  816.     return(0);
  817. #endif
  818. #endif
  819. #endif
  820. #endif
  821. #endif
  822. #endif
  823. #endif
  824. #endif
  825. }
  826.  
  827. /*  Z O P E N I  --  Open an existing file for input. */
  828.  
  829. int
  830. zopeni(n,name) int n; char *name; {
  831.     int x, y;
  832.  
  833.     debug(F111," zopeni",name,n);
  834.     debug(F101,"  fp","", fp[n]);
  835.     if (chkfn(n) != 0) return(0);
  836.     zincnt = 0;                /* Reset input buffer */
  837.     if (n == ZSYSFN) {            /* Input from a system function? */
  838. /*** Note, this function should not be called with ZSYSFN ***/
  839. /*** Always call zxcmd() directly, and give it the real file number ***/
  840. /*** you want to use.  ***/
  841.         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
  842.     *nambuf = '\0';            /* No filename. */
  843.     return(0);            /* fail. */
  844. #ifdef COMMENT
  845.     return(zxcmd(n,name));        /* Try to fork the command */
  846. #endif
  847.     }
  848.     if (n == ZSTDIO) {            /* Standard input? */
  849.     if (is_a_tty(0)) {
  850.         fprintf(stderr,"Terminal input not allowed");
  851.         debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  852.         return(0);
  853.     }
  854.     fp[ZIFILE] = stdin;
  855. #ifdef OS2
  856. #ifdef NT
  857.     _setmode(_fileno(stdin),O_BINARY);
  858. #else
  859.     setmode(fileno(stdin),O_BINARY);
  860. #endif /* NT */
  861. #endif /* OS2 */
  862.     return(1);
  863.     }
  864. #ifdef OS2
  865.     if (n == ZIFILE || n == ZRFILE) {
  866.     strncpy( os2filename, name, MAXPATH ) ;
  867.     errno = 0;
  868. #ifdef NT
  869.     fp[n] = _fsopen(name,"rb",_SH_DENYWR);        /* Binary mode */
  870. #else
  871.     fp[n] = fopen(name,"rb");/* Binary mode */
  872. #endif /* NT */
  873.     if (fp[ZIFILE]) {
  874.         x = ferror(fp[ZIFILE]);
  875. #ifdef ZDEBUG
  876.         printf("ZOPENI errno=%d\n",errno);
  877.         printf("ZOPENI ferror=%d\n",x);
  878. #endif /* ZDEBUG */
  879.     }
  880. #ifdef CK_LABELED
  881.     if (binary == XYFT_L) {
  882.         os2getattr(name);
  883.         os2geteas(name);
  884.     }
  885. #endif /* CK_LABELED */
  886.     } else
  887. #ifdef NT
  888.     fp[n] = _fsopen(name,"rb",_SH_DENYWR); /* Real file, open it. */
  889. #else
  890.         fp[n] = fopen(name,"rb");/* Real file, open it. */
  891. #endif /* NT */
  892. #else /* OS2 */
  893.     fp[n] = fopen(name,"r");        /* Real file, open it. */
  894. #endif /* OS2 */
  895.     debug(F111," zopeni", name, fp[n]);
  896. #ifdef ZDEBUG
  897.     printf("ZOPENI fp[%d]=%ld\n",n,fp[n]);
  898. #endif /* ZDEBUG */
  899.     if (fp[n] == NULL)
  900.       perror("zopeni");
  901.     else
  902.       clearerr(fp[n]);
  903.     return((fp[n] != NULL) ? 1 : 0);
  904. }
  905.  
  906. /*  Z O P E N O  --  Open a new file for output.  */
  907.  
  908. int
  909. zopeno(n,name,zz,fcb)
  910. /* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
  911.  
  912.     char p[8];                /* (===OS2 change===) */
  913.  
  914. /* As of Version 5A, the attribute structure and the file information */
  915. /* structure are included in the arglist. */
  916.  
  917. #ifdef DEBUG
  918.     debug(F111,"zopeno",name,n);
  919.     if (fcb) {
  920.     debug(F101,"zopeno fcb disp","",fcb->dsp);
  921.     debug(F101,"zopeno fcb type","",fcb->typ);
  922.     debug(F101,"zopeno fcb char","",fcb->cs);
  923.     } else {
  924.     debug(F100,"zopeno fcb is NULL","",0);
  925.     }
  926.     if (n != ZDFILE)
  927.       debug(F111," zopeno",name,n);
  928. #endif /* DEBUG */
  929.  
  930.     if (chkfn(n) != 0)            /* Already open? */
  931.       return(0);            /* Nothing to do. */
  932.  
  933.     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
  934.     fp[ZOFILE] = stdout;
  935. #ifdef DEBUG
  936.     if (n != ZDFILE)
  937.       debug(F101," fp[]=stdout", "", fp[n]);
  938. #endif /* DEBUG */
  939.     zoutcnt = 0;
  940.     zoutptr = zoutbuffer;
  941.     return(1);
  942.     }
  943.  
  944. /* A real file.  Open it in desired mode (create or append). */
  945.  
  946.     strcpy(p,"w");            /* Assume write/create mode */
  947.     if (fcb) {                /* If called with an FCB... */
  948.     if (fcb->dsp == XYFZ_A) {    /* Does it say Append? */
  949.         strcpy(p,"a");        /* Yes. */
  950.         debug(F100,"zopeno append","",0);
  951.     }
  952.     }
  953. #ifdef OS2
  954.     if (n == ZOFILE || n == ZSFILE) {    /* OS/2 binary mode */
  955.     strncpy( os2filename, name, MAXPATH ) ;
  956.     strcat(p,"b");
  957.     }
  958. #endif /* OS2 */
  959.     debug(F110,"zopeno fopen arg",p,0);
  960.     fp[n] = fopen(name,p);        /* Try to open the file */
  961.  
  962. #ifdef ZDEBUG 
  963. printf("ZOPENO fp[%d]=%ld\n",n,fp[n]);
  964. #endif /* ZDEBUG */
  965.  
  966.     if (fp[n] == NULL) {        /* Failed */
  967.     debug(F101,"zopeno failed errno","",errno);
  968. #ifdef COMMENT                /* Let upper levels print message. */
  969.         perror("Can't open output file");
  970. #endif /* COMMENT */
  971.     } else {                /* Succeeded */
  972.         if (n == ZDFILE)        /* If it's the debug log */
  973.       setbuf(fp[n],NULL);        /* make it unbuffered */
  974.     else
  975.       debug(F100, "zopeno ok", "", 0);
  976.     }
  977.     zoutcnt = 0;            /* (PWP) reset output buffer */
  978.     zoutptr = zoutbuffer;
  979.     return((fp[n] != NULL) ? 1 : 0);
  980. }
  981.  
  982. /*  Z C L O S E  --  Close the given file.  */
  983.  
  984. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  985.  
  986. int
  987. zclose(n) int n; {
  988.     int x, x2;
  989.     if (chkfn(n) < 1) return(0);    /* Check range of n */
  990.  
  991.     if ((n == ZOFILE) && (zoutcnt > 0))    /* (PWP) output leftovers */
  992.       x2 = zoutdump();
  993.     else
  994.       x2 = 0;
  995.  
  996.     x = 0;                /* Initialize return code */
  997.     if (fp[ZSYSFN]
  998. #ifdef OS2
  999.      || ispipe[n]            /* If file is really pipe */
  1000. #endif /* OS2 */
  1001.         ) {            
  1002.         x = zclosf(n);            /* do it specially */
  1003.     } else {
  1004.     if ((fp[n] != stdout) && (fp[n] != stdin)) 
  1005.       x = fclose(fp[n]);
  1006.     fp[n] = NULL;
  1007. #ifdef OS2
  1008. #ifdef CK_LABELED
  1009.     if (binary == XYFT_L) {
  1010.         debug(F111,"zclose LABELED","file number",n);
  1011.         if (n == ZOFILE) {
  1012.         debug(F111,"zclose LABELED",
  1013.               "lf_opts && LBL_EXT",
  1014.               lf_opts && LBL_EXT
  1015.               );
  1016.         if (lf_opts && LBL_EXT)
  1017.           os2seteas(os2filename);      
  1018.         os2setattr(os2filename);
  1019.         } else if (n == ZIFILE && pFEAList) {
  1020.         FreeMem(pFEAList);
  1021.         pFEAList = 0;
  1022.         }
  1023.     }
  1024. #endif /* CK_LABELED */
  1025. #endif /* OS2 */
  1026.     }
  1027.     iflen = -1L;            /* Invalidate file length */
  1028.     if (x == EOF) {            /* if we got a close error */
  1029.     debug(F101,"zclose fclose fails","",x);
  1030.     return(-1);
  1031.     } else if (x2 < 0) {        /* or error flushing last buffer */
  1032.     debug(F101,"zclose error flushing last buffer","",x2);
  1033.     return(-1);        /* then return an error */
  1034.     } else {
  1035.     debug(F101,"zclose success","",1);
  1036.     return(1);
  1037.     }
  1038. }
  1039.  
  1040. /*  Z C H I N  --  Get a character from the input file.  */
  1041.  
  1042. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  1043.  
  1044. int
  1045. zchin(n,c) int n; int *c; {
  1046.     int a, x;
  1047.  
  1048.     /* (PWP) Just in case this gets called when it shouldn't. */
  1049.     if (n == ZIFILE) {
  1050.     x = zminchar();
  1051.     *c = x;
  1052.     return(x);
  1053.     }
  1054.     /* if (chkfn(n) < 1) return(-1); */
  1055.     a = getc(fp[n]);
  1056.     if (a == EOF) return(-1);
  1057. #ifdef OS2
  1058.     if (!binary && a == 0x1A)        /* Ctrl-Z marks EOF for text mode*/
  1059.       return(-1);
  1060. #endif
  1061.     *c = (CHAR) a & 0377;
  1062.     return(0);
  1063. }
  1064.  
  1065. /*  Z S I N L  --  Read a line from a file  */
  1066.  
  1067. /*
  1068.   Writes the line into the address provided by the caller.
  1069.   n is the Kermit "channel number".
  1070.   Writing terminates when newline is encountered, newline is not copied.
  1071.   Writing also terminates upon EOF or if length x is exhausted.
  1072.   Returns 0 on success, -1 on EOF or error.
  1073. */
  1074. int
  1075. zsinl(n,s,x) int n, x; char *s; {
  1076.     int a, z = 0;            /* z is return code. */
  1077.     extern CHAR feol;            /* Line terminator */
  1078.  
  1079.     if (chkfn(n) < 1) {            /* Make sure file is open */
  1080.     return(-1);
  1081.     }
  1082.     a = -1;                /* Current character, none yet. */
  1083.     while (x--) {            /* Up to given length */
  1084.     int old;
  1085.     if (feol) old = a;        /* Previous character */
  1086.  
  1087.     if (zchin(n,&a) < 0) {        /* Read a character from the file */
  1088.         debug(F101,"zsinl","",a);
  1089.         z = -1;            /* EOF or other error */
  1090.         break;
  1091.     }
  1092.  
  1093.     if (feol) {            /* Single-character line terminator */
  1094.         if (a == feol)
  1095.           break;    
  1096.     } else {            /* CRLF line terminator */
  1097.         if (a == '\015')        /* CR, get next character */
  1098.           continue;
  1099.         if (old == '\015') {    /* Previous character was CR */
  1100.         if (a == '\012')    /* This one is LF, so we have a line */
  1101.           break;
  1102.         else            /* Not LF, deposit CR */
  1103.           *s++ = '\015';
  1104.         }
  1105. #ifdef OS2
  1106.         if (a == '\012') break;    /* Here break on single LF too */
  1107. #endif /* OS2 */
  1108.     }
  1109.     *s = a;                /* Deposit character */
  1110.     s++;
  1111.     }
  1112.     *s = '\0';                /* Terminate the string */
  1113.     return(z);
  1114. }
  1115.  
  1116. /*  Z X I N  --  Read x bytes from a file  */
  1117.  
  1118. /*
  1119.   Reads x bytes (or less) from channel n and writes them
  1120.   to the address provided by the caller.
  1121.   Returns number of bytes read on success, 0 on EOF or error.
  1122. */
  1123. int
  1124. zxin(n,s,x) int n, x; char *s; {
  1125.     return(fread(s, sizeof (char), x, fp[n]));
  1126. }
  1127.  
  1128. /*
  1129.   Z I N F I L L  --  Buffered file input.
  1130.  
  1131.   (re)fill the file input buffer with data.  All file input
  1132.   should go through this routine, usually by calling the zminchar()
  1133.   macro defined in ckcker.h.  Returns:
  1134.  
  1135.   Value 0..255 on success, the character that was read.
  1136.   -1 on end of file.
  1137.   -2 on any kind of error other than end of file.
  1138. */
  1139. int
  1140. zinfill() {
  1141.     int x;
  1142.  
  1143.     errno = 0;
  1144.  
  1145. #ifdef ZDEBUG 
  1146. printf("ZINFILL fp[%d]=%ld\n",ZIFILE,fp[ZIFILE]);
  1147. #endif /* ZDEBUG */
  1148.  
  1149. #ifdef OS2
  1150. #ifdef CK_LABELED
  1151.     debug(F101,"zinfill: binary","",binary);
  1152.     debug(F101,"zinfill: pFEAList","",pFEAList);
  1153.     if ( binary == XYFT_L && pFEAList ) {
  1154.     zinptr = zinbuffer ;
  1155.     do_label_send(os2filename) ;
  1156.     if (feof(fp[ZIFILE]))
  1157.       return(-1);
  1158.     clearerr(fp[ZIFILE]);
  1159.     zincnt += fread(zinptr, sizeof (char), INBUFSIZE - zincnt, fp[ZIFILE]);
  1160.     } else {
  1161. #endif /* CK_LABELED */
  1162. #endif /* OS2 */
  1163.  
  1164.     if (feof(fp[ZIFILE])) {
  1165.         debug(F100,"ZINFILL feof","",0);
  1166. #ifdef ZDEBUG 
  1167.         printf("ZINFILL EOF\n");
  1168. #endif /* ZDEBUG */
  1169.         return(-1);
  1170.     }
  1171.     clearerr(fp[ZIFILE]);
  1172.     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  1173.     debug(F101,"ZINFILL fread","",zincnt);
  1174. #ifdef ZDEBUG 
  1175.     printf("FREAD=%d\n",zincnt);
  1176. #endif /* ZDEBUG */
  1177. #ifdef OS2
  1178. #ifdef CK_LABELED
  1179.     }
  1180. #endif /* CK_LABELED */
  1181. #endif /* OS2 */
  1182.  
  1183.     if (ferror(fp[ZIFILE])) {
  1184.     debug(F100,"ZINFILL ferror","",0);
  1185.     debug(F100,"ZINFILL errno","",errno);
  1186. #ifdef ZDEBUG 
  1187.     printf("ZINFILL errno=%d\n",errno);
  1188. #endif /* ZDEBUG */
  1189.     return(-2);
  1190.     }
  1191.     /* In case feof() didn't work just above -- sometimes it doesn't... */
  1192.     if (zincnt == 0) {
  1193.        if (feof(fp[ZIFILE]) ) {
  1194.        debug(F100,"ZINFILL count 0 EOF return -1","",0);
  1195.        return (-1);
  1196.        } else {
  1197.        debug(F100,"ZINFILL count 0 not EOF return -2","",0);
  1198.        return(-2);
  1199.        }
  1200.     }
  1201.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  1202.     zincnt--;                /* One less char in buffer */
  1203.     return((int)(*zinptr++) & 0377);    /* because we return the first */
  1204. }
  1205.  
  1206. /*  Z S O U T  --  Write a string out to the given file, buffered.  */
  1207.  
  1208. int
  1209. zsout(n,s) int n; char *s; {
  1210.     if (chkfn(n) < 1) return(-1);    /* Keep this, prevents memory faults */
  1211.     if (!s) return(0);            /* Null pointer, do nothing, succeed */
  1212.     if (!*s) return(0);            /* empty string, ditto */
  1213. #ifdef OS2
  1214.     if (n == ZCTERM)
  1215.       return(Vscrnprintf(s));
  1216. #endif /* OS2 */
  1217.     if (n == ZSFILE)
  1218.       return(write(fileno(fp[n]),s,(int)strlen(s)));
  1219.     return(fputs(s,fp[n]) == EOF ? -1 : 0);
  1220. }
  1221.  
  1222. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  1223.  
  1224. int
  1225. zsoutl(n,s) int n; char *s; {
  1226.     if (zsout(n,s) < 0) 
  1227.         return(-1);
  1228. #ifdef OS2
  1229.     if (n == ZCTERM)
  1230.       return(Vscrnprintf("\n"));
  1231. #endif /* OS2 */
  1232.     if (n == ZSFILE)            /* But session log is unbuffered */
  1233.       return(write(fileno(fp[n]),"\n",1)); 
  1234.     if (fputs("\n",fp[n]) == EOF) 
  1235.         return(-1); /* (===OS2 ? \r\n) */
  1236.     return(0);
  1237. }
  1238.  
  1239. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  1240.  
  1241. int
  1242. zsoutx(n,s,x) int n, x; char *s; {
  1243. #ifdef COMMENT
  1244.     if (chkfn(n) < 1) return(-1);
  1245.     return(write(fp[n]->_file,s,x));
  1246. #endif /* COMMENT */
  1247.  
  1248. #ifdef OS2
  1249.     if (n == ZCTERM) {
  1250.         int i;
  1251.         for (i = 0; i < x; i++)
  1252.           if (!Vscrnprintf("%c",s[i]))
  1253.             return(-1);
  1254.         return(x);
  1255.     }
  1256. #endif /* OS2 */
  1257.     return(write(fileno(fp[n]),s,x) == x ? x : -1);
  1258. }
  1259.  
  1260. /*  Z C H O U T  --  Add a character to the given file.  */
  1261.  
  1262. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  1263.  
  1264. int
  1265. #ifdef CK_ANSIC
  1266. zchout(register int n, char c)
  1267. #else
  1268. zchout(n,c) register int n; char c;
  1269. #endif /* CK_ANSIC */
  1270. /* zchout() */ {
  1271.     /* if (chkfn(n) < 1) return(-1); */
  1272. #ifdef OS2
  1273.     if ( n==ZCTERM ) 
  1274.         return(Vscrnprintf("%c",c));
  1275. #endif /* OS2 */
  1276.     if (n == ZSFILE)             /* Use unbuffered for session log */
  1277.         return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
  1278.                                 /* Buffered for everything else */
  1279.     if (putc(c,fp[n]) == EOF)    /* If true, maybe there was an error */
  1280.         return(ferror(fp[n])?-1:0);    /* Check to make sure */
  1281.     else                    /* Otherwise... */
  1282.         return(0);            /* There was no error. */
  1283. }
  1284.  
  1285. /* (PWP) buffered character output routine to speed up file IO */
  1286.  
  1287. int
  1288. zoutdump() {
  1289.     int x;
  1290.     zoutptr = zoutbuffer;        /* Reset buffer pointer in all cases */
  1291.     debug(F101,"zoutdump chars","",zoutcnt);
  1292.     if (zoutcnt == 0) {            /* Nothing to output */
  1293.     return(0);
  1294.     } else if (zoutcnt < 0) {        /* Unexpected negative argument */
  1295.     zoutcnt = 0;            /* Reset output buffer count */
  1296.     return(-1);            /* and fail. */
  1297.     }
  1298.  
  1299. #ifdef CK_LABELED
  1300.     if (binary == XYFT_L ) {
  1301.     x = do_label_recv() ;
  1302.     if ( x > 0 ) { /* more room in the buffer */
  1303.         debug(F101,"zoutdump do_label_recv unfilled buffer","",zoutcnt);
  1304.         return 0 ; 
  1305.     } else if ( x < 0 ) {
  1306.         debug(F101,"zoutdump do_label_recv error","",x);
  1307.         return -1 ; 
  1308.     }
  1309.     }
  1310. #endif /* CK_LABELED */
  1311. /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
  1312. /* followed by a write() would improve the efficiency, especially when */
  1313. /* writing to stdout.  Subsequent tests showed a 5-fold improvement!   */
  1314. /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {              */
  1315.  
  1316.     fflush(fp[ZOFILE]);
  1317.     if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
  1318.     debug(F101,"zoutdump write ok","",zoutcnt);
  1319.     zoutcnt = 0;            /* Reset output buffer count */
  1320.     return(0);            /* write() worked OK */
  1321.     } else {
  1322.     debug(F101,"zoutdump write error","",errno);
  1323.     debug(F101,"zoutdump write returns","",x);
  1324.     zoutcnt = 0;            /* Reset output buffer count */
  1325.     return(-1);            /* write() failed */
  1326.     }
  1327. }
  1328.  
  1329. /*  C H K F N  --  Internal function to verify file number is ok  */
  1330.  
  1331. /*
  1332.  Returns:
  1333.   -1: File number n is out of range
  1334.    0: n is in range, but file is not open
  1335.    1: n in range and file is open
  1336. */
  1337. int
  1338. chkfn(n) int n; {
  1339. #ifdef COMMENT                /* Save some stack space */
  1340.     switch (n) {
  1341.     case ZCTERM:
  1342.     case ZSTDIO:
  1343.     case ZIFILE:
  1344.     case ZOFILE:
  1345.     case ZDFILE:
  1346.     case ZTFILE:
  1347.     case ZPFILE:
  1348.     case ZSFILE:
  1349.     case ZSYSFN:
  1350.         case ZRFILE:
  1351.         case ZWFILE:
  1352. #ifdef OS2
  1353.         case ZPRINT:
  1354. #endif /* OS2 */
  1355.         break;
  1356.     default:
  1357.         debug(F101,"chkfn: file number out of range","",n);
  1358.         fprintf(stderr,"?File number out of range - %d\n",n);
  1359.         return(-1);
  1360.     }
  1361.     return( (fp[n] == NULL) ? 0 : 1 );
  1362. #else
  1363.     if (n < 0 || n >= ZNFILS)
  1364.       return(-1);
  1365.     else return( (fp[n] == NULL) ? 0 : 1 );
  1366. #endif /* COMMENT */
  1367. }
  1368.  
  1369. /*  Z C H K I  --  Check if input file exists and is readable  */
  1370.  
  1371. /*
  1372.   Returns:
  1373.    >= 0 if the file can be read (returns the size).
  1374.      -1 if file doesn't exist or can't be accessed,
  1375.      -2 if file exists but is not readable (e.g. a directory file).
  1376.      -3 if file exists but protected against read access.
  1377. */
  1378. /*
  1379.  For Berkeley Unix, a file must be of type "regular" to be readable.
  1380.  Directory files, special files, and symbolic links are not readable.
  1381. */
  1382. long
  1383. zchki(name) char *name; {
  1384. #ifdef NT
  1385.     struct _stat buf;
  1386. #else
  1387.     struct stat buf;
  1388. #endif /* NT */
  1389.     int x;
  1390.  
  1391. #ifdef UNIX
  1392.     x = strlen(name);
  1393.     if (x == 9 && !strcmp(name,"/dev/null"))
  1394.       return(0);
  1395. #endif /* UNIX */
  1396.  
  1397.     x = stat(name,&buf);
  1398.     if (x < 0) {
  1399.     debug(F111,"zchki stat fails",name,errno);
  1400.     return(-1);
  1401.     }
  1402.     if (!S_ISREG (buf.st_mode)        /* Must be regular file */
  1403. #ifdef S_ISFIFO
  1404.     && !S_ISFIFO (buf.st_mode)    /* or FIFO */
  1405. #endif /* S_ISFIFO */
  1406.     ) {                
  1407.     debug(F111,"zchki skipping:",name,x);
  1408.     return(-2);
  1409.     }
  1410.     debug(F111,"zchki stat ok:",name,x);
  1411.  
  1412. #ifdef SW_ACC_ID
  1413.     debug(F100,"zchki swapping ids for access()","",0);
  1414.     priv_on();
  1415. #endif /* SW_ACC_ID */
  1416. #ifdef NT
  1417.     x = _access(name,R_OK);
  1418. #else
  1419.     x = access(name,R_OK);
  1420. #endif /* NT */
  1421. #ifdef SW_ACC_ID
  1422.     priv_off();
  1423.     debug(F100,"zchki swapped ids restored","",0);
  1424. #endif /* SW_ACC_ID */
  1425.     if (x < 0) {     /* Is the file accessible? */
  1426.     debug(F111," access failed:",name,x); /* No */
  1427.         return(-3);
  1428.     } else {
  1429.     iflen = buf.st_size;              /* Yes, remember size */
  1430.     strncpy(nambuf,name,MAXNAMLEN);          /* and name globally. */
  1431.     debug(F111," access ok:",name,(int) iflen);
  1432.     return( (iflen > -1L) ? iflen : 0L );
  1433.     }
  1434. }
  1435.  
  1436. /*  Z C H K O  --  Check if output file can be created  */
  1437.  
  1438. /*
  1439.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  1440. */
  1441. int
  1442. zchko(name) char *name; {
  1443.     int i, x;
  1444.     char *s;
  1445.  
  1446.     if (!name) return(-1);        /* Watch out for null pointer. */
  1447.     x = (int)strlen(name);        /* Get length of filename */
  1448.     debug(F101," length","",x);
  1449.  
  1450. #ifdef UNIX
  1451. /*
  1452.   Writing to null device is OK.
  1453. */
  1454.     if (x == 9 && !strcmp(name,"/dev/null"))
  1455.       return(0);
  1456. #endif /* UNIX */
  1457.  
  1458.     if (isdir(name))            /* Directories are not writeable */
  1459.       return(-1);
  1460.  
  1461.     s = malloc(x+3);            /* Must copy because we can't */
  1462.     if (!s) {                /* write into our argument. */
  1463.     fprintf(stderr,"Malloc error 46\n");
  1464.     return(-1);
  1465.     }
  1466.     strcpy(s,name);
  1467.  
  1468.     for (i = x; i > 0; i--)        /* Strip filename from right. */
  1469.       if (ISDIRSEP(s[i-1])) break;
  1470.     debug(F101," i","",i);
  1471.  
  1472. #ifdef COMMENT
  1473. /* X/OPEN XPG3-compliant systems fail if argument ends with "/"...  */
  1474.     if (i == 0)                /* If no path, use current directory */
  1475.       strcpy(s,"./");
  1476.     else                /* Otherwise, use given one. */
  1477.       s[i] = '\0';
  1478. #else
  1479. /* So now we use "path/." if path given, or "." if no path given. */
  1480.     s[i++] = '.';            /* Append "." to path. */
  1481.     s[i] = '\0';
  1482. #endif /* COMMENT */
  1483.  
  1484. #ifdef SW_ACC_ID
  1485.     debug(F100,"zchko swapping ids for access()","",0);
  1486.     priv_on();
  1487. #endif /* SW_ACC_ID */
  1488. #ifdef OS2                /* No unwritable directories in OS/2 */
  1489.     x = 0;
  1490. #else
  1491. #ifdef NT
  1492.     x = _access(s,W_OK);        /* Check access of path. */
  1493. #else
  1494.     x = access(s,W_OK);            /* Check access of path. */
  1495. #endif /* NT */
  1496. #endif /* OS2 */
  1497. #ifdef SW_ACC_ID
  1498.     priv_off();
  1499.     debug(F100,"zchko swapped ids restored","",0);
  1500. #endif /* SW_ACC_ID */
  1501.     if (x < 0)
  1502.       debug(F111,"zchko access failed:",s,errno);
  1503.     else
  1504.       debug(F111,"zchko access ok:",s,x);
  1505.     free(s);                /* Free temporary storage */
  1506.     return((x < 0) ? -1 : 0);        /* and return. */
  1507. }
  1508.  
  1509. /*  Z D E L E T  --  Delete the named file.  */
  1510.  
  1511. int
  1512. zdelet(name) char *name; {
  1513. #ifdef NT
  1514.     return(_unlink(name));
  1515. #else /* NT */
  1516.     return(unlink(name));
  1517. #endif /* NT */
  1518. }
  1519.  
  1520. /*  Z R T O L  --  Convert remote filename into local form  */
  1521.  
  1522. VOID
  1523. zrtol(name,name2) char *name, *name2; {
  1524.     char *p; int flag = 0, n = 0;
  1525.     int acase = 0;
  1526.     if (!name || !name2) return;
  1527.     debug(F101,"zrtol original name","",name);
  1528.     p = name2;
  1529.     for ( ; *name != '\0' && n < maxnam; name++) {
  1530.     if (*name > ' ') flag = 1;    /* Strip leading blanks and controls */
  1531.     if (flag == 0 && *name < '!')
  1532.       continue;
  1533.     if (isupper(*name))        /* Check for mixed case */
  1534.       acase |= 1;
  1535.     else if (islower(*name))
  1536.       acase |= 2;
  1537.         *p++ = *name;
  1538.     n++;
  1539.     }
  1540.     *p-- = '\0';            /* Terminate */
  1541.     while (*p < '!' && p > name2)    /* Strip trailing blanks & controls */
  1542.       *p-- = '\0';
  1543.  
  1544.     if (*name2 == '\0') {        /* Nothing left? */
  1545.     strcpy(name2,"NONAME");        /* do this... */
  1546.     } else if (acase == 1) {        /* All uppercase? */
  1547.     p = name2;            /* So convert all letters to lower */
  1548.     while (*p) {
  1549.         if (isupper(*p))
  1550.           *p = tolower(*p);
  1551.         p++;
  1552.     }
  1553.     }      
  1554. #ifdef OS2
  1555.     if (!IsFileNameValid(name2))
  1556.       ChangeNameForFAT(name2);
  1557. #endif /* OS2 */
  1558.     debug(F110,"zrtol new name",name2,0);
  1559. }
  1560.  
  1561.  
  1562. /*  Z S T R I P  --  Strip device & directory name from file specification */
  1563.  
  1564. /*  Strip pathname from filename "name", return pointer to result in name2 */
  1565.  
  1566. #ifdef pdp11
  1567. #define ZSTRPLEN 64
  1568. #else
  1569. #define ZSTRPLEN MAXPATH
  1570. #endif /* pdp11 */
  1571. static char work[ZSTRPLEN+1];
  1572.  
  1573. VOID
  1574. zstrip(name,name2) char *name, **name2; {
  1575.     char *cp, *pp;
  1576.     int n = 0;
  1577.     debug(F110,"zstrip before",name,0);
  1578.     if (!name) { *name2 = ""; return; }
  1579.     pp = work;
  1580. #ifdef DTILDE
  1581.     /* Strip leading tilde */
  1582.     if (*name == '~') name++;
  1583.     debug(F110,"zstrip after tilde-stripping",name,0);
  1584. #else
  1585. #ifdef OS2
  1586.     /* Strip disk letter and colon */
  1587.     if (isalpha(*name) && (*(name+1) == ':')) name += 2;
  1588.     debug(F110,"zstrip after disk-stripping",name,0);
  1589. #endif /* OS2 */
  1590. #endif /* DTILDE */
  1591.     for (cp = name; *cp; cp++) {
  1592.         if (ISDIRSEP(*cp)) {
  1593.         pp = work;
  1594.         n = 0;
  1595.     } else {
  1596.         *pp++ = *cp;
  1597.         if (n++ >= ZSTRPLEN)
  1598.           break;
  1599.     }
  1600.     }
  1601.     *pp = '\0';                /* Terminate the string */
  1602.     *name2 = work;
  1603.     debug(F110,"zstrip after",*name2,0);
  1604. }
  1605.  
  1606. /*  Z L T O R  --  Local TO Remote */
  1607.  
  1608. VOID
  1609. zltor(name,name2) char *name, *name2; {
  1610.     char *cp, *pp;
  1611.     int dc = 0;
  1612.     char *dotp = NULL;
  1613. #ifdef aegis
  1614.     char *namechars;
  1615.     int tilde = 0, bslash = 0;
  1616.  
  1617.     if ((namechars = getenv("NAMECHARS")) != NULL) {
  1618.         if (xindex(namechars, '~' ) != NULL) tilde  = '~';
  1619.         if (xindex(namechars, '\\') != NULL) bslash = '\\';
  1620.     } else {
  1621.         tilde = '~';
  1622.         bslash = '\\';
  1623.     }
  1624. #endif /* aegis */
  1625.  
  1626.     debug(F110,"zltor",name,0);
  1627.     pp = work;
  1628. #ifdef OS2
  1629.     if (isalpha(*name) && (*(name+1) == ':')) /* Strip disk name */
  1630.       name += 2;
  1631. #endif /* OS2 */
  1632.     for (cp = name; *cp; cp++) {    /* Strip path name */
  1633.     if (ISDIRSEP(*cp)) {
  1634.         dc = 0;            /* Start over... */
  1635.         dotp = NULL;
  1636.         pp = work;
  1637.     } else if (islower(*cp))    /* Uppercase letters */
  1638.       *pp++ = toupper(*cp);        /* Change tilde to 'X' */
  1639.     else if (*cp == '~')
  1640.       *pp++ = 'X';
  1641.     else if (*cp == '#')        /* Change number sign to 'X' */
  1642.       *pp++ = 'X';
  1643.     else if (*cp == '.') {        /* Change dot to underscore */
  1644.         dotp = pp;            /* Remember where we last did this */
  1645.         *pp++ = '_';
  1646.     } else
  1647.       *pp++ = *cp;
  1648.     }
  1649.     *pp = NUL;                /* Tie it off. */
  1650.     if (dotp) *dotp = '.';        /* Restore last dot (if any) */
  1651.     cp = name2;                /* If nothing before dot, */
  1652.     if (*work == '.') *cp++ = 'X';    /* insert 'X' */
  1653.     strcpy(cp,work);
  1654.     debug(F110," name2",name2,0);
  1655. }
  1656.  
  1657.  
  1658. /*  Z C H D I R  --  Change directory  */
  1659. /*
  1660.   Call with:
  1661.     dirnam = pointer to name of directory to change to,
  1662.       which may be "" or NULL to indicate user's home directory.
  1663.   Returns:
  1664.     0 on failure
  1665.     1 on success
  1666. */
  1667. int
  1668. zchdir(dirnam) char *dirnam; {
  1669.     char *hd, *sp, *p;
  1670.  
  1671.     debug(F110,"zchdir",dirnam,0);
  1672.     if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
  1673.       dirnam = zhome();            /* use user's home directory. */
  1674.     sp = dirnam;
  1675.     debug(F110,"zchdir 2",dirnam,0);
  1676.  
  1677. #ifdef DTILDE
  1678.     hd = tilde_expand(dirnam);        /* Attempt to expand tilde */
  1679.     if (*hd == '\0') hd = dirnam;    /* in directory name. */
  1680. #else
  1681.     hd = dirnam;
  1682. #endif /* DTILDE */
  1683.     debug(F110,"zchdir 3",hd,0);
  1684. #ifdef pdp11
  1685.     /* Just to save some space */
  1686.     return((
  1687. #ifdef NT
  1688.         _chdir(hd)
  1689. #else
  1690.         chdir(hd)
  1691. #endif /* NT */
  1692.         == 0) ? 1 : 0);
  1693. #else
  1694. #ifdef OS2
  1695.     if (isalpha(hd[0]) && hd[1] == ':') {
  1696.         if (zchdsk(hd[0]))
  1697.       return(0);
  1698.     if (hd[2] == 0)
  1699.       return(1);            /* Handle drive-only case */
  1700.     }
  1701.     {
  1702.     /* strip trailing DIRSEP except after d:; chdir() doesn't like it */
  1703.     int len = strlen(hd) ;
  1704.     if ( len > 1 && ISDIRSEP(hd[len - 1]) && hd[len - 2] != ':' )
  1705.       hd[len - 1] = 0; 
  1706.     }
  1707. #endif /* OS2 */
  1708.     if (
  1709. #ifdef NT
  1710.     _chdir(hd)
  1711. #else
  1712.     chdir(hd)
  1713. #endif /* NT */
  1714.     == 0) return(1);        /* Try to cd */
  1715.     else return(0);
  1716.  
  1717. #ifdef COMMENT
  1718. /* This doesn't help in Windows or OS/2, and it's wrong in UNIX */
  1719.     p = sp;                /* Failed, lowercase it. */
  1720.     while (*p) {
  1721.     if (isupper(*p)) *p = tolower(*p);
  1722.     p++;
  1723.     }
  1724.     debug(F110,"zchdir 4",hd,0);
  1725. #ifdef DTILDE
  1726.     hd = tilde_expand(sp);        /* Try again to expand tilde */
  1727.     if (*hd == '\0') hd = sp;
  1728. #else
  1729.     hd = sp;                /* Point to result */
  1730. #endif /* DTILDE */
  1731.     debug(F110,"zchdir 5",hd,0);
  1732.     return((
  1733. #ifdef NT
  1734.         _chdir(hd)
  1735. #else
  1736.         chdir(hd)
  1737. #endif /* NT */
  1738.         == 0) ? 1 : 0);
  1739. #endif /* COMMENT */
  1740.  
  1741. #endif /* pdp11 */
  1742. }
  1743.  
  1744. /*  Z H O M E  --  Return pointer to user's home directory  */
  1745.  
  1746. char *
  1747. zhome() {
  1748. #ifdef Plan9
  1749.     char *home = getenv("home");
  1750. #else
  1751.     char *home = getenv("HOME");
  1752. #endif /* Plan9 */
  1753. #ifdef OS2
  1754.     extern char startupdir[];
  1755.     return(home ? home : startupdir);
  1756. #else
  1757.     return(home ? home : ".");
  1758. #endif /* OS2 */
  1759. }
  1760.  
  1761. /*  Z G T D I R  --  Return pointer to user's current directory  */
  1762.  
  1763. #ifdef pdp11
  1764. #define CWDBL 80            /* Save every byte we can... */
  1765. #else
  1766. #define CWDBL MAXPATH
  1767. #endif /* pdp11 */
  1768. static char cwdbuf[CWDBL+1];
  1769.  
  1770. char *
  1771. zgtdir() {
  1772.     char *buf;
  1773.  
  1774. #ifdef BSD44
  1775.     extern char *getcwd();
  1776.     buf = cwdbuf;
  1777.     debug(F101,"zgtdir CWDBL","",CWDBL);
  1778.     return(getcwd(buf,CWDBL));
  1779. #else
  1780. #ifdef SVORPOSIX
  1781.     extern char *getcwd();
  1782.     buf = cwdbuf;
  1783.     debug(F101,"zgtdir CWDBL","",CWDBL);
  1784.     return(getcwd(buf,CWDBL));
  1785. #else
  1786. #ifdef COHERENT
  1787. #ifdef _I386
  1788.     extern char *getcwd();
  1789.     buf = cwdbuf;
  1790.     debug(F101,"zgtdir CWDBL","",CWDBL);
  1791.     return(getcwd(buf,CWDBL));
  1792. #else
  1793.     extern char *getwd();
  1794.     buf = cwdbuf;
  1795.     debug(F101,"zgtdir CWDBL","",CWDBL);
  1796.     return(getwd(buf));
  1797. #endif /* _I386 */
  1798. #else
  1799. #ifdef OS2
  1800. #ifndef __IBMC__ /* which has a macro for this */
  1801.     extern char *getcwd();
  1802. #endif /* __IBMC__ */
  1803.     buf = cwdbuf;
  1804.     debug(F101,"zgtdir CWDBL","",CWDBL);
  1805. #ifdef NT
  1806.     _getcwd(buf,CWDBL);
  1807. #else
  1808.     getcwd(buf,CWDBL);
  1809. #endif /* NT */
  1810.     return(buf);
  1811. #else  /* OS2 */
  1812. #ifdef BSD4
  1813.     extern char *getwd();
  1814.     buf = cwdbuf;
  1815.     debug(F100,"zgtdir getwd()","",0);
  1816.     return(getwd(buf));
  1817. #else
  1818.     return("directory unknown");
  1819. #endif /* BSD4 */
  1820. #endif /* OS2 */
  1821. #endif /* COHERENT */
  1822. #endif /* SYSVORPOSIX */
  1823. #endif /* BSD44 */
  1824. }
  1825.  
  1826. /*  Z X C M D -- Run a system command so its output can be read like a file */
  1827.  
  1828. #ifdef NT
  1829. _PROTOTYP( FILE * win95popen, (char *cmd, char *mode) );
  1830. _PROTOTYP( int win95pclose, (FILE *pipe) );
  1831. #endif /* NT */
  1832.  
  1833. int
  1834. zxcmd(filnum,comand) int filnum; char *comand; {
  1835. #ifdef OS2
  1836.     if (chkfn(filnum) < 0) return(-1);    /* Need a valid Kermit file number. */
  1837.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  1838.       return(0);
  1839.     if (filnum == ZIFILE || filnum == ZRFILE) { /* Input from a command */
  1840.     if (priv_chk() || 
  1841. #ifdef NT
  1842.          isWin95() ? 
  1843.          ((fp[filnum] = win95popen(comand,"rb")) == NULL) :
  1844. #endif /* NT */
  1845.          ((fp[filnum] = popen(comand,"rb")) == NULL)
  1846.          )
  1847.       return(0);
  1848.     } else { /* Output to a command */
  1849.     if (priv_chk() || 
  1850. #ifdef NT
  1851.         isWin95() ? 
  1852.         ((fp[filnum] = win95popen(comand,"w")) == NULL) :
  1853. #endif /* NT */
  1854.         ((fp[filnum] = popen(comand,"w")) == NULL)
  1855.         )
  1856.       return(0);
  1857.     }
  1858.     fp[ZSYSFN] = fp[filnum];        /* remember the pipe handle */
  1859.     ispipe[filnum] = 1;
  1860.     return(1);
  1861. #else /* Not OS2 */
  1862.     int pipes[2];
  1863.     int out;
  1864.  
  1865.     if (chkfn(filnum) < 0) return(-1);    /* Need a valid Kermit file number. */
  1866.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  1867.       return(0);
  1868.  
  1869.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  1870.  
  1871. /* Output to a command */
  1872.  
  1873.     if (out) {                /* Need popen() to do this. */
  1874. #ifdef NOPOPEN
  1875.     return(0);            /* no popen(), fail. */
  1876. #else
  1877. /* Use popen() to run the command. */
  1878.  
  1879. #ifdef _POSIX_SOURCE
  1880. /* Strictly speaking, popen() is not available in POSIX.1 */
  1881. #define DCLPOPEN
  1882. #endif /* _POSIX_SOURCE */
  1883.  
  1884. #ifdef COHERENT
  1885. #define DCLPOPEN
  1886.     FILE * fdopen();
  1887. #endif /* COHERENT */
  1888.  
  1889. #ifdef DCLPOPEN
  1890.     /* popen() needs declaring because it's not declared in <stdio.h> */
  1891.     FILE *popen();
  1892. #endif /* DCLPOPEN */
  1893.  
  1894.     if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
  1895.       return(0);
  1896.     else return(1);
  1897. #endif /* NOPOPEN */
  1898.     }
  1899.  
  1900. /* Input from a command */
  1901.  
  1902.     if (pipe(pipes) != 0) {
  1903.     debug(F100,"zxcmd pipe failure","",0);
  1904.     return(0);            /* can't make pipe, fail */
  1905.     }
  1906.  
  1907. /* Create a fork in which to run the named process */
  1908.  
  1909.     if ((
  1910. #ifdef aegis
  1911.      pid = vfork()            /* child */
  1912. #else
  1913.      pid = fork()            /* child */
  1914. #endif /* aegis */
  1915.      ) == 0) {
  1916.  
  1917. /* We're in the fork. */
  1918.  
  1919.     char *shpath, *shname, *shptr;    /* Find user's preferred shell */
  1920. #ifndef aegis
  1921.     struct passwd *p;
  1922.     char *defshell;
  1923. #ifdef HPUX10                /* Default shell */
  1924.     defshell = "/usr/bin/sh";
  1925. #else
  1926. #ifdef Plan9
  1927.     defshell = "/bin/rc";
  1928. #else
  1929.     defshell = "/bin/sh";
  1930. #endif /* Plan9 */
  1931. #endif /* HPUX10 */
  1932. #endif /* aegis */
  1933.     if (priv_can()) exit(1);    /* Turn off any privileges! */
  1934.     debug(F101,"zxcmd pid","",pid);
  1935.     close(pipes[0]);        /* close input side of pipe */
  1936.     close(0);            /* close stdin */
  1937.     if (open("/dev/null",0) < 0) return(0); /* replace input by null */
  1938. #ifndef OXOS
  1939. #ifndef SVORPOSIX
  1940.     dup2(pipes[1],1);        /* BSD: replace stdout & stderr */
  1941.     dup2(pipes[1],2);        /* by the pipe */
  1942. #else
  1943.     close(1);            /* AT&T: close stdout */
  1944.     if ( dup(pipes[1]) != 1 )    /* Send stdout to the pipe */
  1945.       return(0);
  1946.     close(2);            /* Send stderr to the pipe */
  1947.     if ( dup(pipes[1]) != 2 )
  1948.       return(0);
  1949. #endif /* SVORPOSIX */
  1950. #else /* OXOS */
  1951.     dup2(pipes[1],1);
  1952.     dup2(pipes[1],2);
  1953. #endif /* OXOS */
  1954.     close(pipes[1]);        /* Don't need this any more. */
  1955.  
  1956. #ifdef aegis
  1957.     if ((shpath = getenv("SERVERSHELL")) == NULL)
  1958.       shpath = "/bin/sh";
  1959. #else
  1960.     shpath = getenv("SHELL");    /* What shell? */
  1961.     if (shpath == NULL) {
  1962.         p = getpwuid( real_uid() );    /* Get login data */
  1963.         if (p == (struct passwd *)NULL || !*(p->pw_shell))
  1964.           shpath = defshell;
  1965.         else shpath = p->pw_shell;
  1966.         }
  1967. #endif /* aegis */
  1968.     shptr = shname = shpath;
  1969.     while (*shptr != '\0')
  1970.       if (*shptr++ == '/')
  1971.         shname = shptr;
  1972.     debug(F100,"zxcmd...","",0);
  1973.     debug(F110,shpath,shname,0);
  1974.  
  1975.     execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
  1976.     exit(0);            /* just punt if it failed. */
  1977.     } else if (pid == (PID_T) -1) {
  1978.     debug(F100,"zxcmd fork failure","",0);
  1979.     return(0);
  1980.     }
  1981.     debug(F101,"zxcmd pid","",pid);
  1982.     if (out) {
  1983.     close(pipes[0]);        /* Don't need the input side */
  1984.     fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
  1985.     fp[ZSYSFN] = fp[filnum];    /* Remember. */
  1986.     zoutcnt = 0;            /* (PWP) reset input buffer */
  1987.     zoutptr = zoutbuffer;
  1988.     } else {
  1989.     close(pipes[1]);        /* Don't need the output side */
  1990.     fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
  1991.     fp[ZSYSFN] = fp[filnum];    /* Remember. */
  1992.     zincnt = 0;            /* (PWP) reset input buffer */
  1993.     zinptr = zinbuffer;
  1994.     }
  1995.     return(1);
  1996. #endif /* OS2 */
  1997. } /* zxcmd */
  1998.  
  1999. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  2000.  
  2001. int
  2002. zclosf(filnum) int filnum; {
  2003.     int wstat;
  2004.     debug(F101,"zclosf filnum","",filnum);
  2005. #ifndef NOPOPEN
  2006. #ifdef OS2
  2007.     if (ispipe[filnum]) {
  2008.     int x;
  2009. #ifdef NT
  2010.        x = isWin95() ? win95pclose(fp[filnum]) : pclose(fp[filnum]) ;
  2011. #else /* NT */
  2012.        x = pclose(fp[filnum]);
  2013. #endif /* NT */
  2014.     fp[filnum] = NULL;
  2015.     ispipe[filnum] = 0;
  2016. #else
  2017.     if (filnum == ZWFILE) {
  2018.     int x;
  2019.     x = pclose(fp[filnum]);
  2020.     fp[filnum] = fp[ZSYSFN] = NULL;
  2021. #endif /* OS2 */
  2022.     return((x < 0) ? 0 : 1);
  2023.     }
  2024. #endif /* NOPOPEN */
  2025.     debug(F101,"zclosf fp[filnum]","", fp[filnum]);
  2026.     debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
  2027. #ifdef OS2
  2028.     fclose(fp[filnum]);
  2029.     fp[filnum] = NULL;
  2030. #else
  2031.     if (pid != (PID_T) 0) {
  2032.     debug(F101,"zclosf killing pid","",pid);
  2033. #ifdef Plan9
  2034.     kill(pid, SIGKILL);
  2035. #else
  2036.     kill(pid,9);
  2037. #endif /* Plan9 */
  2038.         while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
  2039.         pid = 0;
  2040.     }
  2041.     fclose(fp[filnum]);
  2042.     fp[filnum] = fp[ZSYSFN] = NULL;
  2043. #endif /* OS2 */
  2044.     return(1);
  2045. }
  2046.  
  2047. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  2048. /*
  2049.   Returns the number of files that match fn1, with data structures set up
  2050.   so that first file (if any) will be returned by the next znext() call.
  2051.   Depends on external variable wildxpand: 0 means we expand wildcards
  2052.   internally, nonzero means we call the shell to do it.
  2053. */
  2054.  
  2055. #ifdef OS2
  2056. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  2057. /*
  2058.   Returns the number of files that match fn1, with data structures set up
  2059.   so that first file (if any) will be returned by the next znext() call.
  2060.   Depends on external variable wildxpand: 0 means we expand wildcards
  2061.   internally, nonzero means we call the shell to do it.
  2062. */
  2063.  
  2064. char findpath[MAXPATH];
  2065. #ifdef NT
  2066. WIN32_FIND_DATA finddata;
  2067. HANDLE findhandle = INVALID_HANDLE_VALUE;
  2068. #else /* NT */
  2069. FILEFINDBUF3    finddata;
  2070. HDIR            findhandle = HDIR_CREATE;
  2071. ULONG           findcount;
  2072. #endif /* NT */
  2073.  
  2074. int
  2075. zxpand(fn) char *fn; {
  2076.     int i, lasterror = 0;
  2077.     char localfn[MAXPATH];
  2078.  
  2079.     if ( !fn || !(*fn) )
  2080.         return(0);
  2081.  
  2082.     debug(F110,"zxpand fn",fn,0);
  2083. #ifdef NT
  2084.     if (findhandle != INVALID_HANDLE_VALUE) {
  2085.     FindClose(findhandle);
  2086.     findhandle = INVALID_HANDLE_VALUE;
  2087.     }
  2088. #else
  2089.     if (findhandle != HDIR_CREATE) {
  2090.     DosFindClose(findhandle);
  2091.     findhandle = HDIR_CREATE;
  2092.     }
  2093. #endif /* NT */
  2094.  
  2095.     fcount = 0;
  2096.     strcpy(findpath, fn);
  2097.     strcpy(localfn, fn);
  2098.     for (i = strlen(findpath); i >= 0; i--) {
  2099.         if (ISDIRSEP(findpath[i]) 
  2100.             || findpath[i] == ':'
  2101.             ) {
  2102.             if (!findpath[i+1])
  2103.               strcat(localfn, "*");
  2104.             else
  2105.               findpath[i+1] = '\0';
  2106.             break;
  2107.         }
  2108.         if (findpath[i] == ':') {
  2109.             if (!findpath[i+1]) {
  2110.                 strcat(localfn, "*");
  2111.                 break;
  2112.             }
  2113.         }
  2114.     }
  2115.     if (i < 0)
  2116.       if (zchki(localfn) == -2) {
  2117.           if ( strlen(localfn) == 2 && localfn[1] == ':' ) {
  2118.               strcat(localfn, "./*");
  2119.           } else {
  2120.               strcat(findpath, "/");
  2121.               strcat(localfn, "/*");
  2122.           }
  2123.       } else if (!ISDIRSEP(localfn[0]) && localfn[1] != ':') {
  2124.           findpath[0] = '\0';
  2125.           strcpy(nambuf, "./");
  2126.           strcat(nambuf, localfn);
  2127.           strcpy(localfn, nambuf);
  2128.       }
  2129.  
  2130.     debug(F100,"zxpand about to FindFirst","",0);
  2131. #ifdef NT
  2132.     findhandle = FindFirstFile( localfn, &finddata );
  2133.     if ( findhandle == INVALID_HANDLE_VALUE ) 
  2134. #else /* NT */
  2135.     findcount = 1;
  2136.     DosFindFirst(localfn,
  2137.          &findhandle, 
  2138.          (ULONG) FILE_NORMAL | FILE_ARCHIVED | FILE_DIRECTORY | 
  2139.            FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY,
  2140.          (PVOID) &finddata, (ULONG) sizeof(finddata),
  2141.          &findcount,
  2142.          FIL_STANDARD
  2143.          );
  2144.     if (findcount != 1)
  2145. #endif /* NT */
  2146.       return(fcount);
  2147.  
  2148.     fcount = 1;
  2149.     while ( 
  2150. #ifdef NT
  2151.        FindNextFile( findhandle, &finddata )
  2152. #else /* NT */
  2153.        !(lasterror = DosFindNext(findhandle,
  2154.                      (PVOID) &finddata, 
  2155.                      (ULONG) sizeof(finddata),
  2156.                      &findcount)) &&
  2157.        findcount == 1
  2158. #endif /* NT */
  2159.        )
  2160.       fcount++;
  2161.  
  2162. #ifdef NT
  2163.     lasterror = GetLastError();
  2164.     FindClose( findhandle );
  2165.     findhandle = INVALID_HANDLE_VALUE;
  2166. #else
  2167.     DosFindClose( findhandle );
  2168.     findhandle = HDIR_CREATE;
  2169. #endif /* NT */
  2170.  
  2171.     if (lasterror != ERROR_NO_MORE_FILES) {
  2172.         fcount = 0;
  2173.         return (fcount);
  2174.     }
  2175.  
  2176.     debug(F111,"zxpand","fcount",fcount);
  2177.  
  2178. #ifdef NT
  2179.     findhandle = FindFirstFile( localfn, &finddata );
  2180. #else /* NT */
  2181.     findcount = 1;
  2182.     DosFindFirst(localfn,
  2183.          &findhandle, 
  2184.          (ULONG) FILE_NORMAL | FILE_ARCHIVED | FILE_DIRECTORY | 
  2185.            FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY,
  2186.          (PVOID) &finddata,
  2187.          (ULONG) sizeof(finddata),
  2188.          &findcount,
  2189.          FIL_STANDARD
  2190.          );
  2191. #endif /* NT */
  2192.     return(fcount);
  2193. }
  2194.  
  2195. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  2196. /*
  2197.    Returns > 0 if there's another file, with its name copied into the argument
  2198.    string, or 0 if no more files in list.
  2199. */
  2200. int
  2201. znext(fn) char *fn; {
  2202.     int lasterror = 0;
  2203.  
  2204.     if (fcount-- > 0 
  2205. #ifdef NT
  2206.          && findhandle != INVALID_HANDLE_VALUE
  2207. #else
  2208.      && findhandle != HDIR_CREATE
  2209. #endif /* NT */
  2210.     ) {
  2211.         strcpy(fn,findpath);
  2212. #ifdef NT
  2213.         strcat(fn,finddata.cFileName);
  2214.         if (!FindNextFile( findhandle, &finddata)) {
  2215.             FindClose( findhandle );
  2216.             findhandle = INVALID_HANDLE_VALUE;
  2217.             fcount = 0;
  2218.         }
  2219. #else /* NT */
  2220.         strcat(fn,finddata.achName );
  2221.         findcount = 1;
  2222.         lasterror = DosFindNext(findhandle,
  2223.                 (PVOID) &finddata, 
  2224.                 (ULONG) sizeof(finddata),
  2225.                 &findcount
  2226.                 );
  2227.         if (lasterror || findcount != 1) {
  2228.         DosFindClose(findhandle);
  2229.         findhandle = HDIR_CREATE;
  2230.         fcount = 0;
  2231.     }
  2232. #endif /* NT */
  2233.     } else {
  2234.         *fn = '\0';
  2235.         fcount = -1;
  2236.     }
  2237.     debug(F111,"znext",fn,fcount+1);
  2238.     return(fcount+1);
  2239. }
  2240.  
  2241. #else /* Not OS2 */
  2242.  
  2243. int
  2244. zxpand(fn) char *fn; {
  2245.     char *p;
  2246. #ifdef DTILDE                /* Built with tilde-expansion? */
  2247.     char *tnam;
  2248. #endif /* DTILDE */
  2249.     debug(F111,"zxpand entry",fn,wildxpand);
  2250.     if ( !fn || !(*fn) )               /* If no argument provided */
  2251.       return(0);                       /* Return zero files found */
  2252.  
  2253. #ifdef DTILDE                /* Built with tilde-expansion? */
  2254.     if (*fn == '~') {            /* Starts with tilde? */
  2255.     tnam = tilde_expand(fn);    /* Try to expand it. */
  2256.     if (tnam) fn = tnam;
  2257.     }
  2258.     debug(F110,"zxpand after tilde_x",fn,0);
  2259. #endif /* DTILDE */
  2260. #ifndef NOPUSH
  2261.     if (!nopush && wildxpand)        /* Who is expanding wildcards? */
  2262.       fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */
  2263.     else
  2264. #endif /* NOPUSH */
  2265.       fcount = (mtchs == NULL &&    /* Kermit */
  2266.         (mtchs = (char **)malloc(MAXWLD * sizeof(*mtchs))) == NULL)
  2267.     ? 0
  2268.       : fgen(fn,mtchs,MAXWLD);    /* Look up the file. */
  2269.  
  2270.     if (fcount > 0) {
  2271.     mtchptr = mtchs;        /* Save pointer for next. */
  2272.     debug(F111,"zxpand ok",mtchs[0],fcount);
  2273.     return(fcount);
  2274.     }
  2275.     debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */
  2276.     p = malloc((int)strlen(fn) + 10);    /* Make space */
  2277.     if (!p) return(0);
  2278.     zrtol(fn,p);            /* Try again, maybe lowercase */
  2279.  
  2280. #ifndef NOPUSH
  2281.     if (!nopush && wildxpand)
  2282.       fcount = shxpand(p,mtchs,MAXWLD); /* Shell */
  2283.     else
  2284. #endif /* NOPUSH */
  2285.       fcount = fgen(p,mtchs,MAXWLD);    /* Kermit */
  2286.     if (fcount > 0) {            /* Got at least one? */
  2287.     mtchptr = mtchs;        /* Save pointer for next. */
  2288.     debug(F111,"zxpand fgen2 ok",mtchs[0],fcount);
  2289.     } else debug(F111,"zxpand 2 not ok",p,fcount);
  2290.     free(p);
  2291.     return(fcount);
  2292. }
  2293.  
  2294.  
  2295. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  2296. /*
  2297.   Returns >0 if there's another file, with its name copied into the arg string,
  2298.   or 0 if no more files in list.
  2299. */
  2300. int
  2301. znext(fn) char *fn; {
  2302.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  2303.     else *fn = '\0';
  2304.     debug(F111,"znext",fn,fcount+1);
  2305.     return(fcount+1);
  2306. }
  2307. #endif /* OS2 */
  2308.  
  2309. /*  Z C H K S P A  --  Check if there is enough space to store the file  */
  2310.  
  2311. /*
  2312.  Call with file specification f, size n in bytes.
  2313.  Returns -1 on error, 0 if not enough space, 1 if enough space.
  2314. */
  2315. int
  2316. #ifdef CK_ANSIC
  2317. zchkspa(char *f, long n)
  2318. #else
  2319. zchkspa(f,n) char *f; long n;
  2320. #endif /* CK_ANSIC */
  2321. /* zchkspa() */ {
  2322. #ifdef OS2
  2323. /* OS/2 gives us an easy way to do this. */
  2324.     unsigned long x, filesize = 0L;
  2325.     debug(F111,"zchkspa",f,n);
  2326.     if (isalpha(f[0]) && f[1] == ':') {
  2327.     x = zdskspace(toupper(f[0]) - 'A' + 1);
  2328.     debug(F101,"zchkspa disk: size","",x);
  2329.     } else {
  2330.     x = zdskspace(0);
  2331.     debug(F101,"zchkspa no disk size","",x);
  2332.     }
  2333.     if (fncact == XYFX_U || fncact == XYFX_X) /* Update or Replace */
  2334.       filesize = zchki(f); 
  2335.  
  2336.    return((x+filesize >= n) ? 1 : 0);
  2337. #else
  2338. /* In UNIX there is no good (and portable) way. */
  2339.     return(1);                /* Always say OK. */
  2340. #endif /* OS2 */
  2341. }
  2342.  
  2343.  
  2344. /*  Z N E W N  --  Make a new name for the given file  */
  2345.  
  2346. /*
  2347.   Given the name, fn, of a file that already exists, this function builds a
  2348.   new name of the form "<oldname>.~<n>~", where <oldname> is argument name
  2349.   (fn), and <n> is a version number, one higher than any existing version
  2350.   number for that file, up to 9999.  This format is consistent with that used
  2351.   by GNU EMACS.  If the constructed name is too long for the system's maximum,
  2352.   enough characters are truncated from the end of <fn> to allow the version
  2353.   number to fit.  If no free version numbers exist between 1 and 9999, a
  2354.   version number of "xxxx" is used.  Returns a pointer to the new name in
  2355.   argument s.
  2356. */
  2357.  
  2358. VOID
  2359. znewn(fn,s) char *fn, **s; {
  2360. #ifdef pdp11
  2361. #define ZNEWNBL 63            /* Name buffer length */
  2362. #define ZNEWNMD 3            /* Max digits for version number */
  2363. #else
  2364. #define ZNEWNBL 255
  2365. #define ZNEWNMD 4
  2366. #endif /* pdp11 */
  2367.  
  2368.     static char buf[ZNEWNBL+1];
  2369.     char *bp, *xp, *yp;
  2370. #ifdef OS2
  2371.     static char localfn[MAXPATH+1];
  2372.     char *tp=NULL, *zp=NULL, ch, temp[14];
  2373. #endif /* OS2 */
  2374.     int len = 0, d = 0, n, t, i, j, k, power = 1;
  2375.  
  2376.     int max = MAXNAMLEN;        /* Maximum name length */
  2377.  
  2378.     if (max < 14) max = 14;        /* Make it reasonable */
  2379.     if (max > ZNEWNBL) max = ZNEWNBL;
  2380.     bp = buf;                /* Buffer for building new name */
  2381.     yp = fn;
  2382.     while (*yp) {            /* Copy old name into buffer */
  2383.     *bp++ = *yp++;
  2384.     if (len++ > ZNEWNBL) break;    /* ...up to buffer length */
  2385.     }
  2386.     *s = NULL;
  2387.     for (i = 1; i < ZNEWNMD + 1; i++) {    /* Version numbers up to 10**i - 1 */
  2388.     power *= 10;            /* Next power of 10 */
  2389.     j = max - len;            /* Space left for version number */
  2390.     k = 3 + i;            /* Space needed for it */
  2391.     if (j < k) {            /* Make room if necessary */
  2392.         len -= (k - j);        /* Adjust length of filename */
  2393.         bp = buf + len;        /* Point to new end */
  2394.     }
  2395.     *bp++ = '*';            /* Put a star on the end (UNIX) */
  2396.     *bp-- = '\0';            /* Terminate with null */
  2397.  
  2398.     debug(F110,"znewn: about to expand",buf,0);
  2399.     n = zxpand(buf);        /* Expand the resulting wild name */
  2400.                     /* n is the number of matches */
  2401.     debug(F101,"znewn matches","",n);
  2402.     while (n-- > 0) {        /* Find any existing name.~n~ files */
  2403. #ifdef OS2
  2404.         znext(localfn);
  2405.         xp = localfn;
  2406. #else /* OS2 */
  2407.         xp = *mtchptr++;        /* Point at matching name */
  2408. #endif /* OS2 */
  2409.         xp += len;            /* Look for .~<n>~ at the end of it */
  2410.         if (*xp == '.' && *(xp+1) == '~') {    /* Has a version number */
  2411.         t = atoi(xp+2);                /* Get it */
  2412.         if (t > d) d = t;    /* Save d = highest version number */
  2413.         }
  2414.     }
  2415.     if (d < power-1) {        /* Less than maximum possible? */
  2416.         debug(F110,"znewn number ok",buf,0);
  2417.         sprintf(bp,".~%d~",d+1);    /* Yes, make "name.~<d+1>~" */
  2418.         *s = buf;            /* Point to new name */
  2419.         ck_znewn = d+1;        /* Also make it available globally */
  2420.         break;            /* Done, return it */
  2421.     }
  2422.     }
  2423.     if (*s == NULL) {
  2424.     debug(F110,"znewn: too many names",buf,0);
  2425.     sprintf(bp,".~xxxx~");        /* Too many, use xxxx. */
  2426.     ck_znewn = -1;            /* Also make it available globally */
  2427.     *s = buf;
  2428.     }
  2429. #ifdef OS2
  2430.     if (IsFileNameValid(buf)) {
  2431.         debug(F110,"znewn: os2 filename valid",buf,0);
  2432.         return; /* HPFS */
  2433.     }
  2434.     /* otherwise make FAT 8.3 name */
  2435.     debug(F110,"znewn: os2 filename invalid",buf,0);
  2436.     xp = bp = buf;
  2437.     yp = fn;
  2438.     while (*yp) {            /* Copy name into buf */
  2439.     ch = *bp++ = *yp++;
  2440.     if (ISDIRSEP(ch) || (ch == ':')) xp=bp;
  2441.     }
  2442.     *bp = '\0';
  2443.     yp = xp;
  2444.     i = 1;
  2445.     while (*yp && (*yp != '.')) {
  2446.     yp++;
  2447.     if (++i<=6) 
  2448.            zp=yp;
  2449.     }
  2450.     /* zp points to 6th character in name, or yp, whichever occurs first. */
  2451.     strcpy(temp,yp);            /* Copy extension, if any */
  2452.     while (zp != xp+8) {
  2453.         if ( zp < xp+5 ) *zp++='0';
  2454.         else *zp++='?';            /* Pad out with wild cards */
  2455.     }
  2456.     strcpy(zp,temp);            /* Get the extension back */
  2457.     debug(F110,"znewn: about to expand",buf,0);
  2458.     n = zxpand(buf);            /* Expand the resulting wild name */
  2459.     debug(F101,"znewn: matches","",n);
  2460.     d = 0;                /* Index number */
  2461.     debug(F110,"znewn: temp",temp,0);
  2462.     while (znext(temp)) {
  2463. #ifdef COMMENT
  2464.         i = atoi(temp+5);
  2465.         if (i > d) d = i;
  2466. #else
  2467.     if ( tp = strrchr( temp, '/' ) ) 
  2468.       tp++;
  2469.     else
  2470.       tp = temp;   
  2471.         i = atoi(tp+5);
  2472.     debug(F111,"znewn: tp=atoi(tp+5)",tp,i);
  2473.         if (i > d) d = i;
  2474.     debug(F101,"znewn: d","",d);
  2475. #endif /* COMMENT */
  2476.     }
  2477.     sprintf(temp,"%03d",d+1);        /* Get the number into a string */
  2478.     ck_znewn = d+1;
  2479.     memcpy(xp+5, temp, 3);
  2480.     debug(F110,"znewn: os2 file name is FAT",buf,0);
  2481. #endif /* OS2 */
  2482.     return;
  2483. }
  2484.  
  2485. /*  Z R E N A M E  --  Rename a file  */
  2486. /*
  2487.    Call with old and new names.
  2488.    If new name is the name of a directory, the 'old' file is moved to
  2489.    that directory.
  2490.    Returns 0 on success, -1 on failure.
  2491. */
  2492. int
  2493. zrename(old,new) char *old, *new; {
  2494.     char *p = NULL, *s = new;
  2495.     int x;
  2496.  
  2497.     debug(F110,"zrename old",old,0);
  2498.     debug(F110,"zrename new",s,0);
  2499.     if (isdir(new)) {
  2500.     char *q = NULL;
  2501.     x = strlen(new);
  2502.     if (!(p = malloc(strlen(new) + strlen(old) + 2)))
  2503.       return(-1);
  2504.     strcpy(p,new);            /* Directory part */
  2505.     if (!ISDIRSEP(*(new+x-1)))    /* Separator, if needed */
  2506.       strcat(p,"/");
  2507.     zstrip(old,&q);            /* Strip path part from old name */
  2508.     strcat(p,q);            /* Concatenate to new directory */
  2509.     s = p;
  2510.     debug(F110,"zrename dir",s,0);
  2511.     } else debug(F110,"zrename no dir",s,0);
  2512. #ifdef RENAME
  2513. /*
  2514.   Atomic, preferred, uses a single system call, rename(), if available.
  2515.   OS/2 rename() returns nonzero, but not necessarily -1 (?), on failure.
  2516. */
  2517.     x = rename(old,s);
  2518.     if (p) free(p);
  2519.     return(x ? -1 : 0);
  2520. #else /* !RENAME */
  2521. /*
  2522.   This way has a window of vulnerability.
  2523. */
  2524.     x = -1;                /* Return code. */
  2525.     if (link(old,s) < 0) {        /* Make a link with the new name. */
  2526.     debug(F111,"zrename link fails, errno",old,errno);
  2527.     } else if (
  2528. #ifdef NT
  2529.            _unlink(old)
  2530. #else
  2531.            unlink(old)
  2532. #endif /* NT */
  2533.            < 0) {    /* Unlink the old name. */
  2534.     debug(F111,"zrename unlink fails, errno",old,errno);
  2535.     } else x = 0;
  2536.     if (p) free(p);
  2537.     return(x);
  2538. #endif /* RENAME */
  2539. }
  2540.  
  2541. /*  Z C O P Y  --  Copy a file  */
  2542. /*
  2543.    Call with source and destination names.
  2544.    If destination name is the name of a directory, the source file is
  2545.    copied to that directory with the original name.
  2546.    Returns 0 on success, -1 on failure.
  2547. */
  2548. int
  2549. zcopy(source,destination) char *source, *destination; {
  2550.     char *p = NULL, *s = destination;
  2551.     int x;
  2552.     
  2553.     debug(F110,"zcopy source",source,0);
  2554.     debug(F110,"zcopy destination",s,0);
  2555.     if (isdir(destination)) {
  2556.     char *q = NULL;
  2557.     x = strlen(destination);
  2558.     if (!(p = malloc(strlen(destination) + strlen(source) + 2)))
  2559.       return(-1);
  2560.     strcpy(p,destination);        /* Directory part */
  2561.     if (!ISDIRSEP(*(destination+x-1))) /* Separator, if needed */
  2562.       strcat(p,"/");
  2563.     zstrip(source,&q);        /* Strip path part from old name */
  2564.     strcat(p,q);            /* Concatenate to new directory */
  2565.     s = p;
  2566.     debug(F110,"zcopy dir",s,0);
  2567.     } else debug(F110,"zcopy no dir",s,0);
  2568. #ifdef OS2
  2569. #ifndef NT
  2570.     x = (DosCopy( source, destination, DCPY_FAILEAS ) ? -1 : 0);
  2571. #else /* NT */
  2572.     x = (CopyFile( source, destination, FALSE ) ? 0 : -1 );
  2573. #endif /* NT */
  2574. #else 
  2575.     /* not yet implemented */
  2576.     x = -1;  
  2577. #endif 
  2578.     return x;
  2579. }
  2580.  
  2581. /*  Z S A T T R */
  2582. /*
  2583.  Fills in a Kermit file attribute structure for the file which is to be sent.
  2584.  Returns 0 on success with the structure filled in, or -1 on failure.
  2585.  If any string member is null, then it should be ignored.
  2586.  If any numeric member is -1, then it should be ignored.
  2587. */
  2588. int
  2589. zsattr(xx) struct zattr *xx; {
  2590.     long k;
  2591.  
  2592.     k = iflen % 1024L;            /* File length in K */
  2593.     if (k != 0L) k = 1L;
  2594.     xx->lengthk = (iflen / 1024L) + k;
  2595.     xx->type.len = 0;            /* File type can't be filled in here */
  2596.     xx->type.val = "";
  2597.     if (*nambuf) {
  2598.     xx->date.val = zfcdat(nambuf);    /* File creation date */
  2599.     xx->date.len = (int)strlen(xx->date.val);
  2600.     } else {
  2601.     xx->date.len = 0;
  2602.     xx->date.val = "";
  2603.     }
  2604.     xx->creator.len = 0;        /* File creator */
  2605.     xx->creator.val = "";
  2606.     xx->account.len = 0;        /* File account */
  2607.     xx->account.val = "";
  2608.     xx->area.len = 0;            /* File area */
  2609.     xx->area.val = "";
  2610.     xx->password.len = 0;        /* Area password */
  2611.     xx->password.val = "";
  2612.     xx->blksize = -1L;            /* File blocksize */
  2613.     xx->xaccess.len = 0;        /* File access */
  2614.     xx->xaccess.val = "";
  2615.     xx->encoding.len = 0;        /* Transfer syntax */
  2616.     xx->encoding.val = 0;
  2617.     xx->disp.len = 0;            /* Disposition upon arrival */
  2618.     xx->disp.val = "";
  2619.     xx->lprotect.len = 0;        /* Local protection */
  2620.     xx->lprotect.val = "";
  2621.     xx->gprotect.len = 0;        /* Generic protection */
  2622.     xx->gprotect.val = "";
  2623.     xx->systemid.len = 2;        /* System ID */
  2624. #ifdef OS2
  2625.     xx->systemid.val = "UO";        /* UO = OS/2 */
  2626. #else
  2627.     xx->systemid.val = "U1";        /* U1 = UNIX */
  2628. #endif /* OS2 */
  2629.     xx->recfm.len = 0;            /* Record format */
  2630.     xx->recfm.val = "";
  2631.     xx->sysparam.len = 0;        /* System-dependent parameters */
  2632.     xx->sysparam.val = "";
  2633.     xx->length = iflen;            /* Length */
  2634.     return(0);
  2635. }
  2636.  
  2637. /* Z F C D A T  --  Get file creation date */
  2638. /*
  2639.   Call with pointer to filename.
  2640.   On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
  2641.   On failure, returns pointer to null string.
  2642. */
  2643. static char datbuf[40];
  2644.  
  2645. char * 
  2646. zdtstr(time) time_t time; {
  2647.     struct tm * time_stamp;
  2648.     struct tm * localtime();
  2649.     int yy, ss;
  2650.  
  2651.     debug(F101,"zdatstr time","",time);
  2652.     if (time < 0)
  2653.       return("");
  2654.     time_stamp = localtime(&(time));
  2655.     if (!time_stamp) {
  2656.     debug(F100,"localtime returns null","",0);
  2657.     return("");
  2658.     }
  2659.     yy = time_stamp->tm_year;        /* Year - 1900 */
  2660.     yy += 1900;
  2661.     debug(F101,"zdatstr year","",yy);
  2662.     if (yy < 1970)            /* By definition of C library */
  2663.       return("");
  2664.  
  2665.     if (time_stamp->tm_mon  < 0 || time_stamp->tm_mon  > 11)
  2666.       return("");
  2667.     if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
  2668.       return("");
  2669.     if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
  2670.       return("");
  2671.     if (time_stamp->tm_min  < 0 || time_stamp->tm_min  > 59)
  2672.       return("");
  2673.     ss = time_stamp->tm_sec;        /* Seconds */
  2674.     if (ss < 0 || ss  > 59)        /* Some systems give a BIG number */
  2675.       ss = 0;
  2676.     sprintf(datbuf,
  2677. #ifdef pdp11
  2678. /* For some reason, 2.1x BSD sprintf gets the last field wrong. */
  2679.         "%04d%02d%02d %02d:%02d:00",
  2680. #else
  2681.         "%04d%02d%02d %02d:%02d:%02d",
  2682. #endif /* pdp11 */
  2683.         yy,
  2684.         time_stamp->tm_mon + 1,
  2685.         time_stamp->tm_mday,
  2686.         time_stamp->tm_hour,
  2687.         time_stamp->tm_min
  2688. #ifndef pdp11
  2689.         , ss
  2690. #endif /* pdp11 */
  2691.         );
  2692.     yy = (int)strlen(datbuf);
  2693.     debug(F111,"zdatstr",datbuf,yy);
  2694.     if (yy > 17) datbuf[17] = '\0';
  2695.     return(datbuf);
  2696. }
  2697.  
  2698. char *
  2699. zfcdat(name) char *name; {
  2700.  
  2701. #ifdef TIMESTAMP
  2702. #ifdef NT
  2703.     struct _stat buffer;
  2704. #else /* NT */
  2705.     struct stat buffer;
  2706. #endif /* NT */
  2707.  
  2708.     datbuf[0] = '\0';
  2709.     if (stat(name,&buffer) != 0) {
  2710.     debug(F110,"zfcdat stat failed",name,0);
  2711.     return("");
  2712.     }
  2713.     return(zdtstr(buffer.st_mtime));
  2714. #else
  2715.     return("");
  2716. #endif /* TIMESTAMP */
  2717. }
  2718.  
  2719. time_t
  2720. zstrdt(date,len) char * date; int len; {
  2721. /*
  2722.   To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
  2723.   is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
  2724. */
  2725. #ifndef OS2
  2726. #ifdef M_UNIX
  2727. /*
  2728.   SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
  2729.   ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
  2730.   dependence on the XPG4 supplement presence.  So always use
  2731.   what the system header file supplies in ODT 3.0...
  2732. */
  2733. #ifndef ODT30
  2734. #ifndef _SCO_DS
  2735.     extern void ftime();  /* extern void ftime(struct timeb *) */
  2736. #endif /* _SCO_DS */
  2737. #endif /* ODT30 */
  2738. #else
  2739.     extern int ftime();    
  2740. #endif /* M_UNIX */
  2741.     extern int stat();
  2742.     extern struct tm * localtime();
  2743.  
  2744.     /* and this should have been declared always through a header file */
  2745. #endif /* OS2 */
  2746.     long tmx, days;
  2747.     int i, n, isleapyear;
  2748.                    /*       J  F  M  A   M   J   J   A   S   O   N   D   */
  2749.                    /*      31 28 31 30  31  30  31  31  30  31  30  31   */
  2750.     static
  2751.     int monthdays [13] = {  0,0,31,59,90,120,151,181,212,243,273,304,334 };
  2752.     char s[5];
  2753.     struct tm *time_stamp;
  2754.  
  2755. #ifdef BSD44
  2756.     struct timeval tp[2];
  2757.     long xtimezone;
  2758. #else
  2759. #ifdef OS2
  2760.  
  2761. #ifdef NT
  2762. struct _utimbuf tp;
  2763. #else /* NT */
  2764. struct utimbuf tp;
  2765. #endif /* NT */
  2766.  
  2767. #ifdef __EMX__
  2768.     long timezone;
  2769.     struct timeb tbp;
  2770. #endif /* __EMX__ */
  2771. #else
  2772. #ifdef V7
  2773.     struct utimbuf {
  2774.       time_t timep[2];        /* New access and modificaton time */
  2775.     } tp;
  2776.     char *tz;
  2777.     long timezone;        /* In case timezone not defined in .h file */
  2778. #else
  2779. #ifdef SYSUTIMEH
  2780.     struct utimbuf tp;
  2781. #else
  2782.     struct utimbuf {
  2783.     time_t atime;
  2784.     time_t mtime;
  2785.     } tp;
  2786. #endif /* SYSUTIMEH */
  2787. #endif /* V7 */
  2788. #endif /* OS2 */
  2789. #endif /* BSD44 */
  2790.  
  2791. #ifdef ANYBSD
  2792.     long timezone = 0L;
  2793.     static struct timeb tbp;
  2794. #endif /* ANYBSD */
  2795.  
  2796. #ifdef BEBOX
  2797.     long timezone = 0L;
  2798. #endif /* BEBOX */
  2799.  
  2800.     debug(F111,"zstrdt",date,len);
  2801.  
  2802.     if ((len == 0)
  2803.         || (len != 17)
  2804.         || (date[8] != ' ')
  2805.         || (date[11] != ':')
  2806.         || (date[14] != ':') ) {
  2807.         debug(F111,"Bad creation date ",date,len);
  2808.         return(-1);
  2809.     }
  2810.     debug(F111,"zstime date check 1",date,len);
  2811.     for(i = 0; i < 8; i++) {
  2812.     if (!isdigit(date[i])) {
  2813.         debug(F111,"Bad creation date ",date,len);
  2814.         return(-1);
  2815.     }
  2816.     }
  2817.     debug(F111,"zstime date check 2",date,len);
  2818.     i++;
  2819.  
  2820.     for (; i < 16; i += 3) {
  2821.     if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
  2822.         debug(F111,"Bad creation date ",date,len);
  2823.         return(-1);
  2824.     }
  2825.     }
  2826.     debug(F111,"zstime date check 3",date,len);
  2827.  
  2828. #ifdef BSD44
  2829.     {
  2830.     int x;
  2831.     struct timezone tzp;
  2832.     x = gettimeofday(NULL, &tzp);
  2833.     debug(F101,"zstime BSD44 gettimeofday","",x);
  2834.     if (x > -1)
  2835.       xtimezone = tzp.tz_minuteswest * 60L;
  2836.     else
  2837.       xtimezone = 0L;
  2838.     debug(F101,"zstime BSD44 timezone","",xtimezone);
  2839.     }
  2840. #else
  2841. #ifdef ANYBSD
  2842.     debug(F100,"zstime BSD calling ftime","",0);
  2843.     ftime(&tbp);
  2844.     debug(F100,"zstime BSD back from ftime","",0);
  2845.     timezone = tbp.timezone * 60L;
  2846.     debug(F101,"zstime BSD timezone","",timezone);
  2847. #else
  2848. #ifdef OS2
  2849. #ifdef __EMX__
  2850.     ftime(&tbp);
  2851.     timezone = tbp.timezone * 60L;
  2852. #endif /* __EMX__ */
  2853. #else
  2854. #ifdef SVORPOSIX
  2855.     tzset();                /* Set timezone */
  2856. #else
  2857. #ifdef V7
  2858.     if ((tz = getenv("TZ")) == NULL)
  2859.       timezone = 0;            /* UTC/GMT */
  2860.     else
  2861.       timezone = atoi(&tz[3]);        /* Set 'timezone'. */
  2862.     timezone *= 60L;
  2863. #endif /* V7 */
  2864. #endif /* SVORPOSIX */
  2865. #endif /* OS2 */
  2866. #endif /* ANYBSD */
  2867. #endif /* BSD44 */
  2868.  
  2869.     debug(F100,"zstime so far so good","",0);
  2870.  
  2871.     s[4] = '\0';
  2872.     for (i = 0; i < 4; i++)        /* Fix the year */
  2873.       s[i] = date[i];
  2874.  
  2875.     n = atoi(s);
  2876.     debug(F111,"zstime year",s,n);
  2877.     if (n < 1970) {
  2878.     debug(F100,"zstime fails - year","",n);
  2879.     return(-1);
  2880.     }
  2881.  
  2882. /*  Previous year's leap days.  This won't work after year 2100. */
  2883.  
  2884.     isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
  2885.     days = (long) (n - 1970) * 365;
  2886.     days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
  2887.  
  2888.     s[2] = '\0';
  2889.  
  2890.     for (i = 4; i < 16; i += 2) {
  2891.     s[0] = date[i];
  2892.     s[1] = date[i + 1];
  2893.     n = atoi(s);
  2894.     switch (i) {
  2895.       case 4:            /* MM: month */
  2896.         if ((n < 1 ) || ( n > 12)) {
  2897.         debug(F111,"zstime 4 bad date ",date,len);
  2898.         return(-1);
  2899.         }
  2900.         days += monthdays [n];
  2901.         if (isleapyear && n > 2)
  2902.           ++days;
  2903.         continue;
  2904.  
  2905.       case 6:            /* DD: day */
  2906.         if ((n < 1 ) || ( n > 31)) {
  2907.         debug(F111,"zstime 6 bad date ",date,len);
  2908.         return(-1);
  2909.         }
  2910.         tmx = (days + n - 1) * 24L * 60L * 60L;
  2911.         i++;            /* Skip the space */
  2912.         continue;
  2913.  
  2914.       case 9:            /* hh: hour */
  2915.         if ((n < 0 ) || ( n > 23)) {
  2916.         debug(F111,"zstime 9 bad date ",date,len);
  2917.         return(-1);
  2918.         }
  2919.         tmx += n * 60L * 60L;
  2920.         i++;            /* Skip the colon */
  2921.         continue;
  2922.  
  2923.       case 12:            /* mm: minute */
  2924.         if ((n < 0 ) || ( n > 59)) {
  2925.         debug(F111,"zstime 12 bad date ",date,len);
  2926.         return(-1);
  2927.         }
  2928. #ifdef BSD44                /* Correct for time zone */
  2929.         tmx += xtimezone;
  2930.         debug(F101,"zstime BSD44 tmx","",tmx);
  2931. #else
  2932. #ifdef ANYBSD
  2933.         tmx += timezone;
  2934. #else
  2935. #ifndef CONVEX9 /* Don't yet know how to do this here */
  2936. #ifdef ultrix
  2937.         tmx += (long) timezone;
  2938. #else
  2939. #ifdef Plan9
  2940.         {
  2941.         extern time_t tzoffset;
  2942.         tmx += tzoffset;
  2943.         }
  2944. #else
  2945.         tmx += timezone;
  2946. #endif /* Plan9 */
  2947. #endif /* ultrix */
  2948. #endif /* CONVEX9 */
  2949. #endif /* BSD44 */
  2950. #endif /* ANYBSD */
  2951.         tmx += n * 60L;
  2952.         i++;            /* Skip the colon */
  2953.         continue;
  2954.  
  2955.       case 15:            /* ss: second */
  2956.         if ((n < 0 ) || ( n > 59)) {
  2957.         debug(F111,"zstime 15 bad date ",date,len);
  2958.         return(-1);
  2959.         }
  2960.         tmx += n;
  2961.     }
  2962.     time_stamp = localtime(&tmx);
  2963.     if (!time_stamp)
  2964.       return(-1);
  2965.     if (localtime(&tmx)->tm_isdst)
  2966.       tmx -= 60L * 60L;        /* Adjust for daylight savings time */
  2967.     }
  2968.     return(tmx);
  2969. }
  2970.  
  2971. /* Z S T I M E  --  Set creation date for incoming file */
  2972. /*
  2973.  Call with:
  2974.  f  = pointer to name of existing file.
  2975.  yy = pointer to a Kermit file attribute structure in which yy->date.val
  2976.       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
  2977.  x  = is a function code: 0 means to set the file's creation date as given.
  2978.       1 means compare the given date with the file creation date.
  2979.  Returns:
  2980.  -1 on any kind of error.
  2981.   0 if x is 0 and the file date was set successfully.
  2982.   0 if x is 1 and date from attribute structure <= file creation date.
  2983.   1 if x is 1 and date from attribute structure > file creation date.
  2984. */
  2985. int
  2986. zstime(f,yy,x)
  2987. #ifdef HPUX10
  2988. #ifdef CK_ANSIC
  2989.   const 
  2990. #endif /* CK_ANSIC */
  2991. #endif /* HPUX10 */
  2992.   char *f; struct zattr *yy; int x;
  2993. /* zstime */ {
  2994.     int r = -1;                /* Return code */
  2995.  
  2996. /* It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se.  */
  2997.  
  2998. #ifdef TIMESTAMP
  2999. #ifndef OS2
  3000. #ifdef BSD44
  3001.     extern int utimes();
  3002. #else
  3003.     extern int utime();
  3004. #endif /* BSD44 */
  3005. #endif /* OS2 */
  3006.  
  3007. /* At least, the declarations for int functions are not needed anyway */
  3008.  
  3009. #ifdef NT
  3010.     struct _stat sb;
  3011. #else /* NT */
  3012.     struct stat sb;
  3013. #endif /* NT */
  3014.  
  3015. #ifdef BSD44
  3016.     struct timeval tp[2];
  3017.     long xtimezone;
  3018. #else
  3019. #ifdef OS2
  3020.  
  3021. #ifdef NT
  3022. struct _utimbuf tp;
  3023. #else /* NT */
  3024. struct utimbuf tp;
  3025. #endif /* NT */
  3026.  
  3027. #ifdef __EMX__
  3028.     long timezone;
  3029.     struct timeb tbp;
  3030. #endif /* __EMX__ */
  3031. #else
  3032. #ifdef V7
  3033.     struct utimbuf {
  3034.       time_t timep[2];            /* New access and modificaton time */
  3035.     } tp;
  3036.     char *tz;
  3037.     long timezone;            /* In case not defined in .h file */
  3038. #else
  3039. #ifdef SYSUTIMEH
  3040.     struct utimbuf tp;
  3041. #else
  3042.     struct utimbuf {
  3043.     time_t atime;
  3044.     time_t mtime;
  3045.     } tp;
  3046. #endif /* SYSUTIMEH */
  3047. #endif /* V7 */
  3048. #endif /* OS2 */
  3049. #endif /* BSD44 */
  3050.  
  3051.     long tm;
  3052.  
  3053.     debug(F110,"zstime",f,0);
  3054.     debug(F111,"zstime",yy->date.val,yy->date.len);
  3055.     if ((tm = zstrdt(yy->date.val,yy->date.len)) < 0) {
  3056.     debug(F101,"zstime: zstrdt fails","",0);
  3057.     return(-1);
  3058.     }
  3059.     debug(F101,"zstime: tm","",tm);
  3060.     debug(F111,"zstime: A-pkt date ok ",yy->date.val,yy->date.len);
  3061.  
  3062.     if (stat(f,&sb)) {            /* Get the time for the file */
  3063.     debug(F110,"zstime: Can't stat file:",f,0);
  3064.     return(-1);
  3065.     }
  3066.     debug(F101,"zstime: sb.st_atime","",sb.st_atime);
  3067.  
  3068. #ifdef OS2
  3069.     tp.modtime = tm;            /* Set modif. time to creation date */
  3070.     tp.actime = sb.st_atime;        /* Don't change the access time */
  3071. #else
  3072. #ifdef SYSUTIMEH
  3073.     tp.modtime = tm;            /* Set modif. time to creation date */
  3074.     tp.actime = sb.st_atime;        /* Don't change the access time */
  3075. #else
  3076. #ifdef V7
  3077.     tp.timep[0] = tm;            /* Set modif. time to creation date */
  3078.     tp.timep[1] = sb.st_atime;        /* Don't change the access time */
  3079. #else
  3080. #ifdef BSD44
  3081.     tp[0].tv_sec = sb.st_atime;        /* Access time first */
  3082.     tp[1].tv_sec = tm;            /* Update time second */
  3083. #else
  3084.     tp.mtime = tm;            /* Set modif. time to creation date */
  3085.     tp.atime = sb.st_atime;        /* Don't change the access time */
  3086. #endif /* BSD44 */
  3087. #endif /* V7 */
  3088. #endif /* SYSUTIMEH */
  3089. #endif /* OS2 */
  3090.  
  3091.     switch (x) {            /* Execute desired function */
  3092.       case 0:                /* Set the creation date of the file */
  3093.     if (
  3094. #ifdef BSD44
  3095.         utimes(f,tp)
  3096. #else
  3097. #ifdef NT
  3098.         _utime(f,&tp)
  3099. #else /* NT */
  3100.         utime(f,&tp)
  3101. #endif /* NT */
  3102. #endif /* BSD44 */
  3103.         ) {        /* Fix modification time */
  3104.         debug(F110,"zstime 0: can't set modtime for file",f,0);
  3105.         r = -1;
  3106.     } else  {
  3107.         debug(F110,"zstime 0: modtime set for file",f,0);
  3108.         r = 0;
  3109.     }
  3110.     break;
  3111.       case 1:                /* Compare the dates */
  3112. /*
  3113.   This was st_atime, which was wrong.  We want the file-data modification
  3114.   time, st_mtime.
  3115. */
  3116.     debug(F111,"zstime 1: compare",f,sb.st_mtime);
  3117.     debug(F111,"zstime 1: compare","packet",tm);
  3118. #ifdef OS2
  3119. /*
  3120.   In OS/2, sb.st_mtime, at least on a FAT file system, is always even.
  3121.   In that case, if the incoming file is only one second newer than the
  3122.   local file, consider them the same.  (THERE MUST BE A BETTER FIX FOR THIS!)
  3123. */
  3124.     if ((sb.st_mtime & 1) == 0)
  3125.       if ((tm - sb.st_mtime) == 1)
  3126.         tm--;
  3127. #endif /* OS2 */
  3128.     r = (sb.st_mtime < tm) ? 0 : 1;
  3129.     break;
  3130.  
  3131.       default:                /* Error */
  3132.     r = -1;
  3133.     }
  3134. #endif /* TIMESTAMP */
  3135.     return(r);
  3136. }
  3137.  
  3138. /* Find initialization file. */
  3139.  
  3140. #ifdef NOTUSED
  3141. int
  3142. zkermini() {
  3143. /*  nothing here for Unix.  This function added for benefit of VMS Kermit.  */
  3144.     return(0);
  3145. }
  3146. #endif /* NOTUSED */
  3147.  
  3148. #ifndef NOFRILLS
  3149. int
  3150. zmail(p,f) char *p; char *f; {        /* Send file f as mail to address p */
  3151. /*
  3152.   Returns 0 on success
  3153.    2 if mail delivered but temp file can't be deleted
  3154.   -2 if mail can't be delivered
  3155.   The UNIX version always returns 0 because it can't get a good return
  3156.   code from zsyscmd.
  3157. */
  3158. #ifdef BSD4
  3159. /* The idea is to use /usr/ucb/mail, rather than regular mail, so that   */
  3160. /* a subject line can be included with -s.  Since we can't depend on the */
  3161. /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
  3162. /* and even if Mail has been moved to somewhere else, this should still  */
  3163. /* find it...  The search could be made more reliable by actually using  */
  3164. /* access() to see if /usr/ucb/Mail exists. */
  3165.  
  3166. /* Should also make some check on zmbuf overflow... */
  3167.  
  3168. #ifdef DGUX540
  3169.     sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
  3170. #else
  3171.     sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
  3172. #endif /* DGUX540 */
  3173.     zsyscmd(zmbuf);
  3174. #else
  3175. #ifdef SVORPOSIX
  3176. #ifndef OXOS
  3177.     sprintf(zmbuf,"mail %s < %s", p, f);
  3178. #else /* OXOS */
  3179.     sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
  3180. #endif /* OXOS */
  3181.     zsyscmd(zmbuf);
  3182. #else
  3183.     *zmbuf = '\0';
  3184. #endif
  3185. #endif
  3186.     return(0);
  3187. }
  3188. #endif /* NOFRILLS */
  3189.  
  3190. #ifndef NOFRILLS
  3191. int
  3192. zprint(p,f) char *p; char *f; {        /* Print file f with options p */
  3193.     extern char * printfile;        /* From ckuus3.c */
  3194.     extern int printpipe;
  3195.  
  3196.     debug(F110,"zprint file",f,0);
  3197.     debug(F110,"zprint flags",p,0);
  3198.     debug(F110,"zprint printfile",printfile,0);
  3199.     debug(F101,"zprint printpipe","",printpipe);
  3200.  
  3201. #ifdef NT
  3202.     if (printfile) {
  3203.     if (printpipe) 
  3204.       sprintf(zmbuf,"COPY /B %s | %s", f, printfile);
  3205.     else
  3206.       sprintf(zmbuf,"COPY /B %s %s", f, printfile);
  3207.     } else {
  3208.     sprintf(zmbuf,"COPY /B %s PRN", f);
  3209.     }
  3210.     debug(F110,"zprint command",zmbuf,0);
  3211.     zsyscmd(zmbuf);
  3212. #else
  3213. #ifdef OS2
  3214.     if (printfile) {
  3215.     if (printpipe) 
  3216.       sprintf(zmbuf,"COPY /B %s | %s", f, printfile);
  3217.     else
  3218.       sprintf(zmbuf,"COPY /B %s %s", f, printfile);
  3219.     } else {
  3220.     sprintf(zmbuf,"print %s %s", p, f); /* Construct print command */
  3221.     }
  3222.     debug(F110,"zprint command",zmbuf,0);
  3223.     zsyscmd(zmbuf);
  3224. #else
  3225. #ifdef UNIX
  3226. #ifdef ANYBSD                /* BSD uses lpr to spool */
  3227. #ifdef DGUX540                /* And DG/UX */
  3228. #define SPOOLER "lp"
  3229. #else
  3230. #define SPOOLER "lpr"
  3231. #endif /* DGUX540 */
  3232. #else                    /* Sys V uses lp */
  3233. #ifdef TRS16                /* except for Tandy-16/6000... */
  3234. #define SPOOLER "lpr"
  3235. #else
  3236. #define SPOOLER "lp"
  3237. #endif
  3238. #endif
  3239. /*
  3240.   Note use of standard input redirection.  In some systems, lp[r] runs
  3241.   setuid to lp (or ...?), so if user has sent a file into a directory
  3242.   that lp does not have read access to, it can't be printed unless it is
  3243.   fed to lp[r] as standard input.
  3244. */
  3245.     if (printpipe && printfile) {
  3246.     sprintf(zmbuf,"cat %s | %s", f, printfile);
  3247.     } else if (printfile) {
  3248.     sprintf(zmbuf,"cat %s >> %s", f, printfile);
  3249.     } else {
  3250.     sprintf(zmbuf,"%s %s < %s", SPOOLER, p, f);
  3251.     }
  3252.     debug(F110,"zprint command",zmbuf,0);
  3253.     zsyscmd(zmbuf);
  3254. #else /* Not UNIX */
  3255.     *zmbuf = '\0';
  3256. #endif /* UNIX */
  3257. #endif /* OS2 */
  3258. #endif /* NT */
  3259.     return(0);
  3260. }
  3261. #endif /* NOFRILLS */
  3262.  
  3263. /*
  3264.   Wildcard expansion functions.  C-Kermit used to insist on doing this itself
  3265.   New code (version 5A, 1990-91) gives user option to ask UNIX to do it.
  3266.   This lets users use the wildcard expansion features of their favorite shell.
  3267.   Operation is slower because of the forking & piping, but flexibility is
  3268.   greater and program is smaller.  For OS/2, C-Kermit still does this itself.
  3269. */
  3270. static char scratch[MAXPATH+4];        /* Used by both methods */
  3271.  
  3272. #ifndef OS2
  3273. static int oldmtchs = 0;        /* Let shell (ls) expand them. */
  3274. #ifdef COMMENT
  3275. static char *lscmd = "/bin/ls -d";     /* Command to use. */
  3276. #else
  3277. static char *lscmd = "echo";        /* Command to use. */
  3278. #endif /* COMMENT */
  3279.  
  3280. #ifndef NOPUSH
  3281. int
  3282. shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
  3283.     char *fgbuf = NULL;            /* Buffer for forming ls command */
  3284.     char *p, *q;            /* Workers */
  3285.     int i, x, retcode; char c;        /* ... */
  3286.  
  3287.     x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
  3288.     for (i = 0; i < oldmtchs; i++) {    /* Free previous file list */
  3289.     if (namlst[i] ) {        /* If memory is allocated  */
  3290.         free(namlst[i]);        /* Free the memory         */
  3291.         namlst[i] = NULL ;        /* Remember no memory is allocated */
  3292.     }
  3293.     }
  3294.     oldmtchs = 0 ;            /* Remember there are no matches */
  3295.     fgbuf = malloc(x);            /* Get buffer for command */
  3296.     if (!fgbuf) return(-1);        /* Fail if cannot */
  3297.     sprintf(fgbuf,"%s %s",lscmd,pat);    /* Form the command */
  3298.     zxcmd(ZIFILE,fgbuf);        /* Start the command */
  3299.     i = 0;                /* File counter */
  3300.     p = scratch;            /* Point to scratch area */
  3301.     retcode = -1;            /* Assume failure */
  3302.     while ((x = zminchar()) != -1) {    /* Read characters from command */
  3303.     c = (char) x;
  3304.     if (c == ' ' || c == '\n') {    /* Got newline or space? */
  3305.         *p = '\0';            /* Yes, terminate string */
  3306.         p = scratch;        /* Point back to beginning */
  3307.         if (zchki(p) == -1)        /* Does file exist? */
  3308.           continue;            /* No, continue */
  3309.         x = (int)strlen(p);        /* Yes, get length of name */
  3310.         q = malloc(x+1);        /* Allocate space for it */
  3311.         if (!q) goto shxfin;    /* Fail if space can't be obtained */
  3312.         strcpy(q,scratch);        /* Copy name to space */
  3313.         namlst[i++] = q;        /* Copy pointer to name into array */
  3314.         if (i >= len) goto shxfin;    /* Fail if too many */
  3315.     } else {            /* Regular character */
  3316.         *p++ = c;            /* Copy it into scratch area */
  3317.     }
  3318.     }
  3319.     retcode = i;            /* Return number of matching files */
  3320. shxfin:                    /* Common exit point */
  3321.     free(fgbuf);            /* Free command buffer */
  3322.     fgbuf = NULL;
  3323.     zclosf(ZIFILE);            /* Delete the command fork. */
  3324.     oldmtchs = i;            /* Remember how many files */
  3325.     return(retcode);
  3326. }
  3327. #endif /* NOPUSH */
  3328. #endif /* OS2 */
  3329.  
  3330. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  3331.  
  3332. /* Define the size of the string space for filename expansion. */
  3333.  
  3334. #ifndef DYNAMIC
  3335. #ifdef PROVX1
  3336. #define SSPACE 500
  3337. #else
  3338. #ifdef BSD29
  3339. #define SSPACE 500
  3340. #else
  3341. #ifdef pdp11
  3342. #define SSPACE 500
  3343. #else
  3344. #ifdef aegis
  3345. #define SSPACE 10000            /* size of string-generating buffer */
  3346. #else                    /* Default static buffer size */
  3347. #ifdef BIGBUFOK
  3348. #define SSPACE 32768            /* size of string-generating buffer */
  3349. #else
  3350. #define SSPACE 2000            /* size of string-generating buffer */
  3351. #endif /* BIGBUFOK */
  3352. #endif /* aegis */
  3353. #endif /* pdp11 */
  3354. #endif /* BSD29 */
  3355. #endif /* PROVX1 */
  3356. static char sspace[SSPACE];             /* Buffer for generating filenames */
  3357. #else /* is DYNAMIC */
  3358. #ifdef BIGBUFOK
  3359. #define SSPACE 32768
  3360. #else
  3361. #define SSPACE 10000
  3362. #endif /* BIGBUFOK */
  3363. static char *sspace = (char *)0;
  3364. #endif /* DYNAMIC */
  3365. static int ssplen = SSPACE;        /* Length of string space buffer */
  3366.  
  3367. static char *freeptr, **resptr;            /* copies of caller's arguments */
  3368. static int remlen;                      /* remaining length in caller's array*/
  3369. static int numfnd;                      /* number of matches found */
  3370.  
  3371. #ifdef aegis
  3372. static char bslash;
  3373. #endif /* aegis */
  3374.  
  3375. /*
  3376.  * splitpath:
  3377.  *  takes a string and splits the slash-separated portions into
  3378.  *  a list of path structures.  Returns the head of the list.  The
  3379.  *  structures are allocated by malloc, so they must be freed.
  3380.  *  Splitpath is used internally by the filename generator.
  3381.  *
  3382.  * Input: A string.
  3383.  * Returns: A linked list of the slash-separated segments of the input.
  3384.  */
  3385.  
  3386. struct path *
  3387. splitpath(p) char *p; {
  3388.     struct path *head,*cur,*prv;
  3389.     int i;
  3390.  
  3391.     debug(F110,"splitpath",p,0);
  3392.  
  3393.     head = prv = NULL;
  3394.     if (ISDIRSEP(*p)) p++;            /* skip leading slash */
  3395. #ifdef OS2
  3396.     if ( *p == '\0' ) {    /* the user wants the root directory */
  3397.         cur = (struct path *) malloc(sizeof(struct path));
  3398.         debug(F101,"splitpath malloc","",cur);
  3399.         if (cur == NULL) {
  3400.             debug(F100,"splitpath malloc failure","",0);
  3401.             return((struct path *)NULL);
  3402.         }
  3403.         cur->fwd = NULL;
  3404.         cur->npart[0] = '.';
  3405.         cur->npart[1] = '\0';
  3406.         head = cur;
  3407.         return head;
  3408.         }
  3409. #endif /* OS2 */
  3410.     while (*p != '\0') {
  3411.     cur = (struct path *) malloc(sizeof (struct path));
  3412.     debug(F101,"splitpath malloc","",cur);
  3413.     if (cur == NULL) {
  3414.         debug(F100,"splitpath malloc failure","",0);
  3415.         return((struct path *)NULL);
  3416.     }
  3417.     cur -> fwd = NULL;
  3418.     if (head == NULL)
  3419.       head = cur;
  3420.     else
  3421.       prv -> fwd = cur;        /* link into chain */
  3422.     prv = cur;
  3423. #ifdef aegis
  3424.     /* treat backslash as "../" */
  3425.     if (bslash && *p == bslash) {
  3426.         strcpy(cur->npart, "..");
  3427.         ++p;
  3428.     } else {
  3429.         for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
  3430.           cur -> npart[i] = *p++;
  3431.         cur -> npart[i] = '\0';    /* end this segment */
  3432.         if (i >= MAXNAMLEN)
  3433.           while (*p && *p != '/' && *p != bslash)
  3434.         p++;
  3435.     }
  3436.     if (*p == '/') p++;
  3437. #else
  3438. #ifdef OS2
  3439.     for (i = 0;
  3440.          i < MAXNAMLEN && !ISDIRSEP(*p) && *p != ':' && *p != '\0';
  3441.          i++ )
  3442.         cur -> npart[i] = *p++;
  3443.         if ( *p == ':' ) {
  3444.             cur -> npart[i++] = *p++;
  3445.             if ( !ISDIRSEP(*p) )
  3446.                 cur -> npart[i++] = '.';
  3447.         }
  3448. #else
  3449.     for (i=0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
  3450.         cur -> npart[i] = *p++;
  3451.     }
  3452. #endif /* OS2 */
  3453.     cur -> npart[i] = '\0';        /* end this segment */
  3454.     if (i >= MAXNAMLEN)
  3455.       while (!ISDIRSEP(*p) && *p != '\0') p++;
  3456.     if (ISDIRSEP(*p))
  3457.       p++;
  3458.  
  3459. #endif /* aegis */
  3460.     }
  3461.     return(head);
  3462. }
  3463.  
  3464. /*
  3465.  * fgen:
  3466.  *  This is the actual name generator.  It is passed a string,
  3467.  *  possibly containing wildcards, and an array of character pointers.
  3468.  *  It finds all the matching filenames and stores pointers to them in the
  3469.  *  array.  The returned strings are allocated from a static buffer local to
  3470.  *  this module (so the caller doesn't have to worry about deallocating
  3471.  *  them); this means that successive calls to fgen will wipe out
  3472.  *  the results of previous calls.  This isn't a problem here
  3473.  *  because we process one wildcard string at a time.
  3474.  *
  3475.  * Input: a wildcard string, an array to write names to, the
  3476.  *        length of the array.
  3477.  * Returns: the number of matches.  The array is filled with filenames
  3478.  *          that matched the pattern.  If there wasn't enough room in the
  3479.  *        array, -1 is returned.
  3480.  * Originally by: Jeff Damens, CUCCA, 1984.  Many changes since then.
  3481.  */
  3482. static int
  3483. fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
  3484.     struct path *head;
  3485.     char *sptr;
  3486. #ifdef aegis
  3487.     char *namechars;
  3488.     int tilde = 0, bquote = 0;
  3489.  
  3490.     if ((namechars = getenv("NAMECHARS")) != NULL) {
  3491.     if (xindex(namechars, '~' ) != NULL) tilde  = '~';
  3492.     if (xindex(namechars, '\\') != NULL) bslash = '\\';
  3493.     if (xindex(namechars, '`' ) != NULL) bquote = '`';
  3494.     } else {
  3495.     tilde = '~'; bslash = '\\'; bquote = '`';
  3496.     }
  3497.     sptr = scratch;
  3498.  
  3499.     /* copy "`node_data", etc. anchors */
  3500.     if (bquote && *pat == bquote)
  3501.       while (*pat && *pat != '/' && *pat != bslash)
  3502.     *sptr++ = *pat++;
  3503.     else if (tilde && *pat == tilde)
  3504.       *sptr++ = *pat++;
  3505.     while (*pat == '/')
  3506.       *sptr++ = *pat++;
  3507.     if (sptr == scratch) {
  3508.     strcpy(scratch,"./");
  3509.     sptr = scratch+2;
  3510.     }                    /* init buffer correctly */
  3511.     if (!(head = splitpath(pat))) return(-1);
  3512. #else /* not aegis */
  3513.     debug(F110,"fgen pat",pat,0);
  3514. #ifdef OS2
  3515.     head = splitpath(pat);
  3516. #else /* not OS2 */
  3517.     if (!(head = splitpath(pat))) return(-1);
  3518. #endif /* OS2 */
  3519.     sptr = scratch;
  3520.     if (!ISDIRSEP(*pat))
  3521.       *sptr++ = '.';            /* init buffer correctly */
  3522.     *sptr++ = DIRSEP;
  3523. #ifdef OS2
  3524.     if (isalpha(pat[0]) && pat[1] == ':')
  3525.         sptr = scratch;                 /* reset in case of leading drive: */
  3526. #endif /* OS2 */
  3527. #endif /* aegis */
  3528.     numfnd = 0;                /* none found yet */
  3529. #ifdef DYNAMIC
  3530.     if (!sspace) {            /* Need to allocate string space? */
  3531.     while (ssplen > 50) {
  3532.         if ((sspace = malloc(ssplen+2))) { /* Got it. */
  3533.         debug(F101,"fgen string space","",ssplen);
  3534.         break;
  3535.         }
  3536.         ssplen = (ssplen / 2) + (ssplen / 4); /* Didn't, reduce by 3/4 */
  3537.     }
  3538.     if (ssplen <= 50) {        /* Did we get it? */
  3539.         fprintf(stderr,"fgen can't malloc string space\n");
  3540.         return(-1);
  3541.     }
  3542.     }
  3543. #endif /* DYNAMIC */
  3544.     freeptr = sspace;            /* this is where matches are copied */
  3545.     resptr = resarry;            /* static copies of these so */
  3546.     remlen = len;            /* recursive calls can alter them */
  3547.     traverse(head,scratch,sptr);    /* go walk the directory tree */
  3548. #ifdef COMMENT
  3549. /*
  3550.   This code, circa 1984, has never worked right - it references the head
  3551.   pointer after it has already been freed.  Lord knows what might have been
  3552.   happening because of this.  Thanks to Steve Walton for finding & fixing
  3553.   this bug.
  3554. */
  3555.     for (; head != NULL; head = head -> fwd) {
  3556.     free(head);            /* return the path segments */
  3557.     head = NULL;
  3558.     }
  3559. #else
  3560.     while (head != NULL) {
  3561.     struct path *next = head -> fwd;
  3562.     free(head);
  3563.     head = next;
  3564.     }
  3565. #endif /* COMMENT */
  3566.     return(numfnd);            /* and return the number of matches */
  3567. }
  3568.  
  3569. /* traverse:
  3570.  *  Walks the directory tree looking for matches to its arguments.
  3571.  *  The algorithm is, briefly:
  3572.  *   If the current pattern segment contains no wildcards, that
  3573.  *   segment is added to what we already have.  If the name so far
  3574.  *   exists, we call ourselves recursively with the next segment
  3575.  *   in the pattern string; otherwise, we just return.
  3576.  *
  3577.  *   If the current pattern segment contains wildcards, we open the name
  3578.  *   we've accumulated so far (assuming it is really a directory), then read
  3579.  *   each filename in it, and, if it matches the wildcard pattern segment, add
  3580.  *   that filename to what we have so far and call ourselves recursively on the
  3581.  *   next segment.
  3582.  *
  3583.  *   Finally, when no more pattern segments remain, we add what's accumulated
  3584.  *   so far to the result array and increment the number of matches.
  3585.  *
  3586.  * Input: a pattern path list (as generated by splitpath), a string
  3587.  *      pointer that points to what we've traversed so far (this
  3588.  *      can be initialized to "/" to start the search at the root
  3589.  *      directory, or to "./" to start the search at the current
  3590.  *      directory), and a string pointer to the end of the string
  3591.  *      in the previous argument.
  3592.  * Returns: nothing.
  3593.  */
  3594. static VOID
  3595. traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
  3596.  
  3597. /* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
  3598. /* LONGFN can also be defined on the cc command line. */
  3599.  
  3600. #ifdef BSD29
  3601. #ifndef LONGFN
  3602. #define LONGFN
  3603. #endif
  3604. #endif
  3605.  
  3606. #ifdef BSD42
  3607. #ifndef LONGFN
  3608. #define LONGFN
  3609. #endif
  3610. #endif
  3611.  
  3612. /* Appropriate declarations for directory routines and structures */
  3613. /* #define OPENDIR means to use opendir(), readdir(), closedir()  */
  3614. /* If OPENDIR not defined, we use open(), read(), close() */
  3615.  
  3616. #ifdef DIRENT                /* New way, <dirent.h> */
  3617. #define OPENDIR
  3618.     DIR *fd, *opendir();
  3619.     struct dirent *dirbuf;
  3620.     struct dirent *readdir();
  3621. #else /* !DIRENT */
  3622. #ifdef LONGFN                /* Old way, <dir.h> with opendir() */
  3623. #define OPENDIR
  3624.     DIR *fd, *opendir();
  3625.     struct direct *dirbuf;
  3626. #else /* !LONGFN */
  3627.     int fd;                /* Old way, <dir.h> with open() */
  3628.     struct direct dir_entry;
  3629.     struct direct *dirbuf = &dir_entry;
  3630. #endif /* LONGFN */
  3631. #endif /* DIRENT */
  3632.  
  3633. #ifdef NT
  3634.     struct _stat statbuf;        /* for file info */
  3635. #else /* NT */
  3636.     struct stat statbuf;        /* for file info */
  3637. #endif /* NT */
  3638.  
  3639.     if (pl == NULL) {
  3640.     *--endcur = '\0';        /* end string, overwrite trailing / */
  3641.     addresult(sofar);
  3642.     return;
  3643.     }
  3644.     if (!iswild(pl -> npart)) {
  3645.     strcpy(endcur,pl -> npart);
  3646.     endcur += (int)strlen(pl -> npart);
  3647.     *endcur = '\0';            /* end current string */
  3648.     if (stat(sofar,&statbuf) == 0) { /* if current piece exists */
  3649. #ifdef OS2
  3650.         if (endcur - sofar == 3 && endcur[-1] == '.' && endcur[-2] == ':')
  3651.           endcur--;
  3652.         else
  3653. #endif /* OS2 */
  3654.           *endcur++ = DIRSEP;    /* add slash to end */
  3655.         *endcur = '\0';        /* and end the string */
  3656.         traverse(pl -> fwd,sofar,endcur);
  3657.     }
  3658.     return;
  3659.     }
  3660.  
  3661.     /* Segment contains wildcards, have to search directory */
  3662.  
  3663.     *endcur = '\0';                            /* end current string */
  3664.     if (stat(sofar,&statbuf) == -1) return;       /* doesn't exist, forget it */
  3665.     if (!S_ISDIR (statbuf.st_mode)) return;     /* not a directory, skip */
  3666.  
  3667. #ifdef OPENDIR
  3668.     if ((fd = opendir(sofar)) == NULL) return; /* Can't open, fail. */
  3669.     while (dirbuf = readdir(fd))
  3670. #else /* !OPENDIR */
  3671.     if ((fd = open(sofar,O_RDONLY)) < 0) return; /* Can't open, fail. */
  3672.     while (read(fd, (char *)dirbuf, sizeof dir_entry))
  3673. #endif /* OPENDIR */
  3674.       {
  3675.       /* Get null-terminated copy!!! */
  3676.       strncpy(nambuf,dirbuf->d_name,MAXNAMLEN);
  3677.       nambuf[MAXNAMLEN] = '\0';
  3678. #ifdef unos
  3679.       if (dirbuf->d_ino != -1 && match(pl -> npart,nambuf))
  3680. #else
  3681. /* #ifdef _POSIX_SOURCE */
  3682. /*
  3683.   Directory reading is not specified in POSIX.1.  POSIX.2 gives us glob() and
  3684.   fnmatch(), which are not yet supported by C-Kermit.  Meanwhile, maybe POSIX
  3685.   implementations should force "set wildcard shell" and remove all of this
  3686.   code.
  3687. */
  3688. #ifdef QNX
  3689.       if (dirbuf->d_stat.st_ino != 0 && match(pl -> npart,nambuf))
  3690. #else
  3691. #ifdef SOLARIS
  3692.       if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
  3693. #else
  3694. #ifdef sun
  3695.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  3696. #else
  3697. #ifdef bsdi
  3698.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  3699. #else
  3700. #ifdef __386BSD__
  3701.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  3702. #else
  3703. #ifdef __FreeBSD__
  3704.       if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
  3705. #else
  3706. #ifdef ultrix
  3707.       if (dirbuf->gd_ino != 0 && match(pl -> npart,nambuf))
  3708. #else
  3709. #ifdef Plan9
  3710.       if (match(pl->npart,nambuf))
  3711. #else
  3712.       if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
  3713. #endif /* Plan9 */
  3714. #endif /* ultrix */
  3715. #endif /* __FreeBSD__ */
  3716. #endif /* __386BSD__ */
  3717. #endif /* bsdi */
  3718. #endif /* sun */
  3719. #endif /* SOLARIS */
  3720. #endif /* QNX */
  3721.  
  3722. /* #else */ /* not _POSIX_SOURCE */
  3723. /*      if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) */
  3724. /* #endif */ /* _POSIX_SOURCE */
  3725.  
  3726. #endif /* unos */
  3727.       {
  3728.           char *eos;
  3729.           strcpy(endcur,nambuf);
  3730.           eos = endcur + (int)strlen(nambuf);
  3731.           *eos++ = DIRSEP;        /* end this segment */
  3732.           traverse(pl -> fwd,sofar,eos);
  3733.       }
  3734.       }
  3735. #ifdef OPENDIR
  3736.     closedir(fd);
  3737. #else /* !OPENDIR */
  3738.     close(fd);
  3739. #endif /* OPENDIR */
  3740. }
  3741.  
  3742. /*
  3743.  * addresult:
  3744.  *  Adds a result string to the result array.  Increments the number
  3745.  *  of matches found, copies the found string into our string
  3746.  *  buffer, and puts a pointer to the buffer into the caller's result
  3747.  *  array.  Our free buffer pointer is updated.  If there is no
  3748.  *  more room in the caller's array, the number of matches is set to -1.
  3749.  * Input: a result string.
  3750.  * Returns: nothing.
  3751.  */
  3752. static VOID
  3753. addresult(str) char *str; {
  3754.     int l;
  3755.     debug(F111,"addresult",str,remlen);
  3756.     if (str[0] == '.' && ISDIRSEP(str[1])) str += 2; /* (===OS2 change===) */
  3757.     if (--remlen < 0) {
  3758.     numfnd = -1;
  3759.     return;
  3760.     }
  3761.     l = (int)strlen(str) + 1;        /* size this will take up */
  3762.     if ((freeptr + l) > (sspace + ssplen)) {
  3763.     numfnd = -1;            /* do not record if not enough space */
  3764.     return;
  3765.     }
  3766.     strcpy(freeptr,str);
  3767.     *resptr++ = freeptr;
  3768.     freeptr += l;
  3769.     numfnd++;
  3770. }
  3771.  
  3772. /*
  3773.  * match:
  3774.  *  pattern matcher.  Takes a string and a pattern possibly containing
  3775.  *  the wildcard characters '*' and '?'.  Returns true if the pattern
  3776.  *  matches the string, false otherwise.
  3777.  * by: Jeff Damens, CUCCA, 1984
  3778.  * skipping over dot files and backslash quoting added by fdc, 1990.
  3779.  *
  3780.  * Input: a string and a wildcard pattern.
  3781.  * Returns: 1 if match, 0 if no match.
  3782.  */
  3783. static int
  3784. match(pattern,string) char *pattern,*string; {
  3785.     char *psave,*ssave;            /* back up pointers for failure */
  3786.     int q = 0;                /* quote flag */
  3787.  
  3788.     debug(F110,"match str",string,0);
  3789.     psave = ssave = NULL;
  3790. #ifndef MATCHDOT
  3791.     if (*string == '.' && *pattern != '.') {
  3792.     debug(F110,"match skip",string,0);
  3793.     return(0);
  3794.     }
  3795. #endif
  3796.     while (1) {
  3797. #ifdef OS2
  3798.     for (; tolower(*pattern) == tolower(*string); pattern++,string++)
  3799. #else
  3800.     for (; *pattern == *string; pattern++,string++)  /* skip first */
  3801. #endif /* OS2 */
  3802.         if (*string == '\0') return(1);    /* end of strings, succeed */
  3803.  
  3804.     if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
  3805.         q = 1;            /* metacharacters */
  3806.         pattern++;            /* advance past quote */
  3807.         if (*pattern != *string) return(0);
  3808.         continue;
  3809.     } else q = 0;
  3810.  
  3811.     if (q) {
  3812.         return(0);
  3813.     } else {
  3814.         if (*string != '\0' && *pattern == '?') {
  3815.         pattern++;        /* '?', let it match */
  3816.         string++;
  3817.         } else if (*pattern == '*') { /* '*' ... */
  3818.         psave = ++pattern;    /* remember where we saw it */
  3819.         ssave = string;        /* let it match 0 chars */
  3820.         } else if (ssave != NULL && *ssave != '\0') { /* if not at end  */
  3821.                     /* ...have seen a star */
  3822.         string = ++ssave;    /* skip 1 char from string */
  3823.         pattern = psave;    /* and back up pattern */
  3824.         } else return(0);        /* otherwise just fail */
  3825.     }
  3826.     }
  3827. }
  3828.  
  3829. /*
  3830.   The following two functions are for expanding tilde in filenames
  3831.   Contributed by Howie Kaye, CUCCA, developed for CCMD package.
  3832. */
  3833.  
  3834. /*  W H O A M I  --  Get user's username.  */
  3835.  
  3836. /*
  3837.   1) Get real uid
  3838.   2) See if the $USER environment variable is set ($LOGNAME on AT&T)
  3839.   3) If $USER's uid is the same as ruid, realname is $USER
  3840.   4) Otherwise get logged in user's name
  3841.   5) If that name has the same uid as the real uid realname is loginname
  3842.   6) Otherwise, get a name for ruid from /etc/passwd
  3843. */
  3844. static char *
  3845. whoami () {
  3846. #ifdef DTILDE
  3847. #ifdef pdp11
  3848. #define WHOLEN 100
  3849. #else
  3850. #define WHOLEN 257
  3851. #endif /* pdp11 */
  3852.     static char realname[256];        /* user's name */
  3853.     static int ruid = -1;        /* user's real uid */
  3854.     char loginname[256], envname[256];    /* temp storage */
  3855.     char *c;
  3856.     struct passwd *p;
  3857.     _PROTOTYP(extern char * getlogin, (void) );
  3858.  
  3859.     if (ruid != -1)
  3860.       return(realname);
  3861.  
  3862.     ruid = real_uid();            /* get our uid */
  3863.  
  3864.   /* how about $USER or $LOGNAME? */
  3865.     if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
  3866.     strcpy (envname, c);
  3867.     if ((p = getpwnam(envname)) != NULL) {
  3868.         if (p->pw_uid == ruid) {    /* get passwd entry for envname */
  3869.         strcpy (realname, envname); /* if the uid's are the same */
  3870.         return(realname);
  3871.         }
  3872.     }
  3873.     }
  3874.  
  3875.   /* can we use loginname() ? */
  3876.  
  3877.     if ((c =  getlogin()) != NULL) {    /* name from utmp file */
  3878.     strcpy (loginname, c);
  3879.     if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
  3880.       if (p->pw_uid == ruid) {    /* for loginname */
  3881.           strcpy (realname, loginname); /* if the uid's are the same */
  3882.           return(realname);
  3883.       }
  3884.     }
  3885.  
  3886.   /* Use first name we get for ruid */
  3887.  
  3888.     if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
  3889.     realname[0] = '\0';        /* no user name */
  3890.     ruid = -1;
  3891.     return(NULL);
  3892.     }
  3893.     strcpy (realname, p->pw_name);
  3894.     return(realname);
  3895. #else
  3896.     return(NULL);
  3897. #endif /* DTILDE */
  3898. }
  3899.  
  3900. /*  T I L D E _ E X P A N D  --  expand ~user to the user's home directory. */
  3901.  
  3902. char *
  3903. tilde_expand(dirname) char *dirname; {
  3904. #ifdef DTILDE
  3905. #ifdef pdp11
  3906. #define BUFLEN 100
  3907. #else
  3908. #define BUFLEN 257
  3909. #endif /* pdp11 */
  3910.     struct passwd *user;
  3911.     static char olddir[BUFLEN];
  3912.     static char oldrealdir[BUFLEN];
  3913.     static char temp[BUFLEN];
  3914.     int i, j;
  3915.  
  3916.     debug(F111,"tilde_expand",dirname,dirname[0]);
  3917.  
  3918.     if (dirname[0] != '~')        /* Not a tilde...return param */
  3919.       return(dirname);
  3920.     if (!strcmp(olddir,dirname)) {    /* Same as last time */
  3921.       return(oldrealdir);        /* so return old answer. */
  3922.     } else {
  3923.     j = (int)strlen(dirname);
  3924.     for (i = 0; i < j; i++)        /* find username part of string */
  3925.       if (!ISDIRSEP(dirname[i]))
  3926.         temp[i] = dirname[i];
  3927.       else break;
  3928.     temp[i] = '\0';            /* tie off with a NULL */
  3929.     if (i == 1) {            /* if just a "~" */
  3930.         user = getpwnam(whoami());    /*  get info on current user */
  3931.     } else {
  3932.         user = getpwnam(&temp[1]);    /* otherwise on the specified user */
  3933.     }
  3934.     }
  3935.     if (user != NULL) {            /* valid user? */
  3936.     strcpy(olddir, dirname);    /* remember the directory */
  3937.     strcpy(oldrealdir,user->pw_dir); /* and their home directory */
  3938.     strcat(oldrealdir,&dirname[i]);
  3939.     return(oldrealdir);
  3940.     } else {                /* invalid? */
  3941.     strcpy(olddir, dirname);    /* remember for next time */
  3942.     strcpy(oldrealdir, dirname);
  3943.     return(oldrealdir);
  3944.     }
  3945. #else
  3946.     return(NULL);
  3947. #endif /* DTILDE */
  3948. }
  3949.  
  3950. /*
  3951.   Functions for executing system commands.
  3952.   zsyscmd() executes the system command in the normal, default way for
  3953.   the system.  In UNIX, it does what system() does.  Thus, its results
  3954.   are always predictable.
  3955.   zshcmd() executes the command using the user's preferred shell.
  3956. */
  3957. int
  3958. zsyscmd(s) char *s; {
  3959. #ifdef aegis
  3960.     if (!priv_chk()) return(system(s));
  3961. #else
  3962. #ifdef OS2
  3963.     /*
  3964.         We must set the priority back to normal.  Otherwise all of children
  3965.         processes are going to inherit our FOREGROUNDSERVER priority
  3966.         and that would not be good for the system or ourselves.
  3967.     */
  3968.  
  3969.    if (!priv_chk()) {
  3970.        ULONG rc = 0;
  3971. #ifndef KUI
  3972.        char title[80];
  3973.        title[0] = '\0';
  3974.        os2gettitle( title, 80 );
  3975.        RequestScreenMutex(SEM_INDEFINITE_WAIT);
  3976. #endif /* KUI */
  3977.        KbdHandlerCleanup();
  3978.        ResetThreadPrty();
  3979.        rc = system(s);
  3980.        SetThreadPrty(priority,15);
  3981.        KbdHandlerInit();
  3982. #ifndef KUI
  3983.        if (
  3984. #ifndef NOSPL
  3985.         cmdlvl == 0
  3986. #else
  3987.         tlevel < 0
  3988. #endif /* NOSPL */
  3989.         )
  3990.        OS2WaitForKey();
  3991.        ReleaseScreenMutex();
  3992.        os2settitle( title, FALSE );
  3993. #endif /* KUI */
  3994.        return rc;
  3995.    }
  3996.    return 0;
  3997. #else
  3998.     PID_T shpid;
  3999. #ifdef COMMENT
  4000. /* This doesn't work... */
  4001.     WAIT_T status;
  4002. #else
  4003.     int status;
  4004. #endif /* COMMENT */
  4005.  
  4006.     if (shpid = fork()) {
  4007.     if (shpid < (PID_T)0) return(-1); /* Parent */
  4008.     while (shpid != (PID_T) wait(&status))
  4009.      ;
  4010.     return(status);
  4011.     }
  4012.     if (priv_can()) {            /* Child: cancel any priv's */
  4013.     printf("?Privilege cancellation failure\n");
  4014.     _exit(255);
  4015.     }
  4016. #ifdef HPUX10
  4017.     execl("/usr/bin/sh","sh","-c",s,NULL);
  4018.     perror("/usr/bin/sh");
  4019. #else
  4020. #ifdef Plan9
  4021.     execl("/bin/rc", "rc", "-c", s, NULL);
  4022.     perror("/bin/rc");
  4023. #else
  4024.     execl("/bin/sh","sh","-c",s,NULL);
  4025.     perror("/bin/sh");
  4026. #endif /* Plan9 */
  4027. #endif /* HPUX10 */
  4028.     _exit(255);
  4029.     return(0);                /* Shut up ANSI compilers. */
  4030. #endif /* OS2 */
  4031. #endif /* aegis */
  4032. }
  4033.  
  4034. /*
  4035.   UNIX code by H. Fischer; copyright rights assigned to Columbia Univ.
  4036.   Adapted to use getpwuid to find login shell because many systems do not
  4037.   have SHELL in environment, and to use direct calling of shell rather
  4038.   than intermediate system() call. -- H. Fischer
  4039.   Call with s pointing to command to execute.
  4040. */
  4041.  
  4042. int
  4043. zshcmd(s) char *s; {
  4044.     PID_T pid;
  4045.  
  4046. #ifdef OS2
  4047.    int rc;
  4048.    char title[80];
  4049. #ifdef NT 
  4050.    SIGTYP (* savint)(int);
  4051. #endif /* NT */
  4052.    char *shell = getenv("SHELL");
  4053.     if ( !shell )
  4054.        shell = getenv("COMSPEC");
  4055.  
  4056.     if (!priv_chk()) {
  4057. #ifndef KUI
  4058.     os2gettitle( title, 80 );
  4059.     RequestScreenMutex(SEM_INDEFINITE_WAIT);
  4060. #endif /* KUI */
  4061.     KbdHandlerCleanup();
  4062.     ResetThreadPrty();
  4063. #ifdef NT
  4064.     savint = signal( SIGINT, SIG_IGN );
  4065. #endif /* NT */
  4066.  
  4067.     if (!s || *s == '\0')
  4068.           rc = system(shell) == 0;    /* was _spawnlp(P_WAIT, shell, NULL) */
  4069.     else
  4070.       rc = system(s) == 0;
  4071. #ifdef NT
  4072.     signal( SIGINT, savint );
  4073. #endif /* NT */
  4074.  
  4075.     SetThreadPrty(priority,15);
  4076.     KbdHandlerInit();
  4077. #ifndef KUI
  4078.     if (
  4079. #ifndef NOSPL
  4080.         cmdlvl == 0
  4081. #else  /* NOSPL */
  4082.         tlevel < 0
  4083. #endif /* NOSPL */
  4084.         )
  4085.         OS2WaitForKey();
  4086.     ReleaseScreenMutex();
  4087.     os2settitle( title, FALSE );
  4088. #endif /* KUI */
  4089.     return(rc);
  4090.     }
  4091.     return(0);
  4092. #else /* OS2 */
  4093. #ifdef AMIGA
  4094.     if (!priv_chk()) system(s);
  4095. #else
  4096. #ifdef datageneral
  4097.     if (priv_chk) return(1);
  4098.     if (*s == '\0')            /* Interactive shell requested? */
  4099. #ifdef mvux
  4100.     system("/bin/sh ");
  4101. #else
  4102.         system("x :cli prefix Kermit_Baby:");
  4103. #endif /* mvux */
  4104.     else                /* Otherwise, */
  4105.         system(s);            /* Best for aos/vs?? */
  4106.  
  4107. #else
  4108. #ifdef aegis
  4109.     if ((pid = vfork()) == 0) {        /* Make child quickly */
  4110.     char *shpath, *shname, *shptr;    /* For finding desired shell */
  4111.  
  4112.     if (priv_can()) exit(1);    /* Turn off privs. */
  4113.         if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
  4114.  
  4115. #else                    /* All Unix systems */
  4116.     if ((pid = fork()) == 0) {        /* Make child */
  4117.     char *shpath, *shname, *shptr;    /* For finding desired shell */
  4118.     struct passwd *p;
  4119. #ifdef HPUX10                /* Default */
  4120.     char *defshell = "/usr/bin/sh";
  4121. #else
  4122. #ifdef Plan9
  4123.     char *defshell = "/bin/rc";
  4124. #else
  4125.     char *defshell = "/bin/sh";
  4126. #endif /* Plan9 */
  4127. #endif /* HPUX10 */
  4128.     if (priv_can()) exit(1);    /* Turn off privs. */
  4129. #ifdef COMMENT
  4130. /* Old way always used /etc/passwd shell */
  4131.     p = getpwuid(real_uid());    /* Get login data */
  4132.     if (p == (struct passwd *) NULL || !*(p->pw_shell))
  4133.       shpath = defshell;
  4134.     else
  4135.       shpath = p->pw_shell;
  4136. #else
  4137. /* New way lets user override with SHELL variable, but does not rely on it. */
  4138. /* This allows user to specify a different shell. */
  4139.     shpath = getenv("SHELL");    /* What shell? */
  4140.     if (shpath == NULL) {
  4141.         p = getpwuid( real_uid() );    /* Get login data */
  4142.         if (p == (struct passwd *)NULL || !*(p->pw_shell))
  4143.           shpath = defshell;
  4144.         else shpath = p->pw_shell;
  4145.         }
  4146. #endif /* COMMENT */
  4147. #endif /* aegis */
  4148.     shptr = shname = shpath;
  4149.     while (*shptr != '\0')
  4150.       if (*shptr++ == DIRSEP)
  4151.         shname = shptr;
  4152.     if (s == NULL || *s == '\0') {    /* Interactive shell requested? */
  4153.         execl(shpath,shname,"-i",NULL); /* Yes, do that */
  4154.     } else {            /* Otherwise, */
  4155.         execl(shpath,shname,"-c",s,NULL); /* exec the given command */
  4156.     }                /* If execl() failed, */
  4157.     exit(BAD_EXIT);            /* return bad return code. */
  4158.  
  4159.     } else {                /* Parent */
  4160.  
  4161.         int wstat;            /* ... must wait for child */
  4162.         int child;          /* Child's exit status */
  4163.     SIGTYP (*istat)(), (*qstat)();
  4164.  
  4165.     if (pid == (PID_T) -1) return(-1); /* fork() failed? */
  4166.  
  4167.     istat = signal(SIGINT,SIG_IGN);    /* Let the fork handle keyboard */
  4168.     qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
  4169.  
  4170. #ifdef UNIX
  4171. #define CK_CHILD            /* Assume this is safe in UNIX */
  4172. #endif /* UNIX */
  4173.  
  4174. #ifdef CK_CHILD
  4175.         while (((wstat = wait(&child)) != pid) && (wstat != -1))
  4176. #else
  4177.         while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
  4178. #endif /* CK_CHILD */
  4179.       ;                /* Wait for fork */
  4180.     signal(SIGINT,istat);        /* Restore interrupts */
  4181.     signal(SIGQUIT,qstat);
  4182. #ifdef CK_CHILD
  4183.     return(child == 0 ? 1 : 0);    /* Return child's status */
  4184. #endif /* CK_CHILD */
  4185.     }
  4186. #endif
  4187. #endif
  4188. #endif /* OS2 */
  4189.     return(1);
  4190. }
  4191.  
  4192. #ifdef aegis
  4193. /*
  4194.  Replacement for strchr() and index(), neither of which seem to be universal.
  4195. */
  4196. static char *
  4197. #ifdef CK_ANSIC
  4198. xindex(char * s, char c)
  4199. #else
  4200. xindex(s,c) char *s, c;
  4201. #endif /* CK_ANSIC */
  4202. /* xindex */ {
  4203.     while (*s != '\0' && *s != c) s++;
  4204.     if (*s == c) return(s); else return(NULL);
  4205. }
  4206. #endif /* aegis */
  4207.  
  4208. /*  I S W I L D  --  Check if filespec is "wild"  */
  4209.  
  4210. /*
  4211.   Returns 0 if it is a single file, 1 if it contains wildcard characters.
  4212.   Note: must match the algorithm used by match(), hence no [a-z], etc.
  4213. */
  4214. int
  4215. iswild(filespec) char *filespec; {
  4216.     char c; int x; char *p;
  4217.     if (wildxpand) {
  4218.     if ((x = zxpand(filespec)) > 1) return(1);
  4219.     if (x == 0) return(0);        /* File does not exist */
  4220.     p = malloc(MAXNAMLEN + 20);
  4221.     znext(p);
  4222. #ifdef OS2
  4223.     x = (
  4224. #ifdef NT
  4225.          _stricmp(filespec,p)
  4226. #else
  4227.          stricmp(filespec,p)
  4228. #endif /* NT */
  4229.          != 0);
  4230. #else
  4231.     x = (strcmp(filespec,p) != 0);
  4232. #endif /* OS2 */
  4233.     free(p);
  4234.     p = NULL;
  4235.     return(x);
  4236.     } else {
  4237.     while ((c = *filespec++) != '\0')
  4238.       if (c == '*' || c == '?') return(1);
  4239.     return(0);
  4240.     }
  4241. }
  4242.  
  4243. /*
  4244.    Tell if string pointer s is the name of an existing directory.
  4245.    Returns 1 if directory, 0 if not a directory.
  4246. */
  4247. int
  4248. isdir(s) char *s; {
  4249.     int x;
  4250. #ifdef NT
  4251.     struct _stat statbuf;
  4252. #else /* NT */
  4253.     struct stat statbuf;
  4254. #endif /* NT */
  4255.  
  4256.  
  4257.     if (!s) return(0);
  4258.     if (!*s) return(0);
  4259.  
  4260. #ifdef OS2
  4261.     /* Disk letter like A: is top-level directory on a disk */
  4262.     if (((int)strlen(s) == 2) && (isalpha(*s)) && (*(s+1) == ':'))
  4263.       return(1);
  4264. #endif /* OS2 */
  4265.     x = stat(s,&statbuf);
  4266.     debug(F111,"isdir stat",s,x);
  4267.     if (x == -1) {
  4268.     debug(F101,"isdir errno","",errno);
  4269.     return(0);
  4270.     } else {
  4271.     debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode);
  4272.     return( S_ISDIR (statbuf.st_mode) ? 1 : 0 );
  4273.     }
  4274. }
  4275.  
  4276. #ifdef CK_MKDIR
  4277. /* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */
  4278.  
  4279. /* Z M K D I R  --  Create directory(s) if necessary */
  4280. /*
  4281.    Call with:
  4282.     A pointer to a file specification that might contain directory
  4283.     information.  The filename is expected to be included.
  4284.     If the file specification does not include any directory separators,
  4285.     then it is assumed to be a plain file.
  4286.     If one or more directories are included in the file specification,
  4287.     this routine tries to create them if they don't already exist.
  4288.    Returns:
  4289.     0 on success, i.e. the directory was created
  4290.    -1 on failure to create the directory
  4291. */
  4292. int
  4293. zmkdir(path) char *path; {
  4294.     char *xp, *tp, c;
  4295.     int x;
  4296.  
  4297.     x = strlen(path);
  4298.     debug(F111,"zmkdir",path,x);
  4299.     if (x < 1 || x > MAXPATH)        /* Check length */
  4300.       return(-1);
  4301.     if (!(tp = malloc(x+1)))        /* Make a temporary copy */
  4302.       return(-1);
  4303.     strcpy(tp,path);
  4304. #ifdef DTILDE
  4305.     if (*tp == '~') {            /* Starts with tilde? */
  4306.     xp = tilde_expand(tp);        /* Attempt to expand tilde */
  4307.     if (*xp) {
  4308.         char *zp;
  4309.         debug(F110,"zmkdir tilde_expand",xp,0);
  4310.         if (!(zp = malloc(strlen(xp) + 1))) { /* Make a place for it */
  4311.         free(tp);
  4312.         tp = NULL;
  4313.         return(-1);
  4314.         }
  4315.         free(tp);            /* Free previous buffer */
  4316.         tp = zp;            /* Point to new one */
  4317.         strcpy(tp,xp);        /* Copy expanded name to new buffer */
  4318.     }
  4319.     debug(F110,"zmkdir tp after tilde_expansion",tp,0);
  4320.     }
  4321. #endif /* DTILDE */
  4322.     xp = tp;
  4323.     if (ISDIRSEP(*xp))            /* Don't create root directory! */
  4324.       xp++;
  4325.  
  4326.     /* Go thru filespec from left to right... */
  4327.  
  4328.     for (; *xp; xp++) {            /* Create parts that don't exist */
  4329.     if (!ISDIRSEP(*xp))        /* Find next directory separator */
  4330.       continue;
  4331.     c = *xp;            /* Got one. */
  4332.     *xp = NUL;            /* Make this the end of the string. */
  4333.     if (!isdir(tp)) {        /* This directory exists already? */
  4334.         debug(F110,"zmkdir making",tp,0);
  4335.         x =                /* No, try to create it */
  4336. #ifdef NOMKDIR
  4337.            -1            /* Systems without mkdir() */
  4338. #else
  4339. #ifdef OS2                /* OS/2 */
  4340.           _mkdir(tp)        /* The IBM way */
  4341. #else
  4342.            mkdir(tp,0777)        /* UNIX */
  4343. #endif /* OS2 */
  4344. #endif /* NOMKDIR */
  4345.          ;
  4346.         if (x < 0) {
  4347.         debug(F101,"zmkdir failed, errno","",errno);
  4348.         free(tp);        /* Free temporary buffer. */
  4349.         tp = NULL;
  4350.         return(-1);        /* Freturn failure code. */
  4351.         }
  4352.     }
  4353.     *xp = c;            /* Replace the separator. */
  4354.     }
  4355.     free(tp);                /* Free temporary buffer. */
  4356.     return(0);                /* Return success code. */
  4357. }
  4358. #endif /* CK_MKDIR */
  4359.  
  4360. /* Z F S E E K  --  Position input file pointer */
  4361. /*
  4362.    Call with:
  4363.     Long int, 0-based, indicating desired position.
  4364.    Returns:
  4365.     0 on success.
  4366.    -1 on failure.
  4367. */
  4368. #ifndef NORESEND
  4369. int
  4370. #ifdef CK_ANSIC
  4371. zfseek(long pos)
  4372. #else
  4373. zfseek(pos) long pos;
  4374. #endif /* CK_ANSIC */
  4375. /* zfseek */ {
  4376. #ifdef NT
  4377.     fpos_t fpos = pos ;
  4378. #endif /* NT */
  4379.   
  4380.     zincnt = -1 ;        /* must empty the input buffer */
  4381.  
  4382.     debug(F101,"zfseek","",pos);
  4383. #ifdef NT
  4384.     return(fsetpos(fp[ZIFILE], &fpos)?-1:0);
  4385. #else
  4386.     return(fseek(fp[ZIFILE], pos, 0)?-1:0);
  4387. #endif
  4388. }
  4389. #endif /* NORESEND */
  4390.  
  4391. struct zfnfp *
  4392. zfnqfp(fname, buflen, buf)  char * fname; int buflen; char * buf; {
  4393.     int x = 0, y = 0;
  4394.     char * xp;
  4395.     static struct zfnfp fnfp;
  4396.  
  4397.     if (!fname)
  4398.       return(NULL);
  4399.  
  4400.     /* initialize the data structure */
  4401.     fnfp.len = buflen;
  4402.     fnfp.fpath = buf;
  4403.     fnfp.fname = NULL;
  4404.  
  4405. #ifdef OS2
  4406. #ifdef NT
  4407.     if ( GetFullPathName( fname, buflen, fnfp.fpath, &fnfp.fname ) )
  4408.       return(&fnfp);
  4409.     else 
  4410. #else /* NT */
  4411.       if (!DosQueryPathInfo(fname,5 /* Full Path Info */, fnfp.fpath,buflen)) {
  4412.       x = strlen(fnfp.fpath);
  4413.       for (x = x + 1; x >= 0; x--)    /* Find where the filename starts */
  4414.             if (fnfp.fpath[x] == '/'
  4415.         || fnfp.fpath[x] == '\\'
  4416.         )            /* There is guaranteed to be one */
  4417.           fnfp.fname = fnfp.fpath + x; /* Got it, set pointer */
  4418.       return(&fnfp);        /* and return. */
  4419.       } else
  4420. #endif /* NT */
  4421. #else /* OS2 */
  4422.  
  4423. #ifdef DTILDE
  4424.     if (*fname == '~') {        /* Starts with tilde? */
  4425.         xp = tilde_expand(fname);    /* Attempt to expand tilde */
  4426.         if (*xp) 
  4427.           fname = xp;
  4428.     }
  4429. #endif /* DTILDE */
  4430.  
  4431.     if (*fname == '/'
  4432.         ) {                /* Pathname is absolute */
  4433.         strncpy(buf,fname,buflen);
  4434.         x = strlen(buf);
  4435.         y = 0;
  4436.     } else {            /* Pathname is relative */
  4437.         char * p;
  4438.         if (p = zgtdir()) {        /* So get current directory */
  4439.         strncpy(buf,p,buflen);
  4440.         x = strlen(buf);        
  4441.         buf[x++] = '/';
  4442.         buflen -= x;        /* How much room left in buffer */
  4443.         if ((y = (int)strlen(fname)) > buflen) /* If enough room... */
  4444.           return(NULL);
  4445.         strncpy(buf+x,fname,buflen); /* ... append the filename */
  4446.         } else {
  4447.         return(NULL);
  4448.         }
  4449.     }
  4450.  
  4451.     for (x = x + y - 1; x > -1; x--)    /* Find where the filename starts */
  4452.       if (buf[x] == '/'
  4453.       ) {                /* There is guaranteed to be one */
  4454.       fnfp.fname = buf + x;        /* Got it, set pointer */
  4455.       return(&fnfp);        /* and return. */
  4456.       }
  4457. #endif /* OS2 */
  4458.     return(NULL);
  4459. }
  4460.  
  4461. #ifdef OS2
  4462.  
  4463. /*  Z C H D S K  --  Change currently selected disk device */
  4464.  
  4465. /* Returns -1 if error, otherwise 0 */
  4466.  
  4467. zchdsk(c) int c; {
  4468.     int i = toupper(c) - 64;
  4469.     return( _chdrive(i));
  4470. }
  4471.  
  4472. #undef stat
  4473. #ifdef __IBMC__STAT
  4474. #define stat(p, s) _stat(p, s)
  4475. #endif /* __IBMC__STAT */
  4476.  
  4477. os2stat(char *path,
  4478. #ifdef NT
  4479.     struct _stat *st
  4480. #else
  4481.     struct stat *st
  4482. #endif /* NT */
  4483.     ) {
  4484.     char local[MAXPATH];
  4485.     int len;
  4486.  
  4487.     strcpy(local, path);
  4488.     len = strlen(local);
  4489.  
  4490.     if ( len == 2 && local[1] == ':' )
  4491.         local[2] = DIRSEP, local[3] = 0; /* if drive only, append / */
  4492.     else if ( len == 0 )
  4493.         local[0] = DIRSEP, local[1] = 0; /* if empty path, take / instead */
  4494.     else if ( len > 1 && ISDIRSEP(local[len - 1]) && local[len - 2] != ':' )
  4495.         local[len - 1] = 0; /* strip trailing / except after d: */
  4496.  
  4497. #ifdef NT
  4498.     return _stat(local, st);
  4499. #else /* NT */
  4500.     return stat(local, st);
  4501. #endif /* NT */
  4502. }
  4503.  
  4504. #ifdef CK_LABELED
  4505. /* O S 2 S E T L O N G N A M E -- Set .LONGNAME Extended Attribute */
  4506.  
  4507. /* Returns -1 if error, otherwise 0 */
  4508.  
  4509. int
  4510. os2setlongname( char * fn, char * ln ) {
  4511.    EAOP2         FileInfoBuf;
  4512.    ULONG         FileInfoSize;
  4513.    ULONG         PathInfoFlags;
  4514.    APIRET        rc;
  4515.    char          FEA2List[1024];
  4516.    FEA2 *        pfea2;
  4517.    WORD *        pEAdata;
  4518.  
  4519.    debug(F110,"os2setlongname: filename is",fn,0);
  4520.    debug(F110,"os2setlongname: longname is",ln,0);
  4521.  
  4522.    FileInfoSize = sizeof( EAOP2 );
  4523.    PathInfoFlags = DSPI_WRTTHRU; /* complete write operation before return */
  4524.  
  4525.    FileInfoBuf.fpGEA2List = 0;
  4526.    FileInfoBuf.fpFEA2List = (PFEA2LIST) &FEA2List;
  4527.    pfea2 = FileInfoBuf.fpFEA2List->list;
  4528.  
  4529.    pfea2->oNextEntryOffset = 0;
  4530.    pfea2->fEA = 0;
  4531.    pfea2->cbName = 9; /* length of ".LONGNAME" without \0 */
  4532.    pfea2->cbValue = strlen( ln ) + 2 * sizeof( WORD );
  4533.    strcpy( pfea2->szName, ".LONGNAME" );
  4534.  
  4535.    pEAdata = (WORD *) pfea2->szName + 10/sizeof(WORD);
  4536.    *pEAdata = EAT_ASCII;
  4537.    pEAdata++;
  4538.    *pEAdata = strlen( ln );
  4539.    pEAdata++;
  4540.    strcpy( (char *) pEAdata, ln );
  4541.    pEAdata += (strlen( ln )+1)/sizeof(WORD);
  4542.  
  4543.    FileInfoBuf.fpFEA2List->cbList = (char *) pEAdata -
  4544.                                     (char *) FileInfoBuf.fpFEA2List;
  4545.      
  4546.    rc = DosSetPathInfo( fn, 2, &FileInfoBuf, FileInfoSize, PathInfoFlags );
  4547.    debug(F101,"os2setlongname: rc=","",rc);
  4548.    if ( !rc )
  4549.       return 0;
  4550.    else
  4551.       return -1;
  4552. }
  4553.  
  4554. /* O S 2 G E T L O N G N A M E -- Get .LONGNAME Extended Attribute */
  4555.  
  4556. /* Returns -1 if error, otherwise 0 */
  4557.  
  4558. int
  4559. os2getlongname( char * fn, char ** ln ) {
  4560.    static char   * LongNameBuf = 0;
  4561.    EAOP2         FileInfoBuf;
  4562.    ULONG         FileInfoSize;
  4563.    ULONG         PathInfoFlags;
  4564.    APIRET        rc;
  4565.    char          FEA2List[1024];
  4566.    FEA2 *        pfea2;
  4567.    char          GEA2List[1024];
  4568.    GEA2 *        pgea2;
  4569.    WORD *        pEAdata;
  4570.    WORD          LongNameLength;
  4571.  
  4572.    *ln = 0;
  4573.    if ( !LongNameBuf )
  4574.       LongNameBuf = strdup( "Initialization of LongNameBuf" );
  4575.    debug(F110,"os2getlongname: filename is",fn,0);
  4576.  
  4577.    FileInfoSize = sizeof( EAOP2 );
  4578.    PathInfoFlags = DSPI_WRTTHRU; /* Complete write operation before return */
  4579.  
  4580.    FileInfoBuf.fpGEA2List = (PGEA2LIST) &GEA2List;
  4581.    FileInfoBuf.fpFEA2List = (PFEA2LIST) &FEA2List;
  4582.    pgea2 = FileInfoBuf.fpGEA2List->list;
  4583.    pfea2 = FileInfoBuf.fpFEA2List->list;
  4584.  
  4585.    pfea2->oNextEntryOffset = 0;
  4586.    pfea2->fEA = 0;
  4587.    pfea2->cbName = 9;            /* Length of ".LONGNAME" without \0 */
  4588.    pfea2->cbValue = MAXPATH;
  4589.    strcpy( pfea2->szName, ".LONGNAME" );
  4590.  
  4591.    FileInfoBuf.fpGEA2List->cbList = sizeof(GEA2LIST)
  4592.                                   + pgea2->cbName + 1;
  4593.    pgea2->oNextEntryOffset = 0;
  4594.    pgea2->cbName = pfea2->cbName;
  4595.    strcpy(pgea2->szName,pfea2->szName);
  4596.  
  4597.    FileInfoBuf.fpFEA2List->cbList = 1024;
  4598.  
  4599.    rc = DosQueryPathInfo(fn,FIL_QUERYEASFROMLIST,&FileInfoBuf,FileInfoSize );
  4600.    LongNameLength =
  4601.      *(WORD *)((char *)pfea2 + sizeof(FEA2) + pfea2->cbName + sizeof(WORD));
  4602.    debug(F101,"os2getlongname: rc=","",rc);
  4603.    debug(F101,"   cbValue:","",pfea2->cbValue);
  4604.    debug(F101,"   cbName:","",pfea2->cbName);
  4605.    debug(F101,"   EA Value Length:","",LongNameLength );
  4606.    debug(F110,"   EA Value:",(char *)pfea2 + sizeof(FEA2)
  4607.                              + pfea2->cbName + (2 * sizeof(WORD)),0 );
  4608.    if ( rc ) {
  4609.        return -1;
  4610.    } else if ( pfea2->cbValue ) {
  4611.        if (LongNameBuf) {
  4612.        free(LongNameBuf);
  4613.        LongNameBuf = NULL;
  4614.        }
  4615.        LongNameBuf = (char *) malloc( LongNameLength + 1 );
  4616.        if (LongNameBuf) {
  4617.        strncpy(LongNameBuf, (char *)pfea2 + sizeof(FEA2)
  4618.            + pfea2->cbName + (2 * sizeof(WORD)),
  4619.            LongNameLength
  4620.            );
  4621.        LongNameBuf[LongNameLength] = '\0';
  4622.        debug(F110,"os2getlongname: longname is",LongNameBuf,0);
  4623.        } else
  4624.          debug(F100,"os2getlongname: malloc failed","",0);
  4625.    } else {
  4626.        if ( LongNameBuf )
  4627.      free( LongNameBuf );
  4628.        LongNameBuf = strdup( "" );
  4629.        debug(F110,
  4630.          "os2getlongname: there is no longname attribute",
  4631.          LongNameBuf,
  4632.          0
  4633.          );
  4634.    }
  4635.    *ln = LongNameBuf;
  4636.    return 0;
  4637. }
  4638.  
  4639.  
  4640. _PROTOTYP( VOID GetMem, (PVOID *, ULONG) );
  4641.  
  4642. /* O S 2 G E T E A S - Get all OS/2 Extended Attributes */
  4643.  
  4644. /* Returns 0 on success, -1 on failure */
  4645.  
  4646. int
  4647. os2geteas( char * name ) {
  4648.     CHAR *pAllocc=NULL; /* Holds the FEA struct returned by DosEnumAttribute */
  4649.                         /*  used to create the GEA2LIST for DosQueryPathInfo */
  4650.  
  4651.     ULONG ulEntryNum = 1; /* count of current EA to read (1-relative)        */
  4652.     ULONG ulEnumCnt;      /* Number of EAs for Enum to return, always 1      */
  4653.  
  4654.     ULONG FEAListSize = sizeof(ULONG);/* starting size of buffer necessary to 
  4655.                                                         hold all FEA blocks */
  4656.     ULONG GEAListSize = MAXEACOUNT * sizeof(GEA2) + sizeof(ULONG);
  4657.  
  4658.     FEA2 *pFEA;           /* Used to read from Enum's return buffer          */
  4659.     GEA2 *pGEA, *pLastGEAIn; /* Used to write to pGEAList buffer             */
  4660.     GEA2LIST *pGEAList;/*Ptr used to set up buffer for DosQueryPathInfo call */
  4661.     EAOP2  eaopGet;       /* Used to call DosQueryPathInfo                   */
  4662.     APIRET rc;
  4663.     int offset;
  4664.  
  4665.                                 /* Allocate enough room for any GEA List */
  4666.     GetMem((PPVOID)&pAllocc, MAX_GEA);
  4667.     pFEA = (FEA2 *) pAllocc;               /* pFEA always uses pAlloc buffer */
  4668.  
  4669.     GetMem((PPVOID)&pGEAList, GEAListSize ); /* alloc buffer for GEA2 list */
  4670.     pGEAList->cbList = GEAListSize;
  4671.     pGEA = pGEAList->list;
  4672.     pLastGEAIn = 0;
  4673.  
  4674.     if ( !pAllocc || ! pGEAList ) {
  4675.     FreeMem( pAllocc );
  4676.     FreeMem( pGEAList );
  4677.     return -1;
  4678.     }
  4679.     if ( pFEAList ) {
  4680.     FreeMem( pFEAList );
  4681.     pFEAList = 0;
  4682.    }
  4683.    while(TRUE) {              /* Loop continues until there are no more EAs */
  4684.        ulEnumCnt = 1;                   /* Only want to get one EA at a time */
  4685.        if(DosEnumAttribute(Ref_ASCIIZ,            /* Read into pAlloc Buffer */
  4686.                name,                  /* Note that this does not */
  4687.                ulEntryNum,            /* get the aValue field,   */
  4688.                pAllocc,               /* so DosQueryPathInfo must*/
  4689.                MAX_GEA,               /* be called to get it.    */
  4690.                &ulEnumCnt,
  4691.                (LONG) GetInfoLevel1)) {
  4692.        FreeMem(pGEAList);        /* There was some sort of error */
  4693.        FreeMem(pAllocc);
  4694.        return (-1);
  4695.        }
  4696.        if(ulEnumCnt != 1)        /* All the EAs have been read */
  4697.          break;
  4698.  
  4699.        ulEntryNum++;
  4700.        FEAListSize += sizeof(FEA2LIST) + pFEA->cbName+1 +
  4701.                   pFEA->cbValue + 4;
  4702.  
  4703.        if (pLastGEAIn)
  4704.          pLastGEAIn->oNextEntryOffset = (BYTE *)pGEA - (BYTE *)pLastGEAIn;
  4705.        pLastGEAIn = pGEA;
  4706.  
  4707.        pGEA->oNextEntryOffset = 0L;
  4708.        pGEA->cbName = pFEA->cbName;
  4709.        strcpy(pGEA->szName, pFEA->szName);
  4710.       
  4711.        /* must align GEA2 blocks on double word boundaries */
  4712.        offset = sizeof(GEA2) + pGEA->cbName + 1;
  4713.        offset += ( offset % 4 ? (4 - offset % 4) : 0 );
  4714.        pGEA = (GEA2 *) ((BYTE *) pGEA + offset);
  4715.    }
  4716.    debug(F111,"os2geteas: EA count",name,ulEntryNum-1);
  4717.    GetMem( (PPVOID) &pFEAList, FEAListSize );
  4718.    pFEAList->cbList = FEAListSize;
  4719.  
  4720.    eaopGet.fpGEA2List = pGEAList;
  4721.    eaopGet.fpFEA2List = pFEAList;
  4722.  
  4723.    rc = DosQueryPathInfo(name,                   /* Get the complete EA info */
  4724.                    GetInfoLevel3,
  4725.                    (PVOID) &eaopGet,
  4726.                     sizeof(EAOP2));
  4727.  
  4728.    debug(F111,"os2geteas: DosQueryPathInfo",name,rc);
  4729.    FreeMem( pGEAList );
  4730.    FreeMem( pAllocc );
  4731.    return ( rc ? -1 : 0 );
  4732. }
  4733.  
  4734. /* O S 2 S E T E A S - Set all OS/2 Extended Attributes */
  4735.  
  4736. /* Returns 0 on success, -1 on failure                  */
  4737.  
  4738. int
  4739. os2seteas( char * name ) {
  4740.    EAOP2  eaopSet;       /* Used to call DosSetPathInfo */
  4741.    APIRET rc;
  4742.  
  4743.    if ( !pFEAList ) {
  4744.      debug(F100,"os2seteas: EA List is empty","",0);
  4745.      return 0;
  4746.    }
  4747.    eaopSet.fpGEA2List = 0;
  4748.    eaopSet.fpFEA2List = pFEAList;
  4749.  
  4750.    rc = DosSetPathInfo(name,        /* Set the EA info */
  4751.                     SetInfoLevel2,
  4752.                    (PVOID) &eaopSet,
  4753.                     sizeof(EAOP2),
  4754.                     DSPI_WRTTHRU);
  4755.    debug(F111,"os2seteas: DosSetPathInfo",name,rc);
  4756.  
  4757.    if ( !rc ) {
  4758.       FreeMem( pFEAList );
  4759.       pFEAList = 0;
  4760.    }
  4761.    return ( rc ? -1 : 0 );
  4762. }
  4763.  
  4764. /* O S 2 G E T A T T R - Get all OS/2 Normal Attributes */
  4765.  
  4766. /* Returns 0 on success, -1 on failure                  */
  4767.  
  4768. int 
  4769. os2getattr( char * name ) {
  4770.    FILESTATUS3 FileInfoBuf;
  4771.    APIRET rc;
  4772.  
  4773.    rc = DosQueryPathInfo(name,                   /* Get the complete EA info */
  4774.                    GetInfoLevel1,
  4775.                    (PVOID) &FileInfoBuf,
  4776.                     sizeof(FILESTATUS3));
  4777.  
  4778.    if ( !rc ) {
  4779.       os2attrs = FileInfoBuf.attrFile;
  4780.       return 0;
  4781.       }
  4782.    else {
  4783.       os2attrs = FILE_NORMAL;
  4784.       return -1;
  4785.       }
  4786. }
  4787.  
  4788. /* O S 2 S E T A T T R - Set all OS/2 Normal Attributes */
  4789.  
  4790. /* Returns 0 on success, -1 on failure                  */
  4791.  
  4792. int 
  4793. os2setattr( char * name ) {
  4794.    FILESTATUS3 FileInfoBuf;
  4795.    APIRET rc;
  4796.  
  4797.    rc = DosQueryPathInfo(name,                   /* Get the complete EA info */
  4798.                    GetInfoLevel1,
  4799.                    (PVOID) &FileInfoBuf,
  4800.                     sizeof(FILESTATUS3));
  4801.  
  4802.    if ( !rc ) {
  4803.       FileInfoBuf.attrFile = lf_opts & os2attrs;
  4804.       rc = DosSetPathInfo( name,
  4805.                    GetInfoLevel1,
  4806.                    (PVOID) &FileInfoBuf,
  4807.                    sizeof(FILESTATUS3),
  4808.                    0);
  4809.       if ( !rc )
  4810.          return 0;
  4811.       }
  4812.    return -1;
  4813. }
  4814.  
  4815. /****************************************************************\
  4816.  *                                                              *
  4817.  *  Name:    GetMem (ppv, cb)                                   *
  4818.  *                                                              *
  4819.  *  Purpose: This routine returns a pointer to a available*     *
  4820.  *           memory space.                                      *
  4821.  *                                                              *
  4822.  *  Usage  :                                                    *
  4823.  *  Method : Routine should be bullet proof as it does its own  *
  4824.  *           error checking. It assumes that hwnd points to the *
  4825.  *           correct window with the name listbox in it.        *
  4826.  *                                                              *
  4827.  *  Returns: The current EA as determined by querying the l-box *
  4828.  *           selector.                                          *
  4829.  *                                                              *
  4830. \****************************************************************/
  4831. VOID GetMem (PVOID *ppv, ULONG cb) {
  4832.     BOOL        f;
  4833.  
  4834.     f =(BOOL) DosAllocMem(ppv, cb, fPERM|PAG_COMMIT);
  4835.     if (f) {
  4836.         *ppv = NULL;
  4837.         return;
  4838.     }
  4839.     return;
  4840. }
  4841.  
  4842. extern CHAR os2version[50];
  4843. extern long vernum;
  4844.  
  4845. /* D O _ L A B E L _ S E N D - Generate Label Header from EA List     */
  4846.  
  4847. /* Return 0 on success, -1 on failure                                 */
  4848.  
  4849. int
  4850. do_label_send(char * name) {
  4851.     char scratch[100];
  4852.     long buffreespace = INBUFSIZE;
  4853.     long easleft = 0;
  4854.     long memtocpy = 0;
  4855.     static BYTE * p = 0;
  4856.  
  4857.     debug(F110,"do_label_send",name,0);
  4858.     if ( !pFEAList ) {
  4859.     debug(F101,"   no EA list","",pFEAList);
  4860.       return 0;
  4861.     }
  4862.  
  4863.     if ( !p ) {
  4864.        debug(F100,"do_label_send: generate header","",0);
  4865.        zinptr += sprintf(zinptr,"KERMIT LABELED FILE:02UO04VERS");
  4866.  
  4867.        sprintf(scratch,"%d",strlen(get_os2_vers()));
  4868.        zinptr += sprintf(zinptr,"%02d%d%s",
  4869.           strlen(scratch),
  4870.              strlen(get_os2_vers()), 
  4871.           get_os2_vers());
  4872.  
  4873.        sprintf(scratch,"%d",vernum);
  4874.        zinptr += sprintf(zinptr,"05KVERS02%02d%d", strlen(scratch), vernum);
  4875.  
  4876.        sprintf(scratch,"%d",strlen(name));
  4877.        zinptr += sprintf(zinptr,"08FILENAME%02d%d%s", strlen(scratch),
  4878.           strlen(name), name);
  4879.  
  4880.        zinptr += sprintf(zinptr,"04ATTR%02d",sizeof(ULONG));
  4881.        memcpy( zinptr, (BYTE *) &os2attrs, sizeof(ULONG) );
  4882.        zinptr += sizeof(ULONG);
  4883.  
  4884.        sprintf( scratch, "%d", pFEAList->cbList );
  4885.        zinptr += sprintf(zinptr,"09EABUFSIZE%02d%ld", strlen(scratch), 
  4886.                 pFEAList->cbList);
  4887.        p = (BYTE *) pFEAList;
  4888.        buffreespace -= (BYTE *) zinptr - (BYTE *) zinbuffer;
  4889.     }
  4890.  
  4891.     easleft = pFEAList->cbList - ( (BYTE *) p - (BYTE *) pFEAList );
  4892.     memtocpy = buffreespace > easleft ? easleft : buffreespace;
  4893.     memcpy( zinptr, p, memtocpy );
  4894.     zinptr = (BYTE *) zinptr + memtocpy;
  4895.     p = (BYTE *) p + memtocpy;
  4896.     buffreespace -= memtocpy;
  4897.  
  4898.     if ( buffreespace > 0 ) {
  4899.        p = 0;
  4900.        FreeMem( pFEAList );
  4901.        pFEAList = 0;
  4902.        debug(F100,"do_label_send: terminate header","",0);
  4903.     }
  4904.     zincnt = (zinptr - zinbuffer);        /* Size of this beast */
  4905.     return(0);
  4906. }
  4907.  
  4908. /* D O _ L A B E L _ R E C V - Receive label info and create EA List  */
  4909.  
  4910. /* Return 0 on success, -1 on failure */
  4911.  
  4912. int
  4913. do_label_recv() {
  4914.     char *recv_ptr = zoutbuffer;
  4915.     int lblen;
  4916.     char buffer[16];
  4917.     size_t memtocpy, lefttocpy;
  4918.     static BYTE * pFEA = 0;
  4919.  
  4920.     if ( !pFEAList 
  4921.          && strncmp(zoutbuffer,"KERMIT LABELED FILE:02UO04VERS",30) != 0) {
  4922.     debug(F100,"do_label_recv: not a labeled file","",0);
  4923.     return(0);            /* Just continue if unlabeled */
  4924.     }
  4925.  
  4926.     if ( !pFEAList ) {
  4927.        recv_ptr += 30;            /* start at front of buffer */
  4928.        zoutcnt  -= 30;
  4929.  
  4930.        /* get length of length of OS/2 version */
  4931.        memcpy(buffer, recv_ptr, 2);
  4932.        recv_ptr += 2;
  4933.        zoutcnt  -= 2;
  4934.        buffer[2] = '\0';
  4935.        lblen = atoi(buffer);
  4936.  
  4937.        /* get length of OS/2 version */
  4938.        memcpy(buffer, recv_ptr, lblen);
  4939.        recv_ptr += lblen;
  4940.        zoutcnt  -= lblen;
  4941.        buffer[lblen] = '\0';
  4942.        lblen = atoi(buffer);
  4943.  
  4944.        /* get os2 version */
  4945.        memcpy(buffer, recv_ptr, lblen);
  4946.        recv_ptr += lblen;
  4947.        zoutcnt  -= lblen;
  4948.        buffer[lblen] = '\0';
  4949.        debug(F111,"  file created under OS/2: ",buffer,lblen);
  4950.  
  4951.        /* check sync with Kermit Version */
  4952.        memcpy(buffer, recv_ptr, 7);
  4953.        recv_ptr += 7;
  4954.        zoutcnt  -= 7;
  4955.        if (strncmp(buffer, "05KVERS", 7) != 0) {
  4956.        debug(F111,"  lost sync at KVERS",recv_ptr-7,zoutcnt+7);
  4957.        return(-1);
  4958.        }
  4959.  
  4960.        /* get length of length of C-Kermit version */
  4961.        memcpy(buffer, recv_ptr, 2);
  4962.        recv_ptr += 2;
  4963.        zoutcnt  -= 2;
  4964.        buffer[2] = '\0';
  4965.        lblen = atoi(buffer);
  4966.  
  4967.        /* get length of C-Kermit version */
  4968.        memcpy(buffer, recv_ptr, lblen);
  4969.        recv_ptr += lblen;
  4970.        zoutcnt  -= lblen;
  4971.        buffer[lblen] = '\0';
  4972.        lblen = atoi(buffer);
  4973.  
  4974.        /* get C-Kermit version */
  4975.        memcpy(buffer, recv_ptr, lblen);
  4976.        recv_ptr += lblen;
  4977.        zoutcnt  -= lblen;
  4978.        buffer[lblen] = '\0';
  4979.        debug(F111,"  file created with OS/2 C-Kermit: ",buffer,lblen);
  4980.  
  4981.        /* check sync with FILENAME */
  4982.        memcpy(buffer, recv_ptr, 10);
  4983.        recv_ptr += 10;
  4984.        zoutcnt  -= 10;
  4985.        if (strncmp(buffer, "08FILENAME", 10) != 0) {
  4986.         debug(F111,"  lost sync at FILENAME",recv_ptr-10,zoutcnt+10);
  4987.         return(-1);
  4988.        }
  4989.  
  4990.        /* get length of length of Filename */
  4991.        memcpy(buffer, recv_ptr, 2);
  4992.        recv_ptr += 2;
  4993.        zoutcnt  -= 2;
  4994.        buffer[2] = '\0';
  4995.        lblen = atoi(buffer);
  4996.  
  4997.        /* get length of File Name */
  4998.        memcpy(buffer, recv_ptr, lblen);
  4999.        recv_ptr += lblen;
  5000.        zoutcnt  -= lblen;
  5001.        buffer[lblen] = '\0';
  5002.        lblen = atoi(buffer);
  5003.  
  5004.        /* get File Name */
  5005.        memcpy(buffer, recv_ptr, lblen);
  5006.        recv_ptr += lblen;
  5007.        zoutcnt  -= lblen;
  5008.        buffer[lblen] = '\0';
  5009.        debug(F111,"  file sent with name: ",buffer,lblen);
  5010.  
  5011.        /* check sync with ATTR */
  5012.        memcpy(buffer, recv_ptr, 6);
  5013.        recv_ptr += 6;
  5014.        zoutcnt  -= 6;
  5015.        if (strncmp(buffer, "04ATTR", 6) != 0) {
  5016.        debug(F111,"  lost sync at ATTR",recv_ptr-6,zoutcnt+6);
  5017.        return(-1);
  5018.        }
  5019.  
  5020.        /* get length of attributes - should be sizeof(ULONG) */
  5021.        memcpy(buffer, recv_ptr, 2);
  5022.        recv_ptr += 2;
  5023.        zoutcnt  -= 2;
  5024.        buffer[2] = '\0';
  5025.        lblen = atoi(buffer);
  5026.        if ( lblen != sizeof(ULONG) ) {
  5027.        debug(F101,"   Attributes have wrong length","",lblen);
  5028.        return(-1);
  5029.        }
  5030.  
  5031.        /* get attributes */
  5032.        memcpy(&os2attrs, recv_ptr, sizeof(ULONG));
  5033.        recv_ptr += sizeof(ULONG);
  5034.        zoutcnt  -= sizeof(ULONG);
  5035.  
  5036.        /* check sync with EABUFSIZE */
  5037.        memcpy(buffer, recv_ptr, 11);
  5038.        recv_ptr += 11;
  5039.        zoutcnt  -= 11;
  5040.        if (strncmp(buffer, "09EABUFSIZE", 11) != 0) {
  5041.        debug(F111,"  lost sync at EABUFSIZE",recv_ptr-11,zoutcnt+11);
  5042.        return(-1);
  5043.        }
  5044.  
  5045.        /* get length of length of EA Buffer Size */
  5046.        memcpy(buffer, recv_ptr, 2);
  5047.        recv_ptr += 2;
  5048.        zoutcnt  -= 2;
  5049.        buffer[2] = '\0';
  5050.        lblen = atoi(buffer);
  5051.  
  5052.        /* get length of EA Buffer Size */
  5053.        memcpy(buffer, recv_ptr, lblen);
  5054.        recv_ptr += lblen;
  5055.        zoutcnt  -= lblen;
  5056.        buffer[lblen] = '\0';
  5057.        lblen = atoi(buffer);
  5058.        debug(F101,"  EA Buffer Size:","",lblen);
  5059.  
  5060.        GetMem( (PPVOID) &pFEAList, (ULONG) lblen );
  5061.        if ( !pFEAList ) {
  5062.          debug(F101,"   pFEAList","",pFEAList);
  5063.          return -1;
  5064.        }
  5065.        pFEAList->cbList = lblen;
  5066.        pFEA = (BYTE *) pFEAList;
  5067.     }
  5068.  
  5069.     if ( pFEAList && pFEA ) {
  5070.        /* get EA Buffer */
  5071.        lefttocpy = pFEAList->cbList - ( (BYTE *) pFEA - (BYTE *) pFEAList );
  5072.        memtocpy = ( zoutcnt < lefttocpy ? zoutcnt : lefttocpy );
  5073.        memcpy(pFEA, recv_ptr, memtocpy);
  5074.        recv_ptr += memtocpy;
  5075.        zoutcnt  -= memtocpy;
  5076.        pFEA += memtocpy;
  5077.        debug(F101,"   memtocpy","",memtocpy);
  5078.        debug(F101,"   zoutcnt","",zoutcnt);
  5079.  
  5080.        if ( pFEA == ( (BYTE *) pFEAList + pFEAList->cbList ) ) {
  5081.           pFEA = 0;  /* we are done copying the EA's to the EA List */
  5082.           debug(F100,"   done copying EA's","",0);
  5083.        }
  5084.     }
  5085.  
  5086.     /* if we have processed some of the data in the output buffer */
  5087.     /* then move the data in the buffer so that it is properly    */
  5088.     /* aligned with the beginning of the buffer and reset the ptr */
  5089.     if ( recv_ptr != zoutbuffer ) {
  5090.         memmove(zoutbuffer, recv_ptr, zoutcnt);
  5091.     if ( pFEA ) {
  5092.         zoutptr = zoutbuffer + zoutcnt ;    
  5093.         return(1);                /* Go fill some more */
  5094.     }
  5095.     }
  5096.     return (0);
  5097. }
  5098. #endif /* CK_LABELED */
  5099.  
  5100. #endif /* OS2 */
  5101.