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

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