ckufio.c
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:211k
源码类别:

通讯/手机编程

开发平台:

Windows_Unix

  1. /* C K U F I O  --  Kermit file system support for UNIX, Aegis, and Plan 9 */
  2. #define CK_NONBLOCK                     /* See zoutdump() */
  3. #ifdef aegis
  4. char *ckzv = "Aegis File support, 7.0.156, 30 Dec 1999";
  5. #else
  6. #ifdef Plan9
  7. char *ckzv = "Plan 9 File support, 7.0.156, 30 Dec 1999";
  8. #else
  9. char *ckzv = "UNIX File support, 7.0.156, 30 Dec 1999";
  10. #endif /* Plan9 */
  11. #endif /* aegis */
  12. /*
  13.   Author: Frank da Cruz <fdc@columbia.edu>,
  14.   Columbia University Academic Information Systems, New York City,
  15.   and others noted in the comments below.  Note: CUCCA = Previous name of
  16.   Columbia University Academic Information Systems.
  17.   Copyright (C) 1985, 2000,
  18.     Trustees of Columbia University in the City of New York.
  19.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  20.     copyright text in the ckcmai.c module for disclaimer and permissions.
  21. */
  22. /*
  23.   NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
  24.   compatible with C preprocessors that support only #ifdef, #else, #endif,
  25.   #define, and #undef.  Please do not use #if, logical operators, or other
  26.   preprocessor features in any of the portable C-Kermit modules.  You can,
  27.   of course, use these constructions in platform-specific modules where you
  28.   know they are supported.
  29. */
  30. /* Include Files */
  31. #ifdef MINIX2
  32. #define _MINIX
  33. #endif /* MINIX2 */
  34. #include "ckcsym.h"
  35. #include "ckcdeb.h"
  36. #include "ckcasc.h"
  37. #ifndef NOCSETS
  38. #include "ckcxla.h"
  39. #endif /* NOCSETS */
  40. #ifdef OSF13
  41. #ifdef CK_ANSIC
  42. #ifdef _NO_PROTO
  43. #undef _NO_PROTO
  44. #endif /* _NO_PROTO */
  45. #endif /* CK_ANSIC */
  46. #endif /* OSF13 */
  47. #include <errno.h>
  48. #include <signal.h>
  49. #ifdef MINIX2
  50. #undef MINIX
  51. #undef CKSYSLOG
  52. #include <limits.h>
  53. #include <time.h>
  54. #define NOFILEH
  55. #endif /* MINIX2 */
  56. #ifdef MINIX
  57. #include <limits.h>
  58. #include <sys/types.h>
  59. #include <time.h>
  60. #else
  61. #ifdef POSIX
  62. #include <limits.h>
  63. #else
  64. #ifdef SVR3
  65. #include <limits.h>
  66. #endif /* SVR3 */
  67. #endif /* POSIX */
  68. #endif /* MINIX */
  69. /*
  70.   Directory Separator macros, to allow this module to work with both UNIX and
  71.   OS/2: Because of ambiguity with the command line editor escape  character,
  72.   the directory separator is currently left as / for OS/2 too, because the
  73.   OS/2 kernel also accepts / as directory separator.  But this is subject to
  74.   change in future versions to conform to the normal OS/2 style.
  75. */
  76. #define DIRSEP       '/'
  77. #define ISDIRSEP(c)  ((c)=='/')
  78. #ifdef SDIRENT
  79. #define DIRENT
  80. #endif /* SDIRENT */
  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. #include <sys/dir.h>
  98. #endif /* DIRENT */
  99. #endif /* RTU */
  100. #endif /* NDIR */
  101. #endif /* XNDIR */
  102. #ifdef UNIX                             /* Pointer arg to wait() allowed */
  103. #define CK_CHILD                        /* Assume this is safe in all UNIX */
  104. #endif /* UNIX */
  105. extern int binary, recursive, stathack;
  106. #ifdef CK_CTRLZ
  107. extern int eofmethod;
  108. #endif /* CK_CTRLZ */
  109. #include <pwd.h>                        /* Password file for shell name */
  110. #ifdef CK_SRP
  111. #include <t_pwd.h>                      /* SRP Password file */
  112. #endif /* CK_SRP */
  113. #ifdef HPUX10_TRUSTED
  114. #include <hpsecurity.h>
  115. #include <prot.h>
  116. #endif /* HPUX10_TRUSTED */
  117. #ifdef POSIX
  118. #define UTIMEH
  119. #else
  120. #ifdef HPUX9
  121. #define UTIMEH
  122. #endif /* HPUX9 */
  123. #endif /* POSIX */
  124. #ifdef SYSUTIMEH                        /* <sys/utime.h> if requested,  */
  125. #include <sys/utime.h>                  /* for extra fields required by */
  126. #else                                   /* 88Open spec. */
  127. #ifdef UTIMEH                           /* or <utime.h> if requested */
  128. #include <utime.h>                      /* (SVR4, POSIX) */
  129. #define SYSUTIMEH                       /* Use this for both cases. */
  130. #endif /* UTIMEH */
  131. #endif /* SYSUTIMEH */
  132. #ifndef NOTIMESTAMP
  133. #ifdef POSIX
  134. #ifndef AS400
  135. #define TIMESTAMP
  136. #endif /* AS400 */
  137. #endif /* POSIX */
  138. #ifdef BSD44                            /* BSD 4.4 */
  139. #ifndef TIMESTAMP
  140. #define TIMESTAMP                       /* Can do file dates */
  141. #endif /* TIMESTAMP */
  142. #include <sys/time.h>
  143. #include <sys/timeb.h>
  144. #else  /* Not BSD44 */
  145. #ifdef BSD4                             /* BSD 4.3 and below */
  146. #define TIMESTAMP                       /* Can do file dates */
  147. #include <time.h>                       /* Need this */
  148. #include <sys/timeb.h>                  /* Need this if really BSD */
  149. #else  /* Not BSD 4.3 and below */
  150. #ifdef SVORPOSIX                        /* System V or POSIX */
  151. #ifndef TIMESTAMP
  152. #define TIMESTAMP
  153. #endif /* TIMESTAMP */
  154. #include <time.h>
  155. /* void tzset(); (the "void" type upsets some compilers) */
  156. #ifndef IRIX60
  157. #ifndef ultrix
  158. #ifndef CONVEX9
  159. /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
  160. #ifndef Plan9
  161. extern long timezone;
  162. #endif /* Plan9 */
  163. #endif /* CONVEX9 */
  164. #endif /* ultrix */
  165. #endif /* IRIX60 */
  166. #endif /* SVORPOSIX */
  167. #endif /* BSD4 */
  168. #endif /* BSD44 */
  169. #ifdef COHERENT
  170. #include <time.h>
  171. #endif /* COHERENT */
  172. /* Is `y' a leap year? */
  173. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  174. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  175. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  176. #endif /* NOTIMESTAMP */
  177. #ifdef CIE
  178. #include <stat.h>                       /* File status */
  179. #else
  180. #include <sys/stat.h>
  181. #endif /* CIE */
  182. /* Macro to alleviate isdir() calls internal to this module */
  183. static struct stat STATBUF;
  184. #define xisdir(a) ((stat(a,&STATBUF)==-1)?0:(S_ISDIR(STATBUF.st_mode)?1:0))
  185. extern char uidbuf[];
  186. extern int xferlog;
  187. extern char * xferfile;
  188. static int iklogopen = 0;
  189. static time_t timenow;
  190. static char iksdmsg[CKMAXPATH+512];
  191. extern int local;
  192. extern int server, en_mkd, en_cwd;
  193. /*
  194.   Functions (n is one of the predefined file numbers from ckcker.h):
  195.    zopeni(n,name)   -- Opens an existing file for input.
  196.    zopeno(n,name,attr,fcb) -- Opens a new file for output.
  197.    zclose(n)        -- Closes a file.
  198.    zchin(n,&c)      -- Gets the next character from an input file.
  199.    zsinl(n,&s,x)    -- Read a line from file n, max len x, into address s.
  200.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  201.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  202.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  203.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  204.    zchki(name)      -- Check if named file exists and is readable, return size.
  205.    zchko(name)      -- Check if named file can be created.
  206.    zchkspa(name,n)  -- Check if n bytes available to create new file, name.
  207.    znewn(name,s)    -- Make a new unique file name based on the given name.
  208.    zdelet(name)     -- Delete the named file.
  209.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  210.    znext(string)    -- Returns the next file from the list in "string".
  211.    zxrewind()       -- Rewind zxpand list.
  212.    zxcmd(n,cmd)     -- Execute the command in a lower fork on file number n.
  213.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  214.    zrtol(n1,n2)     -- Convert remote filename into local form.
  215.    zltor(n1,n2)     -- Convert local filename into remote form.
  216.    zchdir(dirnam)   -- Change working directory.
  217.    zhome()          -- Return pointer to home directory name string.
  218.    zkself()         -- Kill self, log out own job.
  219.    zsattr(struct zattr *) -- Return attributes for file which is being sent.
  220.    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
  221.    zrename(old, new) -- Rename a file.
  222.    zcopy(source,destination) -- Copy a file.
  223.    zmkdir(path)       -- Create the directory path if possible
  224.    zfnqfp(fname,len,fullpath) - Determine full path for file name.
  225.    zgetfs(name)     -- return file size regardless of accessibility
  226.    zchkpid(pid)     -- tell if PID is valid and active
  227. */
  228. /* Kermit-specific includes */
  229. /*
  230.   Definitions here supersede those from system include files.
  231.   ckcdeb.h is included above.
  232. */
  233. #include "ckcker.h"                     /* Kermit definitions */
  234. #include "ckucmd.h"                     /* For keyword tables */
  235. #include "ckuver.h"                     /* Version herald */
  236. char *ckzsys = HERALD;
  237. /*
  238.   File access checking ...  There are two calls to access() in this module.
  239.   If this program is installed setuid or setgid on a Berkeley-based UNIX
  240.   system that does NOT incorporate the saved-original-effective-uid/gid
  241.   feature, then, when we have swapped the effective and original uid/gid,
  242.   access() fails because it uses what it thinks are the REAL ids, but we have
  243.   swapped them.  This occurs on systems where ANYBSD is defined, NOSETREU
  244.   is NOT defined, and SAVEDUID is NOT defined.  So, in theory, we should take
  245.   care of this situation like so:
  246.     ifdef ANYBSD
  247.     ifndef NOSETREU
  248.     ifndef SAVEDUID
  249.     define SW_ACC_ID
  250.     endif
  251.     endif
  252.     endif
  253.   But we can't test such a general scheme everywhere, so let's only do this
  254.   when we know we have to...
  255. */
  256. #ifdef NEXT                             /* NeXTSTEP 1.0-3.0 */
  257. #define SW_ACC_ID
  258. #endif /* NEXT */
  259. /* Support for tilde-expansion in file and directory names */
  260. #ifdef POSIX
  261. #define NAMEENV "LOGNAME"
  262. #endif /* POSIX */
  263. #ifdef BSD4
  264. #define NAMEENV "USER"
  265. #endif /* BSD4 */
  266. #ifdef ATTSV
  267. #define NAMEENV "LOGNAME"
  268. #endif /* ATTSV */
  269. /* Berkeley Unix Version 4.x */
  270. /* 4.1bsd support from Charles E Brooks, EDN-VAX */
  271. #ifdef BSD4
  272. #ifdef MAXNAMLEN
  273. #define BSD42
  274. #endif /* MAXNAMLEN */
  275. #endif /* BSD4 */
  276. /* Definitions of some system commands */
  277. char *DELCMD = "rm -f ";                /* For file deletion */
  278. char *CPYCMD = "cp ";                   /* For file copy */
  279. char *RENCMD = "mv ";                   /* For file rename */
  280. char *PWDCMD = "pwd ";                  /* For saying where I am */
  281. #ifdef COMMENT
  282. #ifdef HPUX10
  283. char *DIRCMD = "/usr/bin/ls -l ";       /* For directory listing */
  284. char *DIRCM2 = "/usr/bin/ls -l ";       /* For directory listing, no args */
  285. #else
  286. char *DIRCMD = "/bin/ls -l ";           /* For directory listing */
  287. char *DIRCM2 = "/bin/ls -l ";           /* For directory listing, no args */
  288. #endif /* HPUX10 */
  289. #else
  290. char *DIRCMD = "ls -l ";                /* For directory listing */
  291. char *DIRCM2 = "ls -l ";                /* For directory listing, no args */
  292. #endif /* COMMENT */
  293. char *TYPCMD = "cat ";                  /* For typing a file */
  294. #ifdef DGUX540
  295. char *MAILCMD = "mailx";                /* For sending mail */
  296. #else
  297. #ifdef UNIX
  298. char *MAILCMD = "Mail";
  299. #else
  300. char *MAILCMD = "";
  301. #endif /* UNIX */
  302. #endif /* DGUX40 */
  303. #ifdef UNIX
  304. #ifdef ANYBSD                           /* BSD uses lpr to spool */
  305. #ifdef DGUX540                          /* And DG/UX */
  306. char * PRINTCMD = "lp";
  307. #else
  308. char * PRINTCMD = "lpr";
  309. #endif /* DGUX540 */
  310. #else                                   /* Sys V uses lp */
  311. #ifdef TRS16                            /* except for Tandy-16/6000... */
  312. char * PRINTCMD = "lpr";
  313. #else
  314. char * PRINTCMD = "lp";
  315. #endif /* TRS16 */
  316. #endif /* ANYBSD */
  317. #else  /* Not UNIX */
  318. #define PRINTCMD ""
  319. #endif /* UNIX */
  320. #ifdef FT18                             /* Fortune For:Pro 1.8 */
  321. #undef BSD4
  322. #endif /* FT18 */
  323. #ifdef BSD4
  324. char *SPACMD = "pwd ; df .";            /* Space in current directory */
  325. #else
  326. #ifdef FT18
  327. char *SPACMD = "pwd ; du ; df .";
  328. #else
  329. char *SPACMD = "df ";
  330. #endif /* FT18 */
  331. #endif /* BSD4 */
  332. char *SPACM2 = "df ";                   /* For space in specified directory */
  333. #ifdef FT18
  334. #define BSD4
  335. #endif /* FT18 */
  336. #ifdef BSD4
  337. char *WHOCMD = "finger ";
  338. #else
  339. char *WHOCMD = "who ";
  340. #endif /* BSD4 */
  341. /* More system-dependent includes, which depend on symbols defined */
  342. /* in the Kermit-specific includes.  Oh what a tangled web we weave... */
  343. #ifdef COHERENT                         /* <sys/file.h> */
  344. #define NOFILEH
  345. #endif /* COHERENT */
  346. #ifdef MINIX
  347. #define NOFILEH
  348. #endif /* MINIX */
  349. #ifdef aegis
  350. #define NOFILEH
  351. #endif /* aegis */
  352. #ifdef unos
  353. #define NOFILEH
  354. #endif /* unos */
  355. #ifndef NOFILEH
  356. #include <sys/file.h>
  357. #endif /* NOFILEH */
  358. #ifndef is68k                           /* Whether to include <fcntl.h> */
  359. #ifndef BSD41                           /* All but a couple UNIXes have it. */
  360. #ifndef FT18
  361. #ifndef COHERENT
  362. #include <fcntl.h>
  363. #endif /* COHERENT */
  364. #endif /* FT18  */
  365. #endif /* BSD41 */
  366. #endif /* not is68k */
  367. #ifdef COHERENT
  368. #ifdef _I386
  369. #include <fcntl.h>
  370. #else
  371. #include <sys/fcntl.h>
  372. #endif /* _I386 */
  373. #endif /* COHERENT */
  374. #ifdef IKSD
  375. extern int isguest;
  376. extern int inserver;
  377. extern char * homdir, * anonroot;
  378. #endif /* IKSD */
  379. #ifdef CK_LOGIN
  380. #define GUESTPASS 256
  381. static char guestpass[GUESTPASS] = { NUL, NUL }; /* Anonymous "password" */
  382. static int logged_in = 0;               /* Set when user is logged in */
  383. int guest = 0;                          /* Anonymous user */
  384. static int askpasswd = 0;               /* Have OK user, must ask for passwd */
  385. #endif /* CK_LOGIN */
  386. _PROTOTYP( VOID ignorsigs, (void) );
  387. _PROTOTYP( VOID restorsigs, (void) );
  388. /*
  389.   Change argument to "(const char *)" if this causes trouble.
  390.   Or... if it causes trouble, then maybe it was already declared
  391.   in a header file after all, so you can remove this prototype.
  392. */
  393. #ifndef NDGPWNAM /* If not defined No Declare getpwnam... */
  394. #ifndef _POSIX_SOURCE
  395. #ifndef NEXT
  396. #ifndef SVR4
  397. /* POSIX <pwd.h> already gave prototypes for these. */
  398. #ifdef IRIX40
  399. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  400. #else
  401. #ifdef IRIX51
  402. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  403. #else
  404. #ifdef M_UNIX
  405. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  406. #else
  407. #ifdef HPUX9
  408. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  409. #else
  410. #ifdef HPUX10
  411. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  412. #else
  413. #ifdef DCGPWNAM
  414. _PROTOTYP( struct passwd * getpwnam, (const char *) );
  415. #else
  416. _PROTOTYP( struct passwd * getpwnam, (char *) );
  417. #endif /* DCGPWNAM */
  418. #endif /* HPUX10 */
  419. #endif /* HPUX9 */
  420. #endif /* M_UNIX */
  421. #endif /* IRIX51 */
  422. #endif /* IRIX40 */
  423. #ifndef SUNOS4
  424. #ifndef HPUX9
  425. #ifndef HPUX10
  426. #ifndef _SCO_DS
  427. _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
  428. #endif /* _SCO_DS */
  429. #endif /* HPUX10 */
  430. #endif /* HPUX9 */
  431. #endif /* SUNOS4 */
  432. _PROTOTYP( struct passwd * getpwent, (void) );
  433. #endif /* SVR4 */
  434. #endif /* NEXT */
  435. #endif /* _POSIX_SOURCE */
  436. #endif /* NDGPWNAM */
  437. #ifdef CK_SHADOW                        /* Shadow Passwords... */
  438. #include <shadow.h>
  439. #endif /* CK_SHADOW */
  440. #ifdef CK_PAM                           /* PAM... */
  441. #include <security/pam_appl.h>
  442. #ifndef PAM_SERVICE_TYPE                /* Defines which PAM service we are */
  443. #define PAM_SERVICE_TYPE "kermit"
  444. #endif /* PAM_SERVICE_TYPE */
  445. int
  446. #ifdef CK_ANSIC
  447. pam_cb(int num_msg,
  448.        const struct pam_message **msg,
  449.        struct pam_response **resp,
  450.        void *appdata_ptr
  451.        )
  452. #else /* CK_ANSIC */
  453. pam_cb(num_msg, msg, resp, appdata_ptr)
  454.     int num_msg;
  455.     const struct pam_message **msg;
  456.     struct pam_response **resp;
  457.     void *appdata_ptr;
  458. #endif /* CK_ANSIC */
  459. {
  460.     int i;
  461.     debug(F111,"pam_cb","num_msg",num_msg);
  462.     for (i = 0; i < num_msg; i++) {
  463.         char message[PAM_MAX_MSG_SIZE];
  464.         /* Issue prompt and get response */
  465.         debug(F111,"pam_cb","Message",i);
  466.         debug(F111,"pam_cb",msg[i]->msg,msg[i]->msg_style);
  467.         if (msg[i]->msg_style == PAM_ERROR_MSG) {
  468.             debug(F111,"pam_cb","PAM ERROR",0);
  469.             fprintf(stdout,"%sn", msg[i]->msg);
  470.             return(0);
  471.         } else if (msg[i]->msg_style == PAM_TEXT_INFO) {
  472.             debug(F111,"pam_cb","PAM TEXT INFO",0);
  473.             fprintf(stdout,"%sn", msg[i]->msg);
  474.             return(0);
  475.         } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) {
  476.             debug(F111,"pam_cb","Reading response, no echo",0);
  477.             readpass(msg[i]->msg,message,PAM_MAX_MSG_SIZE);
  478.         } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
  479.             debug(F111,"pam_cb","Reading response, with echo",0);
  480.             readtext(msg[i]->msg,message,PAM_MAX_MSG_SIZE);
  481.         } else {
  482.             debug(F111,"pam_cb","unknown style",0);
  483.             return(0);
  484.         }
  485.         /* Allocate space for this message's response structure */
  486.         resp[i] = (struct pam_response *) malloc(sizeof (struct pam_response));
  487.         if (!resp[i]) {
  488.             int j;
  489.             debug(F110,"pam_cb","malloc failure",0);
  490.             for (j = 0; j < i; j++) {
  491.                 free(resp[j]->resp);
  492.                 free(resp[j]);
  493.             }
  494.             return(0);
  495.         }
  496.         /* Allocate a buffer for the response */
  497.         resp[i]->resp = (char *) malloc((int)strlen(message) + 1);
  498.         if (!resp[i]->resp) {
  499.             int j;
  500.             debug(F110,"pam_cb","malloc failure",0);
  501.             for (j = 0; j < i; j++) {
  502.                 free(resp[j]->resp);
  503.                 free(resp[j]);
  504.             }
  505.             free(resp[i]);
  506.             return(0);
  507.         }
  508.         /* Return the results back to PAM */
  509.         strcpy(resp[i]->resp, message);
  510.         resp[i]->resp_retcode = 0;
  511.     }
  512.     debug(F110,"pam_cb","Exiting",0);
  513.     return(0);
  514. }
  515. #endif /* CK_PAM */
  516. /* Define macros for getting file type */
  517. #ifdef OXOS
  518. /*
  519.   Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
  520.   incorrectly, so we force their redefinition.
  521. */
  522. #undef S_ISREG
  523. #undef S_ISDIR
  524. #endif /* OXOS */
  525. #ifdef UTSV                             /* Same deal for Amdahl UTSV */
  526. #undef S_ISREG
  527. #undef S_ISDIR
  528. #endif /* UTSV */
  529. #ifdef UNISYS52                         /* And for UNISYS UTS V 5.2 */
  530. #undef S_ISREG
  531. #undef S_ISDIR
  532. #endif /* UNISYS52 */
  533. #ifdef ICLSVR3                          /* And for old ICL versions */
  534. #undef S_ISREG
  535. #undef S_ISDIR
  536. #endif /* ICLSVR3 */
  537. #ifdef ISDIRBUG                         /* Also allow this from command line */
  538. #ifdef S_ISREG
  539. #undef S_ISREG
  540. #endif /* S_ISREG */
  541. #ifdef S_ISDIR
  542. #undef S_ISDIR
  543. #endif /*  S_ISDIR */
  544. #endif /* ISDIRBUG */
  545. #ifndef _IFMT
  546. #ifdef S_IFMT
  547. #define _IFMT S_IFMT
  548. #else
  549. #define _IFMT 0170000
  550. #endif /* S_IFMT */
  551. #endif /* _IFMT */
  552. #ifndef S_ISREG
  553. #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  554. #endif /* S_ISREG */
  555. #ifndef S_ISDIR
  556. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  557. #endif /* S_ISDIR */
  558. /* The following mainly for NeXTSTEP... */
  559. #ifndef S_IWUSR
  560. #define S_IWUSR 0000200
  561. #endif /* S_IWUSR */
  562. #ifndef S_IRGRP
  563. #define S_IRGRP 0000040
  564. #endif /* S_IRGRP */
  565. #ifndef S_IWGRP
  566. #define S_IWGRP 0000020
  567. #endif /* S_IWGRP */
  568. #ifndef S_IXGRP
  569. #define S_IXGRP 0000010
  570. #endif /* S_IXGRP */
  571. #ifndef S_IROTH
  572. #define S_IROTH 0000004
  573. #endif /* S_IROTH */
  574. #ifndef S_IWOTH
  575. #define S_IWOTH 0000002
  576. #endif /* S_IWOTH */
  577. #ifndef S_IXOTH
  578. #define S_IXOTH 0000001
  579. #endif /* S_IXOTH */
  580. /*
  581.   Define maximum length for a file name if not already defined.
  582.   NOTE: This applies to a path segment (directory or file name),
  583.   not the entire path string, which can be CKMAXPATH bytes long.
  584. */
  585. #ifdef QNX
  586. #ifdef _MAX_FNAME
  587. #define MAXNAMLEN _MAX_FNAME
  588. #else
  589. #define MAXNAMLEN 48
  590. #endif /* _MAX_FNAME */
  591. #else
  592. #ifndef MAXNAMLEN
  593. #ifdef sun
  594. #define MAXNAMLEN 255
  595. #else
  596. #ifdef FILENAME_MAX
  597. #define MAXNAMLEN FILENAME_MAX
  598. #else
  599. #ifdef NAME_MAX
  600. #define MAXNAMLEN NAME_MAX
  601. #else
  602. #ifdef _POSIX_NAME_MAX
  603. #define MAXNAMLEN _POSIX_NAME_MAX
  604. #else
  605. #ifdef _D_NAME_MAX
  606. #define MAXNAMLEN _D_NAME_MAX
  607. #else
  608. #ifdef DIRSIZ
  609. #define MAXNAMLEN DIRSIZ
  610. #else
  611. #define MAXNAMLEN 14
  612. #endif /* DIRSIZ */
  613. #endif /* _D_NAME_MAX */
  614. #endif /* _POSIX_NAME_MAX */
  615. #endif /* NAME_MAX */
  616. #endif /* FILENAME_MAX */
  617. #endif /* sun */
  618. #endif /* MAXNAMLEN */
  619. #endif /* QNX */
  620. /* Longest pathname ... */
  621. /*
  622.   Beware: MAXPATHLEN is one of UNIX's dirty little secrets.  Where is it
  623.   defined?  Who knows...  <param.h>, <mod.h>, <unistd.h>, <limits.h>, ...
  624.   There is not necessarily even a definition for it anywhere, or it might have
  625.   another name.  If you get it wrong, bad things happen with getcwd() and/or
  626.   getwd().  If you allocate a buffer that is too short, getwd() might write
  627.   over memory and getcwd() will fail with ERANGE.  The definitions of these
  628.   functions (e.g. in SVID or POSIX.1) do not tell you how to determine the
  629.   maximum path length in order to allocate a buffer that is the right size.
  630. */
  631. #ifdef BSD44
  632. #include <sys/param.h>                  /* For MAXPATHLEN */
  633. #endif /* BSD44 */
  634. #ifdef COHERENT
  635. #include <sys/param.h>  /* for MAXPATHLEN, needed for -DDIRENT */
  636. #endif /* COHERENT */
  637. #ifdef MAXPATHLEN
  638. #ifdef MAXPATH
  639. #undef MAXPATH
  640. #endif /* MAXPATH */
  641. #define MAXPATH MAXPATHLEN
  642. #else
  643. #ifdef PATH_MAX
  644. #define MAXPATH PATH_MAX
  645. #else
  646. #ifdef _POSIX_PATH_MAX
  647. #define MAXPATH _POSIX_PATH_MAX
  648. #else
  649. #ifdef BSD42
  650. #define MAXPATH 1024
  651. #else
  652. #ifdef SVR4
  653. #define MAXPATH 1024
  654. #else
  655. #define MAXPATH 255
  656. #endif /* SVR4 */
  657. #endif /* BSD42 */
  658. #endif /* _POSIX_PATH_MAX */
  659. #endif /* PATH_MAX */
  660. #endif /* MAXPATHLEN */
  661. /* Maximum number of filenames for wildcard expansion */
  662. #ifndef MAXWLD                          /* (see ckcdeb.h) */
  663. #ifdef CK_SMALL
  664. #define MAXWLD 50
  665. #else
  666. #ifdef BIGBUFOK
  667. #define MAXWLD 102400
  668. #else
  669. #define MAXWLD 4096
  670. #endif /* BIGBUFOK */
  671. #endif /* CK_SMALL */
  672. #endif /* MAXWLD */
  673. #ifdef DCLFDOPEN
  674. /* fdopen() needs declaring because it's not declared in <stdio.h> */
  675. _PROTOTYP( FILE * fdopen, (int, char *) );
  676. #endif /* DCLFDOPEN */
  677. #ifdef DCLPOPEN
  678. /* popen() needs declaring because it's not declared in <stdio.h> */
  679. _PROTOTYP( FILE * popen, (char *, char *) );
  680. #endif /* DCLPOPEN */
  681. extern int nopush;
  682. /* More internal function prototypes */
  683. /*
  684.  * The path structure is used to represent the name to match.
  685.  * Each slash-separated segment of the name is kept in one
  686.  * such structure, and they are linked together, to make
  687.  * traversing the name easier.
  688.  */
  689. struct path {
  690.     char npart[MAXNAMLEN+4];            /* name part of path segment */
  691.     struct path *fwd;                   /* forward ptr */
  692. };
  693. #ifndef NOPUSH
  694. _PROTOTYP( int shxpand, (char *, char *[], int ) );
  695. #endif /* NOPUSH */
  696. _PROTOTYP( static int fgen, (char *, char *[], int ) );
  697. _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
  698. _PROTOTYP( static VOID addresult, (char *, int) );
  699. #ifdef COMMENT
  700. /* Replaced by ckmatch() */
  701. _PROTOTYP( static int match, (char *, char *) );
  702. #endif /* COMMENT */
  703. _PROTOTYP( char * whoami, (void) );
  704. _PROTOTYP( UID_T real_uid, (void) );
  705. _PROTOTYP( static struct path *splitpath, (char *p) );
  706. _PROTOTYP( char * zdtstr, (time_t) );
  707. _PROTOTYP( time_t zstrdt, (char *, int) );
  708. /* Some systems define these symbols in include files, others don't... */
  709. #ifndef R_OK
  710. #define R_OK 4                          /* For access */
  711. #endif /* R_OK */
  712. #ifndef W_OK
  713. #define W_OK 2
  714. #endif /* W_OK */
  715. #ifndef O_RDONLY
  716. #define O_RDONLY 000
  717. #endif /* O_RDONLY */
  718. /* syslog and wtmp items for Internet Kermit Service */
  719. extern char * clienthost;               /* From ckcmai.c. */
  720. static char fullname[CKMAXPATH+1];
  721. static char tmp2[CKMAXPATH+1];
  722. extern int ckxlogging;
  723. #ifdef CKXPRINTF                        /* Our printf macro conflicts with */
  724. #undef printf                           /* use of "printf" in syslog.h */
  725. #endif /* CKXPRINTF */
  726. #ifdef CKSYSLOG
  727. #include <syslog.h>
  728. #endif /* CKSYSLOG */
  729. #ifdef CKXPRINTF
  730. #define printf ckxprintf
  731. #endif /* CKXPRINTF */
  732. int ckxanon = 1;                        /* Anonymous login ok */
  733. int ckxperms = 0040;                    /* Anonymous file permissions */
  734. int ckxpriv = 1; /* Priv'd login ok */
  735. #ifndef XFERFILE
  736. #define XFERFILE "/var/log/iksd.log"
  737. #endif /* XFERFILE */
  738. /* wtmp logging for IKSD... */
  739. #ifndef CKWTMP                          /* wtmp logging not selected */
  740. int ckxwtmp = 0;                        /* Know this at runtime */
  741. #else                                   /* wtmp file details */
  742. int ckxwtmp = 1;
  743. #ifdef UTMPBUG                          /* Unfortunately... */
  744. /*
  745.   Some versions of Linux have a <utmp.h> file that contains
  746.   "enum utlogin { local, telnet, rlogin, screen, ... };"  This clobbers
  747.   any program that uses any of these words as variable names, function
  748.   names, macro names, etc.  (Other versions of Linux have this declaration
  749.   within #if 0 ... #endif.)  There is nothing we can do about this other
  750.   than to not include the stupid file.  But we need stuff from it, so...
  751. */
  752. #include <features.h>
  753. #include <sys/types.h>
  754. #define UT_LINESIZE     32
  755. #define UT_NAMESIZE     32
  756. #define UT_HOSTSIZE     256
  757. struct timeval {
  758.   time_t tv_sec;
  759.   time_t tv_usec;
  760. };
  761. struct exit_status {
  762.   short int e_termination;      /* Process termination status.  */
  763.   short int e_exit;             /* Process exit status.  */
  764. };
  765. struct utmp {
  766.   short int ut_type;                    /* Type of login */
  767.   pid_t ut_pid;                         /* Pid of login process */
  768.   char ut_line[UT_LINESIZE];            /* NUL-terminated devicename of tty */
  769.   char ut_id[4];                        /* Inittab id */
  770.   char ut_user[UT_NAMESIZE];            /* Username (not NUL terminated) */
  771.   char ut_host[UT_HOSTSIZE];            /* Hostname for remote login */
  772.   struct exit_status ut_exit;           /* Exit status */
  773.   long ut_session;                      /* Session ID, used for windowing */
  774.   struct timeval ut_tv;                 /* Time entry was made */
  775.   int32_t ut_addr_v6[4];                /* Internet address of remote host */
  776.   char pad[20];                         /* Reserved */
  777. };
  778. #define ut_time ut_tv.tv_sec    /* Why should Linux be like anything else? */
  779. #define ut_name ut_user         /* ... */
  780. extern void
  781. logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
  782.                           __const char *__ut_host));
  783. #else  /* Not UTMPBUG */
  784. #ifndef HAVEUTMPX                       /* Who has <utmpx.h> */
  785. #ifdef SOLARIS
  786. #define HAVEUTMPX
  787. #else
  788. #ifdef IRIX60
  789. #define HAVEUTMPX
  790. #else
  791. #ifdef CK_SCOV5
  792. #define HAVEUTMPX
  793. #else
  794. #ifdef HPUX100
  795. #define HAVEUTMPX
  796. #else
  797. #ifdef UNIXWARE
  798. #define HAVEUTMPX
  799. #endif /* UNIXWARE */
  800. #endif /* HPUX100 */
  801. #endif /* CK_SCOV5 */
  802. #endif /* IRIX60 */
  803. #endif /* SOLARIS */
  804. #endif /* HAVEUTMPX */
  805. #ifdef HAVEUTMPX
  806. #include <utmpx.h>
  807. #else
  808. #ifdef OSF50
  809. /* Because the time_t in the utmp struct is 64 bits but time() wants 32 */
  810. #define __V40_OBJ_COMPAT 1
  811. #endif /* OSF50 */
  812. #include <utmp.h>
  813. #ifdef OSF50
  814. #undef __V40_OBJ_COMPAT
  815. #endif /* OSF50 */
  816. #endif /* HAVEUTMPX */
  817. #endif /* UTMPBUG */
  818. #ifndef WTMPFILE
  819. #ifdef QNX
  820. #define WTMPFILE "/usr/adm/wtmp.1"
  821. #else
  822. #ifdef LINUX
  823. #define WTMPFILE "/var/log/wtmp"
  824. #else
  825. #define WTMPFILE "/usr/adm/wtmp"
  826. #endif /* QNX */
  827. #endif /* LINUX */
  828. #endif /* WTMPFILE */
  829. char * wtmpfile = NULL;
  830. static int wtmpfd = 0;
  831. static char cksysline[32] = { NUL, NUL };
  832. #ifndef HAVEUTHOST                      /* Does utmp include ut_host[]? */
  833. #ifdef HAVEUTMPX                        /* utmpx always does */
  834. #define HAVEUTHOST
  835. #else
  836. #ifdef LINUX                            /* Linux does */
  837. #define HAVEUTHOST
  838. #else
  839. #ifdef SUNOS4                           /* SunOS does */
  840. #define HAVEUTHOST
  841. #else
  842. #ifdef AIX41                            /* AIX 4.1 and later do */
  843. #define HAVEUTHOST
  844. #endif /* AIX41 */
  845. #endif /* SUNOS4 */
  846. #endif /* LINUX */
  847. #endif /* HAVEUTMPX */
  848. #endif /* HAVEUTHOST */
  849. #ifdef UW200
  850. PID_T _vfork() {                        /* To satisfy a library foulup */
  851.     return(fork());                     /* in Unixware 2.0.x */
  852. }
  853. #endif /* UW200 */
  854. VOID
  855. #ifdef CK_ANSIC
  856. logwtmp(const char * line, const char * name, const char * host)
  857. #else
  858. logwtmp(line, name, host) char *line, *name, *host;
  859. #endif /* CK_ANSIC */
  860. /* logwtmp */ {
  861. #ifdef HAVEUTMPX
  862.     struct utmpx ut;                    /* Needed for ut_host[] */
  863. #else
  864.     struct utmp ut;
  865. #endif /* HAVEUTMPX */
  866.     struct stat buf;
  867.     /* time_t time(); */
  868.     if (!ckxwtmp)
  869.       return;
  870.     if (!wtmpfile)
  871.       makestr(&wtmpfile,WTMPFILE);
  872.     if (!line) line = "";
  873.     if (!name) name = "";
  874.     if (!host) host = "";
  875.     if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) {
  876.         ckxwtmp = 0;
  877.         debug(F110,"WTMP open failed",line,0);
  878.         return;
  879.     }
  880.     if (!fstat(wtmpfd, &buf)) {
  881.         ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
  882.         ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
  883. #ifdef HAVEUTHOST
  884.         /* Not portable */
  885.         ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
  886. #endif /* HAVEUTHOST */
  887. #ifdef HAVEUTMPX
  888.         time(&ut.ut_tv.tv_sec);
  889. #else
  890. #ifdef LINUX
  891. /* In light of the following comment perhaps the previous line should */
  892. /* be "#ifndef COMMENT". */
  893.         {
  894.             /*
  895.              * On 64-bit platforms sizeof(time_t) and sizeof(ut.ut_time)
  896.              * are not the same and attempt to use an address of
  897.              * ut.ut_time as an argument to time() call may cause
  898.              * "unaligned access" trap.
  899.              */
  900.             time_t zz;
  901.             time(&zz);
  902.             ut.ut_time = zz;
  903.         }
  904. #else
  905.         time(&ut.ut_time);
  906. #endif /* LINUX */
  907. #endif /* HAVEUTMPX */
  908.         if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) !=
  909.             sizeof(struct utmp)) {
  910. #ifndef NOFTRUNCATE
  911. #ifndef COHERENT
  912.             ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */
  913. #else
  914.             chsize(wtmpfd, buf.st_size); /* Error, undo any partial write */
  915. #endif /* COHERENT */
  916. #endif /* NOFTRUNCATE */
  917.             debug(F110,"WTMP write error",line,0);
  918.         } else {
  919.             debug(F110,"WTMP record OK",line,0);
  920.             return;
  921.         }
  922.     }
  923. }
  924. #endif /* CKWTMP */
  925. #ifdef CKSYSLOG
  926. /*
  927.   C K S Y S L O G  --  C-Kermit system logging function,
  928.   For use by other modules.
  929.   This module can, but doesn't have to, use it.
  930.   Call with:
  931.     n = SYSLG_xx values defined in ckcdeb.h
  932.     s1, s2, s3: strings.
  933. */
  934. VOID
  935. cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; {
  936.     int level;
  937.     if (!ckxlogging)                    /* syslogging */
  938.       return;
  939.     if (!s1) s1 = "";                   /* Fix null args */
  940.     if (!s2) s2 = "";
  941.     if (!s3) s3 = "";
  942.     switch (n) {                        /* Translate Kermit level */
  943.       case SYSLG_DB:                    /* to syslog level */
  944.         level = LOG_DEBUG;
  945.         break;
  946.       default:
  947.         level = m ? LOG_INFO : LOG_ERR;
  948.     }
  949.     debug(F110,"cksyslog s1",s1,0);
  950.     debug(F110,"cksyslog s2",s2,0);
  951.     debug(F110,"cksyslog s3",s3,0);
  952.     errno = 0;
  953.     syslog(level, "%s: %s %s", s1, s2, s3); /* Write syslog record */
  954.     debug(F101,"cksyslog errno","",errno);
  955. }
  956. #endif /* CKSYSLOG */
  957. /* Declarations */
  958. int maxnam = MAXNAMLEN;                 /* Available to the outside */
  959. int maxpath = MAXPATH;
  960. int ck_znewn = -1;
  961. #ifdef UNIX
  962. char startupdir[MAXPATH+1];
  963. #endif /* UNIX */
  964. int pexitstat = -2;                     /* Process exit status */
  965. FILE *fp[ZNFILS] = {                    /* File pointers */
  966.    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  967. };
  968. /* Flags for each file indicating whether it was opened with popen() */
  969. int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  970. /* Buffers and pointers used in buffered file input and output. */
  971. #ifdef DYNAMIC
  972. extern char *zinbuffer, *zoutbuffer;
  973. #else
  974. extern char zinbuffer[], zoutbuffer[];
  975. #endif /* DYNAMIC */
  976. extern char *zinptr, *zoutptr;
  977. extern int zincnt, zoutcnt;
  978. extern int wildxpand;
  979. static long iflen = -1L;                /* Input file length */
  980. static PID_T pid = 0;                   /* pid of child fork */
  981. static int fcount = 0;                  /* Number of files in wild group */
  982. static int nxpand = 0;                  /* Copy of fcount */
  983. static char nambuf[CKMAXPATH+4];        /* Buffer for a pathname */
  984. #ifndef NOFRILLS
  985. static char zmbuf[200];                 /* For mail, remote print strings */
  986. #endif /* NOFRILLS */
  987. char **mtchs = NULL;                    /* Matches found for filename */
  988. char **mtchptr = NULL;                  /* Pointer to current match */
  989. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  990. /* Note, should get current pid, but if your system doesn't have */
  991. /* getppid(), then just kill(0,9)...  */
  992. #ifndef SVR3
  993. #ifndef POSIX
  994. #ifndef OSFPC
  995. /* Already declared in unistd.h for SVR3 and POSIX */
  996. #ifdef CK_ANSIC
  997. extern PID_T getppid(void);
  998. #else
  999. #ifndef PS2AIX10
  1000. #ifndef COHERENT
  1001. extern PID_T getppid();
  1002. #endif /* COHERENT */
  1003. #endif /* PS2AIX10 */
  1004. #endif /* CK_ANSIC */
  1005. #endif /* OSFPC */
  1006. #endif /* POSIX */
  1007. #endif /* SVR3 */
  1008. int
  1009. zkself() {                              /* For "bye", but no guarantee! */
  1010. #ifdef PROVX1
  1011.     return(kill(0,9));
  1012. #else
  1013. #ifdef V7
  1014.     return(kill(0,9));
  1015. #else
  1016. #ifdef TOWER1
  1017.     return(kill(0,9));
  1018. #else
  1019. #ifdef FT18
  1020.     return(kill(0,9));
  1021. #else
  1022. #ifdef aegis
  1023.     return(kill(0,9));
  1024. #else
  1025. #ifdef COHERENT
  1026.     return(kill((PID_T)getpid(),1));
  1027. #else
  1028. #ifdef PID_T
  1029.     exit(kill((PID_T)getppid(),1));
  1030.     return(0);
  1031. #else
  1032.     exit(kill(getppid(),1));
  1033.     return(0);
  1034. #endif
  1035. #endif
  1036. #endif
  1037. #endif
  1038. #endif
  1039. #endif
  1040. #endif
  1041. }
  1042. static VOID
  1043. getfullname(name) char * name; {
  1044.     char *p = (char *)fullname;
  1045.     int len = 0;
  1046.     fullname[0] = '';
  1047.     /* If necessary we could also chase down symlinks here... */
  1048. #ifdef COMMENT
  1049.     /* This works but is incompatible with wuftpd */
  1050.     if (isguest && anonroot) {
  1051.         ckstrncpy(fullname,anonroot,CKMAXPATH);
  1052.         len = strlen(fullname);
  1053.         if (len > 0)
  1054.           if (fullname[len-1] == '/')
  1055.             len--;
  1056.     }
  1057.     p += len;
  1058. #endif /* COMMENT */
  1059.     zfnqfp(name, CKMAXPATH - len, p);
  1060.     while (*p) {
  1061.         if (*p < '!') *p = '_';
  1062.         p++;
  1063.     }
  1064. }
  1065. /*  D O I K L O G  --  Open Kermit-specific ftp-like transfer log. */
  1066. static VOID
  1067. doiklog() {
  1068.     if (iklogopen)                      /* Already open? */
  1069.       return;
  1070.     if (xferlog) {                      /* Open iksd log if requested */
  1071.         if (!xferfile)                  /* If no pathname given */
  1072.           xferfile = XFERFILE;          /* use this default */
  1073.         if (*xferfile) {
  1074.             xferlog = open(xferfile, O_WRONLY | O_APPEND | O_CREAT, 0660);
  1075.             debug(F101,"doiklog open","",xferlog);
  1076.             if (xferlog < 0) {
  1077. #ifdef CKSYSLOG
  1078.                 syslog(LOG_ERR, "xferlog open failure %s: %m", xferfile);
  1079. #endif /* CKSYSLOG */
  1080.                 debug(F101,"doiklog open errno","",errno);
  1081.                 xferlog = 0;
  1082.             } else
  1083.               iklogopen = 1;
  1084.         } else
  1085.           xferlog = 0;
  1086. #ifdef CKSYSLOG
  1087.         if (xferlog && ckxlogging)
  1088.           syslog(LOG_INFO, "xferlog: %s open ok", xferfile);
  1089. #endif /* CKSYSLOG */
  1090.     }
  1091. }
  1092. /*  Z O P E N I  --  Open an existing file for input. */
  1093. /* Returns 1 on success, 0 on failure */
  1094. int
  1095. zopeni(n,name) int n; char *name; {
  1096.     int x, y;
  1097.     debug(F111,"zopeni name",name,n);
  1098.     /* debug(F101,"zopeni fp","", (unsigned) fp[n]); */
  1099.     if (chkfn(n) != 0) return(0);
  1100.     zincnt = 0;                         /* Reset input buffer */
  1101.     if (n == ZSYSFN) {                  /* Input from a system function? */
  1102. /*** Note, this function should not be called with ZSYSFN ***/
  1103. /*** Always call zxcmd() directly, and give it the real file number ***/
  1104. /*** you want to use.  ***/
  1105.         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
  1106.         *nambuf = '';                 /* No filename. */
  1107.         return(0);                      /* fail. */
  1108. #ifdef COMMENT
  1109.         return(zxcmd(n,name));          /* Try to fork the command */
  1110. #endif
  1111.     }
  1112.     if (n == ZSTDIO) {                  /* Standard input? */
  1113.         if (is_a_tty(0)) {
  1114.             fprintf(stderr,"Terminal input not allowed");
  1115.             debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  1116.             return(0);
  1117.         }
  1118.         fp[ZIFILE] = stdin;
  1119.         ispipe[ZIFILE] = 0;
  1120.         return(1);
  1121.     }
  1122.     fp[n] = fopen(name,"r");            /* Real file, open it. */
  1123.     debug(F111,"zopeni fopen", name, fp[n]);
  1124. #ifdef ZDEBUG
  1125.     printf("ZOPENI fp[%d]=%ldn",n,fp[n]);
  1126. #endif /* ZDEBUG */
  1127.     ispipe[n] = 0;
  1128.     if (xferlog
  1129. #ifdef CKSYSLOG
  1130.         || ckxsyslog >= SYSLG_FA && ckxlogging
  1131. #endif /* CKSYSLOG */
  1132.         ) {
  1133.         getfullname(name);
  1134.         debug(F110,"zopeni fullname",fullname,0);
  1135.     }
  1136.     if (fp[n] == NULL) {
  1137. #ifdef CKSYSLOG
  1138.         if (ckxsyslog >= SYSLG_FA && ckxlogging)
  1139.           syslog(LOG_INFO, "file[%d] %s: open failed (%m)", n, fullname);
  1140.         perror(fullname);
  1141. #else
  1142.         perror(name);
  1143. #endif /* CKSYSLOG */
  1144.         return(0);
  1145.     } else {
  1146. #ifdef CKSYSLOG
  1147.         if (ckxsyslog >= SYSLG_FA && ckxlogging)
  1148.           syslog(LOG_INFO, "file[%d] %s: open read ok", n, fullname);
  1149. #endif /* CKSYSLOG */
  1150.         clearerr(fp[n]);
  1151.         return(1);
  1152.     }
  1153. }
  1154. #ifdef QNX
  1155. #define DONDELAY
  1156. #else
  1157. #ifdef O_NDELAY
  1158. #define DONDELAY
  1159. #endif /* O_NDELAY */
  1160. #endif /* QNX */
  1161. /*  Z O P E N O  --  Open a new file for output.  */
  1162. int
  1163. zopeno(n,name,zz,fcb)
  1164. /* zopeno */  int n; char *name; struct zattr *zz; struct filinfo *fcb; {
  1165.     char p[8];
  1166.     int append = 0;
  1167. /* As of Version 5A, the attribute structure and the file information */
  1168. /* structure are included in the arglist. */
  1169. #ifdef DEBUG
  1170.     debug(F111,"zopeno",name,n);
  1171.     if (fcb) {
  1172.         debug(F101,"zopeno fcb disp","",fcb->dsp);
  1173.         debug(F101,"zopeno fcb type","",fcb->typ);
  1174.         debug(F101,"zopeno fcb char","",fcb->cs);
  1175.     } else {
  1176.         debug(F100,"zopeno fcb is NULL","",0);
  1177.     }
  1178. #endif /* DEBUG */
  1179.     if (chkfn(n) != 0)                  /* Already open? */
  1180.       return(0);                        /* Nothing to do. */
  1181.     if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
  1182.         fp[ZOFILE] = stdout;
  1183.         ispipe[ZOFILE] = 0;
  1184. #ifdef COMMENT
  1185. /* This seems right but it breaks client server ops */
  1186. fp[n] = stdout;
  1187.         ispipe[n] = 0;
  1188. #endif /* COMMENT */
  1189. #ifdef DEBUG
  1190.         if (n != ZDFILE)
  1191.           debug(F101,"zopeno fp[n]=stdout","",fp[n]);
  1192. #endif /* DEBUG */
  1193.         zoutcnt = 0;
  1194.         zoutptr = zoutbuffer;
  1195.         return(1);
  1196.     }
  1197. /* A real file.  Open it in desired mode (create or append). */
  1198.     strcpy(p,"w");                      /* Assume write/create mode */
  1199.     if (fcb) {                          /* If called with an FCB... */
  1200.         if (fcb->dsp == XYFZ_A) {       /* Does it say Append? */
  1201.             strcpy(p,"a");              /* Yes. */
  1202.             debug(F100,"zopeno append","",0);
  1203.             append = 1;
  1204.         }
  1205.     }
  1206.     if (xferlog
  1207. #ifdef CKSYSLOG
  1208.         || ckxsyslog >= SYSLG_FC && ckxlogging
  1209. #endif /* CKSYSLOG */
  1210.         ) {
  1211.         getfullname(name);
  1212.         debug(F110,"zopeno fullname",fullname,0);
  1213.     }
  1214.     debug(F110,"zopeno fopen arg",p,0);
  1215.     fp[n] = fopen(name,p);              /* Try to open the file */
  1216.     ispipe[ZIFILE] = 0;
  1217. #ifdef ZDEBUG
  1218.     printf("ZOPENO fp[%d]=%ldn",n,fp[n]);
  1219. #endif /* ZDEBUG */
  1220.     if (fp[n] == NULL) {                /* Failed */
  1221.         debug(F101,"zopeno failed errno","",errno);
  1222. #ifdef CKSYSLOG
  1223.         if (ckxsyslog >= SYSLG_FC && ckxlogging)
  1224.           syslog(LOG_INFO, "file[%d] %s: %s failed (%m)",
  1225.                  n,
  1226.                  fullname,
  1227.                  append ? "append" : "create"
  1228.                  );
  1229. #endif /* CKSYSLOG */
  1230. #ifdef COMMENT                          /* Let upper levels print message. */
  1231.         perror("Can't open output file");
  1232. #endif /* COMMENT */
  1233.     } else {                            /* Succeeded */
  1234.         extern int zofbuffer, zofblock, zobufsize;
  1235.         debug(F101, "zopeno zobufsize", "", zobufsize);
  1236.         if (n == ZDFILE || n == ZTFILE) { /* If debug or transaction log */
  1237.             setbuf(fp[n],NULL);           /* make it unbuffered. */
  1238. #ifdef DONDELAY
  1239.         } else if (n == ZOFILE && !zofblock) { /* blocking or nonblocking */
  1240.             int flags;
  1241.             if ((flags = fcntl(fileno(fp[n]),F_GETFL,0)) > -1)
  1242.               fcntl(fileno(fp[n]),F_SETFL, flags |
  1243. #ifdef QNX
  1244.                     O_NONBLOCK
  1245. #else
  1246.                     O_NDELAY
  1247. #endif /* QNX */
  1248.                     );
  1249.             debug(F100,"zopeno ZOFILE nonblocking","",0);
  1250. #endif /* DONDELAY */
  1251.         } else if (n == ZOFILE && !zofbuffer) { /* buffered or unbuffered */
  1252.             setbuf(fp[n],NULL);
  1253.             debug(F100,"zopeno ZOFILE unbuffered","",0);
  1254.         }
  1255. #ifdef CK_LOGIN
  1256.         /* Enforce anonymous file-creation permission */
  1257.         if (isguest)
  1258.           if (n == ZWFILE || n == ZMFILE ||
  1259.               n == ZOFILE || n == ZDFILE ||
  1260.               n == ZTFILE || n == ZPFILE ||
  1261.               n == ZSFILE)
  1262.             chmod(name,ckxperms);
  1263. #endif /* CK_LOGIN */
  1264. #ifdef CKSYSLOG
  1265.         if (ckxsyslog >= SYSLG_FC && ckxlogging)
  1266.           syslog(LOG_INFO, "file[%d] %s: %s ok",
  1267.                  n,
  1268.                  fullname,
  1269.                  append ? "append" : "create"
  1270.                  );
  1271. #endif /* CKSYSLOG */
  1272.         debug(F100, "zopeno ok", "", 0);
  1273.     }
  1274.     zoutcnt = 0;                        /* (PWP) reset output buffer */
  1275.     zoutptr = zoutbuffer;
  1276.     return((fp[n] != NULL) ? 1 : 0);
  1277. }
  1278. /*  Z C L O S E  --  Close the given file.  */
  1279. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  1280. int
  1281. zclose(n) int n; {
  1282.     int x = 0, x2 = 0;
  1283.     extern long ffc;
  1284.     debug(F101,"zclose","",n);
  1285.     if (chkfn(n) < 1) return(0);        /* Check range of n */
  1286.     if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
  1287.       x2 = zoutdump();
  1288.     if (fp[ZSYSFN] || ispipe[n]) {      /* If file is really pipe */
  1289. #ifndef NOPUSH
  1290.         x = zclosf(n);                  /* do it specially */
  1291. #else
  1292.         x = EOF;
  1293. #endif /* NOPUSH */
  1294.         debug(F101,"zclose zclosf","",x);
  1295.         debug(F101,"zclose zclosf fp[n]","",fp[n]);
  1296.     } else {
  1297.         if ((fp[n] != stdout) && (fp[n] != stdin))
  1298.           x = fclose(fp[n]);
  1299.         fp[n] = NULL;
  1300. #ifdef COMMENT
  1301. if (n == ZCTERM || n == ZSTDIO) /* See zopeno() */
  1302.   if (fp[ZOFILE] == stdout)
  1303.     fp[ZOFILE] = NULL;
  1304. #endif /* COMMENT */
  1305.     }
  1306.     iflen = -1L;                        /* Invalidate file length */
  1307.     if (x == EOF) {                     /* if we got a close error */
  1308.         debug(F101,"zclose fclose fails","",x);
  1309.         return(-1);
  1310.     } else if (x2 < 0) {                /* or error flushing last buffer */
  1311.         debug(F101,"zclose error flushing last buffer","",x2);
  1312.         return(-1);                     /* then return an error */
  1313.     } else {
  1314.         /* Print log record compatible with wu-ftpd */
  1315.         if (xferlog && (n == ZIFILE || n == ZOFILE)) {
  1316.             char * s, *p;
  1317.             extern char ttname[];
  1318.             if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */
  1319.             debug(F101,"zclose iklogopen","",iklogopen);
  1320.             if (iklogopen) {
  1321.                 timenow = time(NULL);
  1322. #ifdef CK_LOGIN
  1323.                 if (logged_in)
  1324.                   s = clienthost;
  1325.                 else
  1326. #endif /* CK_LOGIN */
  1327.                   s = (char *)ttname;
  1328.                 if (!s) s = "";
  1329.                 if (!*s) s = "*";
  1330. #ifdef CK_LOGIN
  1331.                 if (logged_in) {
  1332.                     p = guestpass;
  1333.                     if (!*p) p = "*";
  1334.                 } else
  1335. #endif /* CK_LOGIN */
  1336.                   p = whoami();
  1337.                 sprintf(iksdmsg,
  1338.                         "%.24s %d %s %ld %s %c %s %c %c %s %s %d %sn",
  1339.                         ctime(&timenow),        /* date/time */
  1340.                         gtimer(),               /* elapsed secs */
  1341.                         s,                      /* peer name */
  1342.                         ffc,                    /* byte count */
  1343.                         fullname,               /* full pathname of file */
  1344.                         (binary ? 'b' : 'a'),   /* binary or ascii */
  1345.                         "_",                    /* options = none */
  1346.                         n == ZIFILE ? 'o' : 'i', /* in/out */
  1347. #ifdef CK_LOGIN
  1348.                         (isguest ? 'a' : 'r'),  /* User type */
  1349. #else
  1350.                         'r',
  1351. #endif /* CK_LOGIN */
  1352.                         p,                      /* Username or guest passwd */
  1353. #ifdef CK_LOGIN
  1354.                         logged_in ? "iks" : "kermit", /* Record ID */
  1355. #else
  1356.                         "kermit",
  1357. #endif /* CK_LOGIN */
  1358.                         0,              /* User ID on client system unknown */
  1359.                         "*"             /* Ditto */
  1360.                         );
  1361.                 debug(F110,"zclose iksdmsg",iksdmsg,0);
  1362.                 write(xferlog, iksdmsg, (int)strlen(iksdmsg));
  1363.             }
  1364.         }
  1365.         debug(F101,"zclose returns","",1);
  1366.         return(1);
  1367.     }
  1368. }
  1369. /*  Z C H I N  --  Get a character from the input file.  */
  1370. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  1371. int
  1372. zchin(n,c) int n; int *c; {
  1373.     int a, x;
  1374. #ifdef IKSD
  1375.     /* I'm not sure how this would ever happen but... */
  1376.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1377.         *c = coninc(0);
  1378.         if (*c < 0)
  1379.           return(-1);
  1380.         return(0);
  1381.     }
  1382. #endif /* IKSD */
  1383.     /* (PWP) Just in case this gets called when it shouldn't. */
  1384.     if (n == ZIFILE) {
  1385.         x = zminchar();
  1386.         *c = x;
  1387.         return(x);
  1388.     }
  1389.     /* if (chkfn(n) < 1) return(-1); */
  1390.     a = getc(fp[n]);
  1391.     if (a == EOF) return(-1);
  1392. #ifdef CK_CTRLZ
  1393.     /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
  1394.     if (!binary && a == 0x1A && eofmethod == XYEOF_Z)
  1395.       return(-1);
  1396. #endif /* CK_CTRLZ */
  1397.     *c = (CHAR) a & 0377;
  1398.     return(0);
  1399. }
  1400. /*  Z S I N L  --  Read a line from a file  */
  1401. /*
  1402.   Writes the line into the address provided by the caller.
  1403.   n is the Kermit "channel number".
  1404.   Writing terminates when newline is encountered, newline is not copied.
  1405.   Writing also terminates upon EOF or if length x is exhausted.
  1406.   Returns 0 on success, -1 on EOF or error.
  1407. */
  1408. int
  1409. zsinl(n,s,x) int n, x; char *s; {
  1410.     int a, z = 0;                       /* z is return code. */
  1411.     int count = 0;
  1412.     int len = 0;
  1413.     char *buf;
  1414.     extern CHAR feol;                   /* Line terminator */
  1415.     if (!s || chkfn(n) < 1)             /* Make sure file is open, etc */
  1416.       return(-1);
  1417.     buf = s;
  1418.     s[0] = '';                        /* Don't return junk */
  1419.     a = -1;                             /* Current character, none yet. */
  1420.     while (x--) {                       /* Up to given length */
  1421.         int old = 0;
  1422.         if (feol)                       /* Previous character */
  1423.           old = a;
  1424.         if (zchin(n,&a) < 0) {          /* Read a character from the file */
  1425.             debug(F101,"zsinl zchin fail","",count);
  1426.             if (count == 0)
  1427.               z = -1;                   /* EOF or other error */
  1428.             break;
  1429.         } else
  1430.           count++;
  1431.         if (feol) {                     /* Single-character line terminator */
  1432.             if (a == feol)
  1433.               break;
  1434.         } else {                        /* CRLF line terminator */
  1435.             if (a == '15')            /* CR, get next character */
  1436.               continue;
  1437.             if (old == '15') {        /* Previous character was CR */
  1438.                 if (a == '12') {      /* This one is LF, so we have a line */
  1439.                     break;
  1440.                 } else {                /* Not LF, deposit CR */
  1441.                     *s++ = '15';
  1442.                     x--;
  1443.                     len++;
  1444.                 }
  1445.             }
  1446.         }
  1447.         *s = a;                         /* Deposit character */
  1448.         s++;
  1449.         len++;
  1450.     }
  1451.     *s = '';                          /* Terminate the string */
  1452.     debug(F111,"zsinl",buf,len);
  1453.     return(z);
  1454. }
  1455. /*  Z X I N  --  Read x bytes from a file  */
  1456. /*
  1457.   Reads x bytes (or less) from channel n and writes them
  1458.   to the address provided by the caller.
  1459.   Returns number of bytes read on success, 0 on EOF or error.
  1460. */
  1461. int
  1462. zxin(n,s,x) int n, x; char *s; {
  1463. #ifdef IKSD
  1464.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1465.         int a, i;
  1466.         a = ttchk();
  1467.         if (a < 1) return(0);
  1468.         for (i = 0; i < a && i < x; i++)
  1469.           s[i] = coninc(0);
  1470.         return(i);
  1471.     }
  1472. #endif /* IKSD */
  1473.     return(fread(s, sizeof (char), x, fp[n]));
  1474. }
  1475. /*
  1476.   Z I N F I L L  --  Buffered file input.
  1477.   (re)fill the file input buffer with data.  All file input
  1478.   should go through this routine, usually by calling the zminchar()
  1479.   macro defined in ckcker.h.  Returns:
  1480.   Value 0..255 on success, the character that was read.
  1481.   -1 on end of file.
  1482.   -2 on any kind of error other than end of file.
  1483.   -3 timeout when reading from pipe (Kermit packet mode only).
  1484. */
  1485. int
  1486. zinfill() {
  1487.     int x;
  1488.     extern int kactive, srvping;
  1489.     errno = 0;
  1490. #ifdef ZDEBUG
  1491.     printf("ZINFILL fp[%d]=%ldn",ZIFILE,fp[ZIFILE]);
  1492. #endif /* ZDEBUG */
  1493. #ifdef IKSD
  1494.     if (inserver && !local && fp[ZIFILE] == stdin) {
  1495.         int a, i;
  1496.         a = ttchk();
  1497.         if (a < 0) return(-2);
  1498.         for (i = 0; i < a && i < INBUFSIZE; i++) {
  1499.             zinbuffer[i] = coninc(0);
  1500.         }
  1501.         zincnt = i;
  1502.         /* set pointer to beginning, (== &zinbuffer[0]) */
  1503.         zinptr = zinbuffer;
  1504.         if (zincnt == 0) return(-1);
  1505.         zincnt--;                       /* One less char in buffer */
  1506.         return((int)(*zinptr++) & 0377); /* because we return the first */
  1507.     }
  1508. #endif /* IKSD */
  1509.     debug(F101,"zinfill kactive","",kactive);
  1510.     if (!(kactive && ispipe[ZIFILE])) {
  1511.         if (feof(fp[ZIFILE])) {
  1512.             debug(F100,"ZINFILL feof","",0);
  1513. #ifdef ZDEBUG
  1514.             printf("ZINFILL EOFn");
  1515. #endif /* ZDEBUG */
  1516.             return(-1);
  1517.         }
  1518.     }
  1519.     clearerr(fp[ZIFILE]);
  1520. #ifdef SELECT
  1521.     /* Here we can call select() to get a timeout... */
  1522.     if (kactive && ispipe[ZIFILE]) {
  1523.         int secs, z = 0;
  1524. #ifndef NOXFER
  1525.         if (srvping) {
  1526.             secs = 1;
  1527.             debug(F101,"zinfill calling ttwait","",secs);
  1528.             z = ttwait(fileno(fp[ZIFILE]),secs);
  1529.             debug(F101,"zinfill ttwait","",z);
  1530.         }
  1531. #endif /* NOXFER */
  1532.         if (z == 0)
  1533.           return(-3);
  1534.     }
  1535. #endif /* SELECT */
  1536. /*
  1537.   Note: The following read MUST be nonblocking when reading from a pipe
  1538.   and we want timeouts to work.  See zxcmd().
  1539. */
  1540.     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  1541. #ifdef COMMENT
  1542. #ifdef DEBUG
  1543.     if (deblog) {
  1544.         debug(F011,"ZINFILL fread",zinbuffer,zincnt); /* Much too big */
  1545.     }
  1546. #endif /* DEBUG */
  1547. #else  /* COMMENT */
  1548.     debug(F101,"ZINFILL fread","",zincnt); /* Just the size */
  1549. #endif /* COMMENT */
  1550. #ifdef ZDEBUG
  1551.     printf("FREAD=%dn",zincnt);
  1552. #endif /* ZDEBUG */
  1553.     if (zincnt == 0) {                  /* Got nothing? */
  1554.         if (ferror(fp[ZIFILE])) {
  1555.             debug(F100,"ZINFILL ferror","",0);
  1556.             debug(F101,"ZINFILL errno","",errno);
  1557. #ifdef ZDEBUG
  1558.             printf("ZINFILL errno=%dn",errno);
  1559. #endif /* ZDEBUG */
  1560. #ifdef EWOULDBLOCK
  1561.             return((errno == EWOULDBLOCK) ? -3 : -2);
  1562. #else
  1563.             return(-2);
  1564. #endif /* EWOULDBLOCK */
  1565.         }
  1566.     /* In case feof() didn't work just above -- sometimes it doesn't... */
  1567.         if (feof(fp[ZIFILE]) ) {
  1568.             debug(F100,"ZINFILL count 0 EOF return -1","",0);
  1569.             return (-1);
  1570.         } else {
  1571.             debug(F100,"ZINFILL count 0 not EOF return -2","",0);
  1572.             return(-2);
  1573.         }
  1574.     }
  1575.     zinptr = zinbuffer;    /* set pointer to beginning, (== &zinbuffer[0]) */
  1576.     zincnt--;                           /* One less char in buffer */
  1577.     return((int)(*zinptr++) & 0377);    /* because we return the first */
  1578. }
  1579. /*  Z S O U T  --  Write a string out to the given file, buffered.  */
  1580. int
  1581. zsout(n,s) int n; char *s; {
  1582.     int rc = 0;
  1583.     rc = chkfn(n);
  1584.     if (rc < 1) return(-1);             /* Keep this, prevents memory faults */
  1585.     if (!s) return(0);                  /* Null pointer, do nothing, succeed */
  1586.     if (!*s) return(0);                 /* empty string, ditto */
  1587. #ifdef IKSD
  1588.     /*
  1589.       This happens with client-side Kermit server when a REMOTE command
  1590.       was sent from the server to the client and the server is supposed to
  1591.       display the text, but of course there is no place to display it
  1592.       since it is in remote mode executing Kermit protocol.
  1593.     */
  1594.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1595. #ifdef COMMENT
  1596.         return(ttol(s,((int)strlen(s)) < 0) ? -1 : 0);
  1597. #else
  1598.         return(0);
  1599. #endif /* COMMENT */
  1600.     }
  1601. #endif /* IKSD */
  1602.     if (n == ZSFILE)
  1603.       return(write(fileno(fp[n]),s,(int)strlen(s)));
  1604.     rc = fputs(s,fp[n]) == EOF ? -1 : 0;
  1605.     if (n == ZWFILE)
  1606.       fflush(fp[n]);
  1607.     return(rc);
  1608. }
  1609. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  1610. int
  1611. zsoutl(n,s) int n; char *s; {
  1612.     if (zsout(n,s) < 0)
  1613.         return(-1);
  1614. #ifdef IKSD
  1615.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1616. #ifdef COMMENT
  1617.         return(ttoc(LF));
  1618. #else
  1619.         return(0);                      /* See comments in zsout() */
  1620. #endif /* COMMENT */
  1621.     }
  1622. #endif /* IKSD */
  1623.     if (n == ZSFILE)                    /* Session log is unbuffered */
  1624.       return(write(fileno(fp[n]),"n",1));
  1625.     else if (fputs("n",fp[n]) == EOF)
  1626.       return(-1);
  1627.     if (n == ZDIFIL || n == ZWFILE)     /* Flush connection log records */
  1628.       fflush(fp[n]);
  1629.     return(0);
  1630. }
  1631. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  1632. int
  1633. zsoutx(n,s,x) int n, x; char *s; {
  1634. #ifdef IKSD
  1635.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1636. #ifdef COMMENT
  1637.         return(ttol(s,x));              /* See comments in zsout() */
  1638. #else
  1639.         return(x);
  1640. #endif /* COMMENT */
  1641.     }
  1642. #endif /* IKSD */
  1643. #ifdef COMMENT
  1644.     if (chkfn(n) < 1) return(-1);
  1645.     return(write(fp[n]->_file,s,x));
  1646. #endif /* COMMENT */
  1647.     return(write(fileno(fp[n]),s,x) == x ? x : -1);
  1648. }
  1649. /*  Z C H O U T  --  Add a character to the given file.  */
  1650. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  1651. int
  1652. #ifdef CK_ANSIC
  1653. zchout(register int n, char c)
  1654. #else
  1655. zchout(n,c) register int n; char c;
  1656. #endif /* CK_ANSIC */
  1657. /* zchout() */ {
  1658.     /* if (chkfn(n) < 1) return(-1); */
  1659. #ifdef IKSD
  1660.     if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
  1661. #ifdef COMMENT
  1662.         return(ttoc(c));
  1663. #else
  1664.         return(0);                      /* See comments in zsout() */
  1665. #endif /* COMMENT */
  1666.     }
  1667. #endif /* IKSD */
  1668.     if (n == ZSFILE)                    /* Use unbuffered for session log */
  1669.       return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
  1670.                                 /* Buffered for everything else */
  1671.     if (putc(c,fp[n]) == EOF)   /* If true, maybe there was an error */
  1672.       return(ferror(fp[n])?-1:0);       /* Check to make sure */
  1673.     else                                /* Otherwise... */
  1674.       return(0);                        /* There was no error. */
  1675. }
  1676. /* (PWP) buffered character output routine to speed up file IO */
  1677. int
  1678. zoutdump() {
  1679.     int x;
  1680.     char * zp;
  1681.     zoutptr = zoutbuffer;               /* Reset buffer pointer in all cases */
  1682. #ifdef DEBUG
  1683.     if (deblog)
  1684.       debug(F101,"zoutdump zoutcnt","",zoutcnt);
  1685. #endif /* DEBUG */
  1686.     if (zoutcnt == 0) {                 /* Nothing to output */
  1687.         return(0);
  1688.     } else if (zoutcnt < 0) {           /* Unexpected negative argument */
  1689.         zoutcnt = 0;                    /* Reset output buffer count */
  1690.         return(-1);                     /* and fail. */
  1691.     }
  1692. #ifdef IKSD
  1693.     if (inserver && !local && fp[ZOFILE] == stdout) {
  1694. #ifdef COMMENT
  1695.         x = ttol(zoutbuffer,zoutcnt);
  1696. #else
  1697.         x = 1;                          /* See comments in zsout() */
  1698. #endif /* COMMENT */
  1699.         zoutcnt = 0;
  1700.         return(x > 0 ? 0 : -1);
  1701.     }
  1702. #endif /* IKSD */
  1703. /*
  1704.   Frank Prindle suggested that replacing this fwrite() by an fflush()
  1705.   followed by a write() would improve the efficiency, especially when
  1706.   writing to stdout.  Subsequent tests showed a 5-fold improvement.
  1707. */
  1708. #ifdef COMMENT
  1709.     if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) ...
  1710. #endif /* COMMENT */
  1711. #ifndef CK_NONBLOCK
  1712.     fflush(fp[ZOFILE]);
  1713. #endif /* CK_NONBLOCK */
  1714.     zp = zoutbuffer;
  1715.     while (zoutcnt > 0) {
  1716.         if ((x = write(fileno(fp[ZOFILE]),zp,zoutcnt)) > -1) {
  1717. #ifdef DEBUG
  1718.             if (deblog)                 /* Save a function call... */
  1719.               debug(F101,"zoutdump wrote","",x);
  1720. #endif /* DEBUG */
  1721.             zoutcnt -= x;               /* Adjust output buffer count */
  1722.             zp += x;                    /* and pointer */
  1723.         } else {
  1724. #ifdef DEBUG
  1725.             if (deblog) {
  1726.                 debug(F101,"zoutdump write error","",errno);
  1727.                 debug(F101,"zoutdump write returns","",x);
  1728.             }
  1729. #endif /* DEBUG */
  1730.             zoutcnt = 0;                /* Reset output buffer count */
  1731.             return(-1);                 /* write() failed */
  1732.         }
  1733.     }
  1734.     return(0);
  1735. }
  1736. /*  C H K F N  --  Internal function to verify file number is ok  */
  1737. /*
  1738.  Returns:
  1739.   -1: File number n is out of range
  1740.    0: n is in range, but file is not open
  1741.    1: n in range and file is open
  1742. */
  1743. int
  1744. chkfn(n) int n; {
  1745.     /* if (n != ZDFILE) debug(F101,"chkfn","",n); */
  1746.     if (n < 0 || n >= ZNFILS) {
  1747.         if (n != ZDFILE) debug(F101,"chkfn out of range","",n);
  1748.         return(-1);
  1749.     } else {
  1750.         /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */
  1751.         return((fp[n] == NULL) ? 0 : 1);
  1752.     }
  1753. }
  1754. /*  Z G E T F S -- Return file size regardless of accessibility */
  1755. /*
  1756.   Used for directory listings, etc.
  1757.   Returns:
  1758.     The size of the file in bytes, 0 or greater, if the size can be learned.
  1759.     -1 if the file size can not be obtained.
  1760.   Also (and this is a hack just for UNIX):
  1761.     If the argument is the name of a symbolic link,
  1762.     the global variable issymlink is set to 1,
  1763.     and the global buffer linkname[] gets the link value.
  1764.     And it sets zgfs_dir to 1 if it's a directory, otherwise 0.
  1765.   This lets us avoid numerous redundant calls to stat().
  1766. */
  1767. int zgfs_link = 0;
  1768. int zgfs_dir = 0;
  1769. time_t zgfs_mtime = 0;
  1770. unsigned int zgfs_mode = 0;
  1771. #ifdef CKSYMLINK
  1772. char linkname[CKMAXPATH+1];
  1773. #ifndef _IFLNK
  1774. #define _IFLNK 0120000
  1775. #endif /* _IFLNK */
  1776. #endif /* CKSYMLINK */
  1777. long
  1778. zgetfs(name) char *name; {
  1779.     struct stat buf;
  1780.     char fnam[CKMAXPATH+4];
  1781.     long size = -1L;
  1782.     int x;
  1783.     int needrlink = 0;
  1784.     char * s;
  1785. #ifdef UNIX
  1786.     x = strlen(name);
  1787.     if (x == 9 && !strcmp(name,"/dev/null"))
  1788.       return(0);
  1789. #endif /* UNIX */
  1790.     s = name;
  1791. #ifdef DTILDE
  1792.     if (*s == '~') {
  1793.         s = tilde_expand(s);
  1794.         if (!s) s = "";
  1795.         if (!*s) s = name;
  1796.     }
  1797. #endif /* DTILDE */
  1798.     x = ckstrncpy(fnam,s,CKMAXPATH);
  1799.     s = fnam;
  1800.     if (x > 0 && s[x-1] == '/')
  1801.       s[x-1] = '';
  1802.     zgfs_dir = 0;                       /* Assume it's not a directory */
  1803.     zgfs_link = 0;                      /* Assume it's not a symlink */
  1804.     zgfs_mtime = 0; /* No time yet */
  1805.     zgfs_mode = 0; /* No permission bits yet */
  1806. #ifdef CKSYMLINK                        /* We're doing symlinks? */
  1807. #ifdef USE_LSTAT                        /* OK to use lstat()? */
  1808.     x = lstat(s,&buf);
  1809.     debug(F101,"STAT","",1);
  1810.     if (x < 0)                          /* stat() failed */
  1811.       return(-1);
  1812.     if (                                /* Now see if it's a symlink */
  1813. #ifdef S_ISLNK
  1814.         S_ISLNK(buf.st_mode)
  1815. #else
  1816. #ifdef _IFLNK
  1817.         ((_IFMT & buf.st_mode) == _IFLNK)
  1818. #endif /* _IFLNK */
  1819. #endif /* S_ISLNK */
  1820.         ) {
  1821.         zgfs_link = 1;                  /* It's a symlink */
  1822.         linkname[0] = '';             /* Get the name */
  1823.         x = readlink(s,linkname,CKMAXPATH);
  1824.         debug(F101,"zgetfs readlink",s,x);
  1825.         if (x > -1 && x < CKMAXPATH) {  /* It's a link */
  1826.             linkname[x] = '';
  1827.             size = buf.st_size;         /* Remember size of link */
  1828.             x = stat(s,&buf);           /* Now stat the linked-to file */
  1829.     debug(F101,"STAT","",2);
  1830.             if (x < 0)                  /* so we can see if it's a directory */
  1831.               return(-1);
  1832.         } else {
  1833.             strcpy(linkname,"(lookup failed)");
  1834.         }
  1835.     }
  1836. #else  /* !USE_LSTAT */
  1837.     x = stat(s,&buf);                   /* No lstat(), use stat() instead */
  1838.     debug(F101,"STAT","",3);
  1839.     if (x < 0)
  1840.       return(-1);
  1841. #endif /* USE_STAT */
  1842.     /* Do we need to call readlink()? */
  1843. #ifdef NOLINKBITS
  1844. /*
  1845.   lstat() does not work in SCO operating systems.  From "man NS lstat":
  1846.   lstat obtains information about the file named by path. In the case of a
  1847.   symbolic link, lstat returns information about the link, and not the file
  1848.   named by the link. It is only used by the NFS automount daemon and should
  1849.   not be utilized by users.
  1850. */
  1851.     needrlink = 1;
  1852.     debug(F101,"zgetfs forced needrlink","",needrlink);
  1853. #else
  1854. #ifdef S_ISLNK
  1855.     needrlink = S_ISLNK(buf.st_mode);
  1856.     debug(F101,"zgetfs S_ISLNK needrlink","",needrlink);
  1857. #else
  1858. #ifdef _IFLNK
  1859.     needrlink = (_IFMT & buf.st_mode) == _IFLNK;
  1860.     debug(F101,"zgetfs _IFLNK needrlink","",needrlink);
  1861. #else
  1862.     needrlink = 1;
  1863.     debug(F101,"zgetfs default needrlink","",needrlink);
  1864. #endif /* _IFLNK */
  1865. #endif /* S_ISLNK */
  1866. #endif /* NOLINKBITS */
  1867.     if (needrlink) {
  1868.         linkname[0] = '';
  1869.         errno = 0;
  1870.         x = readlink(s,linkname,CKMAXPATH);
  1871. #ifdef DEBUG
  1872.         debug(F111,"zgetfs readlink",s,x);
  1873.         if (x < 0)
  1874.           debug(F101,"zgetfs readlink errno","",errno);
  1875.         else
  1876.           debug(F110,"zgetfs readlink result",linkname,0);
  1877. #endif /* DEBUG */
  1878.         if (x > -1 && x < CKMAXPATH) {
  1879.             zgfs_link = 1;
  1880.             linkname[x] = '';
  1881.         }
  1882.     }
  1883. #else  /* !CKSYMLINK */
  1884.     x = stat(s,&buf);                   /* Just stat the file */
  1885.     debug(F101,"STAT","",4);
  1886.     if (x < 0)                          /* and get the size */
  1887.       return(-1);
  1888. #endif /* CKSYMLINK */
  1889.     zgfs_mtime = buf.st_mtime;
  1890.     zgfs_mode = buf.st_mode;
  1891.     zgfs_dir = (S_ISDIR(buf.st_mode)) ? 1 : 0; /* Set "is directory" flag */
  1892.     return((size < 0L) ? buf.st_size : size); /* Return the size */
  1893. }
  1894. /*  Z C H K I  --  Check if input file exists and is readable  */
  1895. /*
  1896.   Returns:
  1897.    >= 0 if the file can be read (returns the size).
  1898.      -1 if file doesn't exist or can't be accessed,
  1899.      -2 if file exists but is not readable (e.g. a directory file).
  1900.      -3 if file exists but protected against read access.
  1901.   For Berkeley Unix, a file must be of type "regular" to be readable.
  1902.   Directory files, special files, and symbolic links are not readable.
  1903. */
  1904. long
  1905. zchki(name) char *name; {
  1906.     struct stat buf;
  1907.     char * s;
  1908.     int x, itsadir = 0;
  1909.     extern int zchkid;
  1910.     if (!name)
  1911.       return(-1);
  1912.     x = strlen(name);
  1913.     if (x < 1)
  1914.       return(-1);
  1915.     s = name;
  1916. #ifdef UNIX
  1917.     if (x == 9 && !strcmp(s,"/dev/null"))
  1918.       return(0);
  1919. #endif /* UNIX */
  1920. #ifdef DTILDE
  1921.     if (*s == '~') {
  1922.         s = tilde_expand(s);
  1923.         if (!s) s = "";
  1924.         if (!*s) s = name;
  1925.     }
  1926. #endif /* DTILDE */
  1927.     x = stat(s,&buf);
  1928.     debug(F101,"STAT","",5);
  1929.     if (x < 0) {
  1930.         debug(F111,"zchki stat fails",s,errno);
  1931.         return(-1);
  1932.     }
  1933.     if (S_ISDIR (buf.st_mode))
  1934.       itsadir = 1;
  1935.     if (!(itsadir && zchkid)) {         /* Unless this... */
  1936.         if (!S_ISREG (buf.st_mode)      /* Must be regular file */
  1937. #ifdef S_ISFIFO
  1938.             && !S_ISFIFO (buf.st_mode)  /* or FIFO */
  1939. #endif /* S_ISFIFO */
  1940.             ) {
  1941.             debug(F111,"zchki not regular file",s,x);
  1942.             return(-2);
  1943.         }
  1944.     }
  1945.     debug(F111,"zchki stat ok:",s,x);
  1946. #ifdef SW_ACC_ID
  1947.     debug(F100,"zchki swapping ids for access()","",0);
  1948.     priv_on();
  1949. #endif /* SW_ACC_ID */
  1950.     x = access(s,R_OK);
  1951. #ifdef SW_ACC_ID
  1952.     priv_off();
  1953.     debug(F100,"zchki swapped ids restored","",0);
  1954. #endif /* SW_ACC_ID */
  1955.     if (x < 0) {                        /* Is the file accessible? */
  1956.         debug(F111,"zchki access failed:",s,x); /* No */
  1957.         return(-3);
  1958.     } else {
  1959.         iflen = buf.st_size;            /* Yes, remember size */
  1960.         ckstrncpy(nambuf,s,CKMAXPATH);  /* and name globally. */
  1961.         debug(F111,"zchki access ok:",s,iflen);
  1962.         return((iflen > -1L) ? iflen : 0L);
  1963.     }
  1964. }
  1965. /*  Z C H K O  --  Check if output file can be created  */
  1966. /*
  1967.   Returns -1 if write permission for the file would be denied, 0 otherwise.
  1968.   NOTE: The design is flawed.  There is no distinction among:
  1969.    . Can I overwrite an existing file?
  1970.    . Can I create a file (or directory) in an existing directory?
  1971.    . Can I create a file (or directory) and its parent(s)?
  1972. */
  1973. int
  1974. zchko(name) char *name; {
  1975.     int i, x, itsadir = 0;
  1976.     char *s;
  1977.     extern int zchkod;                  /* Used by IF WRITEABLE */
  1978.     if (!name) return(-1);              /* Watch out for null pointer. */
  1979.     x = (int)strlen(name);              /* Get length of filename */
  1980.     debug(F111,"zchko",name,zchkod);
  1981. #ifdef UNIX
  1982. /*
  1983.   Writing to null device is OK.
  1984. */
  1985.     if (x == 9 && !strcmp(name,"/dev/null"))
  1986.       return(0);
  1987. #endif /* UNIX */
  1988.     s = name;
  1989. #ifdef DTILDE
  1990.     if (*s == '~') {
  1991.         s = tilde_expand(s);
  1992.         if (!s) s = "";
  1993.         if (!*s) s = name;
  1994.     }
  1995. #endif /* DTILDE */
  1996.     name = s;
  1997.     s = NULL;
  1998. /*
  1999.   zchkod is a global flag meaning we're checking not to see if the directory
  2000.   file is writeable, but if it's OK to create files IN the directory.
  2001. */
  2002.     if (!zchkod && isdir(name))         /* Directories are not writeable */
  2003.       return(-1);
  2004.     s = malloc(x+3);                    /* Must copy because we can't */
  2005.     if (!s) {                           /* write into our argument. */
  2006.         fprintf(stderr,"zchko: Malloc error 46n");
  2007.         return(-1);
  2008.     }
  2009.     strcpy(s,name);
  2010.     for (i = x; i > 0; i--) {           /* Strip filename from right. */
  2011.         if (ISDIRSEP(s[i-1])) {
  2012.             itsadir = 1;
  2013.             break;
  2014.         }
  2015.     }
  2016.     debug(F101,"zchko i","",i);
  2017.     debug(F101,"zchko itsadir","",itsadir);
  2018. #ifdef COMMENT
  2019. /* X/OPEN XPG3-compliant systems fail if argument ends with "/"...  */
  2020.     if (i == 0)                         /* If no path, use current directory */
  2021.       strcpy(s,"./");
  2022.     else                                /* Otherwise, use given one. */
  2023.       s[i] = '';
  2024. #else
  2025. #ifdef COMMENT
  2026. /*
  2027.   The following does not work for "foo/bar" where the foo directory does
  2028.   not exist even though we could create it: access("foo/.") fails, but
  2029.   access("foo") works OK.
  2030. */
  2031. /* So now we use "path/." if path given, or "." if no path given. */
  2032.     s[i++] = '.';                       /* Append "." to path. */
  2033.     s[i] = '';
  2034. #else
  2035. /* So NOW we strip path segments from the right as long as they don't */
  2036. /* exist -- we only call access() for path segments that *do* exist.. */
  2037. /* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */
  2038. /* succeeds when I have write access to foo and bar but baz doesn't exit.) */
  2039.     if (itsadir && i > 0) {
  2040.         s[i-1] = '';
  2041.         while (s[0] && !isdir(s)) {
  2042.             for (i = (int)strlen(s); i > 0; i--) {
  2043.                 if (ISDIRSEP(s[i-1])) {
  2044.                     s[i-1] = '';
  2045.                     break;
  2046.                 }
  2047.             }
  2048.             if (i == 0)
  2049.               s[0] = '';
  2050.         }
  2051.     } else {
  2052.         s[i++] = '.';                   /* Append "." to path. */
  2053.         s[i] = '';
  2054.     }
  2055. #endif /* COMMENT */
  2056. #endif /* COMMENT */
  2057.     if (!s[0])
  2058.       strcpy(s,".");
  2059. #ifdef SW_ACC_ID
  2060.     debug(F100,"zchko swapping ids for access()","",0);
  2061.     priv_on();
  2062. #endif /* SW_ACC_ID */
  2063.     x = access(s,W_OK);                 /* Check access of path. */
  2064. #ifdef SW_ACC_ID
  2065.     priv_off();
  2066.     debug(F100,"zchko swapped ids restored","",0);
  2067. #endif /* SW_ACC_ID */
  2068.     if (x < 0)
  2069.       debug(F111,"zchko access failed:",s,errno);
  2070.     else
  2071.       debug(F111,"zchko access ok:",s,x);
  2072.     free(s);                            /* Free temporary storage */
  2073.     return((x < 0) ? -1 : 0);           /* and return. */
  2074. }
  2075. /*  Z D E L E T  --  Delete the named file.  */
  2076. int
  2077. zdelet(name) char *name; {
  2078.     int x;
  2079. #ifdef CK_LOGIN
  2080.     if (isguest)
  2081.       x = -1;
  2082.     else
  2083. #endif /* CK_LOGIN */
  2084.     x = unlink(name);
  2085.     debug(F110,"zdelet",name,0);
  2086. #ifdef CKSYSLOG
  2087.     if (ckxsyslog >= SYSLG_FC && ckxlogging) {
  2088.         fullname[0] = '';
  2089.         zfnqfp(name,CKMAXPATH,fullname);
  2090.         debug(F110,"zdelet fullname",fullname,0);
  2091.         if (x < 0)
  2092.           syslog(LOG_INFO, "file[] %s: delete failed (%m)", fullname);
  2093.         else
  2094.           syslog(LOG_INFO, "file[] %s: delete ok", fullname);
  2095.     }
  2096. #endif /* CKSYSLOG */
  2097.     return(x);
  2098. }
  2099. /*  Z R T O L  --  Convert remote filename into local form  */
  2100. VOID
  2101. zrtol(name,name2) char *name, *name2; {
  2102.     nzrtol(name,name2,1,0,CKMAXPATH);
  2103. }
  2104. VOID
  2105. nzrtol(name,name2,fncnv,fnrpath,max)
  2106.     char *name, *name2; int fncnv, fnrpath, max;
  2107. { /* nzrtol */
  2108.     char *s, *p;
  2109.     int flag = 0, n = 0;
  2110.     char fullname[CKMAXPATH+1];
  2111.     int devnull = 0;
  2112.     int acase = 0;
  2113.     if (!name2) return;
  2114.     if (!name) name = "";
  2115.     debug(F110,"nzrtol name",name,0);
  2116. #ifdef DTILDE
  2117.     s = name;
  2118.     if (*s == '~') {
  2119.         s = tilde_expand(s);
  2120.         if (!s) s = "";
  2121.         if (*s) name = s;
  2122.     }
  2123. #endif /* DTILDE */
  2124.     /* Handle the path -- we don't have to convert its format, since */
  2125.     /* the standard path format and our (UNIX) format are the same. */
  2126.     fullname[0] = NUL;
  2127.     devnull = !strcmp(name,"/dev/null");
  2128.     if (!devnull && fnrpath == PATH_OFF) { /* RECEIVE PATHNAMES OFF */
  2129.         zstrip(name,&p);
  2130.         strncpy(fullname,p,CKMAXPATH);
  2131.     } else if (!devnull && fnrpath == PATH_ABS) { /* REC PATHNAMES ABSOLUTE */
  2132.         strncpy(fullname,name,CKMAXPATH);
  2133.     } else if (!devnull && isabsolute(name)) { /* RECEIVE PATHNAMES RELATIVE */
  2134.         sprintf(fullname,".%s",name);
  2135.     } else {                            /* Ditto */
  2136.         ckstrncpy(fullname,name,CKMAXPATH);
  2137.     }
  2138.     fullname[CKMAXPATH] = NUL;
  2139.     debug(F110,"nzrtol fullname",fullname,0);
  2140. #ifndef NOTRUNCATE
  2141. /*
  2142.   The maximum length for any segment of a filename is MAXNAMLEN, defined
  2143.   above.  On some platforms (at least QNX) if a segment exceeds this limit,
  2144.   the open fails with ENAMETOOLONG, so we must prevent it by truncating each
  2145.   overlong name segment to the maximum segment length before passing the
  2146.   name to open().  This must be done even when file names are literal, so as
  2147.   not to halt a file transfer unnecessarily.
  2148. */
  2149.     {
  2150.         char buf[CKMAXPATH+1];          /* New temporary buffer on stack */
  2151.         char *p = fullname;             /* Source and  */
  2152.         char *s = buf;                  /* destination pointers */
  2153.         int i = 0, n = 0;
  2154.         debug(F101,"nzrtol sizing MAXNAMLEN","",MAXNAMLEN);
  2155.         while (*p && n < CKMAXPATH) {   /* Copy name to new buffer */
  2156.             if (++i > MAXNAMLEN) {      /* If this segment too long */
  2157.                 while (*p && *p != '/') /* skip past the rest... */
  2158.                   p++;
  2159.                 i = 0;                  /* and reset counter. */
  2160.             } else if (*p == '/') {     /* End of this segment. */
  2161.                 i = 0;                  /* Reset counter. */
  2162.             }
  2163.             *s++ = *p++;                /* Copy this character. */
  2164.             n++;
  2165.         }
  2166.         *s = NUL;
  2167.         ckstrncpy(fullname,buf,CKMAXPATH); /* Copy back to original buffer. */
  2168.         debug(F111,"nzrtol sizing",fullname,n);
  2169.     }
  2170. #endif /* NOTRUNCATE */
  2171.     if (!fncnv || devnull) {            /* Not converting */
  2172.         ckstrncpy(name2,fullname,max);  /* We're done. */
  2173.         return;
  2174.     }
  2175.     name = fullname;                    /* Converting */
  2176.     p = name2;
  2177.     for (; *name != '' && n < maxnam; name++) {
  2178.         if (*name > SP) flag = 1;       /* Strip leading blanks and controls */
  2179.         if (flag == 0 && *name < '!')
  2180.           continue;
  2181.         if (isupper(*name))             /* Check for mixed case */
  2182.           acase |= 1;
  2183.         else if (islower(*name))
  2184.           acase |= 2;
  2185.         *p++ = *name;
  2186.         n++;
  2187.     }
  2188.     *p-- = '';                        /* Terminate */
  2189.     while (*p < '!' && p > name2)       /* Strip trailing blanks & controls */
  2190.       *p-- = '';
  2191.     if (*name2 == '') {               /* Nothing left? */
  2192.         strcpy(name2,"NONAME");         /* do this... */
  2193.     } else if (acase == 1) {            /* All uppercase? */
  2194.         p = name2;                      /* So convert all letters to lower */
  2195.         while (*p) {
  2196.             if (isupper(*p))
  2197.               *p = tolower(*p);
  2198.             p++;
  2199.         }
  2200.     }
  2201.     debug(F110,"nzrtol new name",name2,0);
  2202. }
  2203. /*  Z S T R I P  --  Strip device & directory name from file specification */
  2204. /*  Strip pathname from filename "name", return pointer to result in name2 */
  2205. static char work[CKMAXPATH+1];
  2206. VOID
  2207. zstrip(name,name2) char *name, **name2; {
  2208.     char *cp, *pp;
  2209.     int n = 0;
  2210.     debug(F110,"zstrip before",name,0);
  2211.     if (!name) { *name2 = ""; return; }
  2212.     pp = work;
  2213. #ifdef DTILDE
  2214.     /* Strip leading tilde */
  2215.     if (*name == '~') name++;
  2216.     debug(F110,"zstrip after tilde-stripping",name,0);
  2217. #endif /* DTILDE */
  2218.     for (cp = name; *cp; cp++) {
  2219.         if (ISDIRSEP(*cp)) {
  2220.             pp = work;
  2221.             n = 0;
  2222.         } else {
  2223.             *pp++ = *cp;
  2224.             if (n++ >= CKMAXPATH)
  2225.               break;
  2226.         }
  2227.     }
  2228.     *pp = '';                         /* Terminate the string */
  2229.     *name2 = work;
  2230.     debug(F110,"zstrip after",*name2,0);
  2231. }
  2232. /*  Z L T O R  --  Local TO Remote */
  2233. VOID
  2234. zltor(name,name2) char *name, *name2; {
  2235.     nzltor(name,name2,1,0,CKMAXPATH);
  2236. }
  2237. /*  N Z L T O R  --  New Local TO Remote */
  2238. VOID
  2239. nzltor(name,name2,fncnv,fnspath,max)
  2240.     char *name, *name2; int fncnv, fnspath, max;
  2241. { /* nzltor */
  2242.     char *cp, *pp;
  2243. #ifdef COMMENT
  2244.     int dc = 0;
  2245. #endif /* COMMENT */
  2246.     int n = 0;
  2247.     char *dotp = NULL;
  2248.     char *dirp = NULL;
  2249.     char fullname[CKMAXPATH+1];
  2250.     char *p;
  2251.     CHAR c;
  2252. #ifndef NOCSETS
  2253.     extern int fcharset, /* tcharset, */ language;
  2254.     int langsv;
  2255.     _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
  2256. #ifdef CK_ANSIC
  2257.     extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
  2258. #else
  2259.     extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
  2260. #endif /* CK_ANSIC */
  2261.     langsv = language;
  2262.     language = L_USASCII;
  2263. #ifdef COMMENT
  2264.     /* Proper translation of filenames must be done elsewhere */
  2265.     n = tcharset ? tcharset : TC_USASCII;
  2266.     sxo = xls[n][fcharset];
  2267. #else
  2268.     sxo = xls[TC_USASCII][fcharset];
  2269. #endif /* COMMENT */
  2270. #endif /* NOCSETS */
  2271.     debug(F110,"nzltor name",name,0);
  2272.     /* Handle pathname */
  2273.     fullname[0] = NUL;
  2274.     if (fnspath == PATH_OFF) {          /* PATHNAMES OFF */
  2275.         zstrip(name,&p);
  2276.         ckstrncpy(fullname,p,CKMAXPATH);
  2277.     } else {                            /* PATHNAMES RELATIVE or ABSOLUTE */
  2278.         int x = 0;
  2279.         char * p = name;
  2280.         while (1) {
  2281.             if (!strncmp(p,"../",3))
  2282.               p += 3;
  2283.             else if (!strncmp(p,"./",2))
  2284.               p += 2;
  2285.             else
  2286.               break;
  2287.         }
  2288.         if (fnspath == PATH_ABS) {      /* ABSOLUTE */
  2289.             zfnqfp(p,CKMAXPATH,fullname);
  2290.         } else {                        /* RELATIVE */
  2291.             ckstrncpy(fullname,p,CKMAXPATH);
  2292.         }
  2293.     }
  2294.     debug(F110,"nzltor fullname",fullname,0);
  2295.     if (!fncnv) {                       /* Not converting */
  2296.         ckstrncpy(name2,fullname,max);  /* We're done. */
  2297. #ifndef NOCSETS
  2298.         langsv = language;
  2299. #endif /* NOCSETS */
  2300.         return;
  2301.     }
  2302.     name = fullname;                    /* Converting */
  2303. #ifdef aegis
  2304.     char *namechars;
  2305.     int tilde = 0, bslash = 0;
  2306.     if ((namechars = getenv("NAMECHARS")) != NULL) {
  2307.         if (ckstrchr(namechars, '~' ) != NULL) tilde  = '~';
  2308.         if (ckstrchr(namechars, '\') != NULL) bslash = '\';
  2309.     } else {
  2310.         tilde = '~';
  2311.         bslash = '\';
  2312.     }
  2313. #endif /* aegis */
  2314.     pp = work;                          /* Output buffer */
  2315.     for (cp = name, n = 0; *cp && n < max; cp++,n++) { /* Convert name chars */
  2316.         c = *cp;
  2317. #ifndef NOCSETS
  2318.         if (sxo) c = (*sxo)(c);         /* Convert to ASCII */
  2319. #endif /* NOCSETS */
  2320.         if (islower(c))                 /* Uppercase letters */
  2321.           *pp++ = toupper(c);           /* Change tilde to hyphen */
  2322.         else if (c == '~')
  2323.           *pp++ = '-';
  2324.         else if (c == '#')              /* Change number sign to 'X' */
  2325.           *pp++ = 'X';
  2326.         else if (c == '*' || c == '?')  /* Change wildcard chars to 'X' */
  2327.           *pp++ = 'X';
  2328.         else if (c == ' ')              /* Change space to underscore */
  2329.           *pp++ = '_';
  2330.         else if (c < ' ')               /* Change space and controls to 'X' */
  2331.           *pp++ = 'X';
  2332.         else if (c == '.') {            /* Change dot to underscore */
  2333.             dotp = pp;                  /* Remember where we last did this */
  2334.             *pp++ = '_';
  2335.         } else {
  2336.             if (c == '/')
  2337.               dirp = pp;
  2338.             *pp++ = c;
  2339.         }
  2340.     }
  2341.     *pp = NUL;                          /* Tie it off. */
  2342. #ifdef COMMENT
  2343.     if (dotp) *dotp = '.';              /* Restore last dot (if any) */
  2344. #else
  2345.     if (dotp > dirp) *dotp = '.';       /* Restore last dot in file name */
  2346. #endif /* COMMENT */
  2347.     cp = name2;                         /* If nothing before dot, */
  2348.     if (*work == '.') *cp++ = 'X';      /* insert 'X' */
  2349.     ckstrncpy(cp,work,max);
  2350. #ifndef NOCSETS
  2351.     langsv = language;
  2352. #endif /* NOCSETS */
  2353.     debug(F110,"nzltor name2",name2,0);
  2354. }
  2355. /*  Z C H D I R  --  Change directory  */
  2356. /*
  2357.   Call with:
  2358.     dirnam = pointer to name of directory to change to,
  2359.       which may be "" or NULL to indicate user's home directory.
  2360.   Returns:
  2361.     0 on failure
  2362.     1 on success
  2363. */
  2364. int
  2365. zchdir(dirnam) char *dirnam; {
  2366.     char *hd, *sp, *p;
  2367. #ifdef IKSDB
  2368.     _PROTOTYP (int slotdir,(char *,char *));
  2369. #endif /* IKSDB */
  2370.     debug(F110,"zchdir",dirnam,0);
  2371.     if (!dirnam) dirnam = "";
  2372.     if (!*dirnam)                       /* If argument is null or empty, */
  2373.       dirnam = zhome();                 /* use user's home directory. */
  2374.     sp = dirnam;
  2375.     debug(F110,"zchdir 2",dirnam,0);
  2376. #ifdef DTILDE
  2377.     hd = tilde_expand(dirnam);          /* Attempt to expand tilde */
  2378.     if (!hd) hd = "";
  2379.     if (*hd == '') hd = dirnam;       /* in directory name. */
  2380. #else
  2381.     hd = dirnam;
  2382. #endif /* DTILDE */
  2383.     debug(F110,"zchdir 3",hd,0);
  2384. #ifdef pdp11
  2385.     /* Just to save some space */
  2386.     return((chdir(hd) == 0) ? 1 : 0);
  2387. #else
  2388.     if (chdir(hd) == 0) {                       /* Try to cd */
  2389. #ifdef IKSDB
  2390.         if (inserver && ikdbopen)
  2391.           slotdir(isguest ? anonroot : "", zgtdir());
  2392. #endif /* IKSDB */
  2393.         return(1);
  2394.     }
  2395.     return(0);
  2396. #endif /* pdp11 */
  2397. }
  2398. int
  2399. #ifdef CK_ANSIC
  2400. zchkpid(unsigned long pid)
  2401. #else
  2402. zchkpid(pid) unsigned long pid;
  2403. #endif /* CK_ANSIC */
  2404. {
  2405.     return((kill((PID_T)pid,0) < 0) ? 0 : 1);
  2406. }
  2407. /*  Z H O M E  --  Return pointer to user's home directory  */
  2408. char *
  2409. zhome() {
  2410. #ifdef Plan9
  2411.     char *home = getenv("home");
  2412. #else
  2413.     char *home = getenv("HOME");
  2414. #endif /* Plan9 */
  2415.     return(home ? home : ".");
  2416. }
  2417. /*  Z G T D I R  --  Returns a pointer to the current directory  */
  2418. /*
  2419.   The "preferred" interface for getting the current directory in modern UNIX
  2420.   is getcwd() [POSIX 1003.1 5.2.2].  However, on certain platforms (such as
  2421.   SunOS), it is implemented by forking a shell, feeding it the pwd command,
  2422.   and returning the result, which is not only inefficient but also can result
  2423.   in stray messages to the terminal.  In such cases -- as well as when
  2424.   getcwd() is not available at all -- getwd() can be used instead by defining
  2425.   USE_GETWD.  However, note that getwd() provides no buffer-length argument
  2426.   and therefore no safeguard against memory leaks.
  2427. */
  2428. #ifndef USE_GETWD
  2429. #ifdef BSD42
  2430. #define USE_GETWD
  2431. #else
  2432. #ifdef SUNOS4
  2433. #define USE_GETWD
  2434. #endif /* SUNOS4 */
  2435. #endif /* BSD42 */
  2436. #endif /* USE_GETWD */
  2437. #ifdef pdp11
  2438. #define CWDBL 80                        /* Save every byte we can... */
  2439. #else
  2440. #define CWDBL CKMAXPATH
  2441. #endif /* pdp11 */
  2442. static char cwdbuf[CWDBL+2];
  2443. /*
  2444.   NOTE: The getcwd() prototypes are commented out on purpose.  If you get
  2445.   compile-time warnings, search through your system's header files to see
  2446.   which one has the needed prototype, and #include it.  Usually it is
  2447.   <unistd.h>.  See the section for including <unistd.h> in ckcdeb.h and
  2448.   make any needed adjustments there (and report them).
  2449. */
  2450. char *
  2451. zgtdir() {
  2452.     char * buf = cwdbuf;
  2453.     char * s;
  2454.     int x;
  2455. #ifdef USE_GETWD
  2456.     extern char *getwd();
  2457.     s = getwd(buf);
  2458.     debug(F110,"zgtdir BSD4 getwd()",s,0);
  2459.     if (!s) s = "./";
  2460.     return(s);
  2461. #else
  2462. #ifdef BSD44
  2463. #ifdef DCLGETCWD
  2464. _PROTOTYP( char * getcwd, (char *, SIZE_T) );
  2465. #endif /* DCLGETCWD */
  2466.     debug(F101,"zgtdir BSD44 CWDBL","",CWDBL);
  2467.     s = getcwd(buf,CWDBL);
  2468.     if (!s) s = "./";
  2469.     return(s);
  2470. #else
  2471. #ifdef MINIX2
  2472. #ifdef DCLGETCWD
  2473.     _PROTOTYP( char * getcwd, (char *, SIZE_T) );
  2474. #endif /* DCLGETCWD */
  2475.     debug(F101,"zgtdir MINIX2 CWDBL","",CWDBL);
  2476.     s = getcwd(buf,CWDBL);
  2477.     if (!s) s = "./";
  2478.     return(s);
  2479. #else
  2480. #ifdef SVORPOSIX
  2481. #ifdef COMMENT
  2482. /* This non-ANSI prototype can be fatal at runtime! (e.g. in SCO3.2v5.0.5). */
  2483. /* Anyway it's already prototyped in some header file that we have included. */
  2484.     extern char *getcwd();
  2485. #else
  2486. #ifdef DCLGETCWD
  2487.     _PROTOTYP( char * getcwd, (char *, SIZE_T) );
  2488. #endif /* DCLGETCWD */
  2489. #endif /* COMMENT */
  2490.     debug(F101,"zgtdir SVORPOSIX CWDBL","",CWDBL);
  2491.     s = getcwd(buf,CWDBL);
  2492.     if (!s) s = "./";
  2493.     return(s);
  2494. #else
  2495. #ifdef COHERENT
  2496. #ifdef _I386
  2497. #ifdef DCLGETCWD
  2498.     extern char *getcwd();
  2499. #endif /* DCLGETCWD */
  2500.     debug(F101,"zgtdir COHERENT _I386 CWDBL","",CWDBL);
  2501.     s = getcwd(buf,CWDBL);
  2502.     if (!s) s = "./";
  2503.     return(s);
  2504. #else
  2505.     extern char *getwd();
  2506.     debug(F101,"zgtdir COHERENT CWDBL","",CWDBL);
  2507.     s = getwd(buf);
  2508.     if (!s) s = "./";
  2509.     return(s);
  2510. #endif /* _I386 */
  2511. #else
  2512. #ifdef SUNOS4
  2513.     debug(F101,"zgtdir SUNOS CWDBL","",CWDBL);
  2514.     s = getcwd(buf,CWDBL);
  2515.     if (!s) s = "./";
  2516.     return(s);
  2517. #else
  2518.     return("./");
  2519. #endif /* SUNOS4 */
  2520. #endif /* COHERENT */
  2521. #endif /* SYSVORPOSIX */
  2522. #endif /* MINIX2 */
  2523. #endif /* BSD44 */
  2524. #endif /* USE_GETWD */
  2525. }
  2526. /*  Z X C M D -- Run a system command so its output can be read like a file */
  2527. #ifndef NOPUSH
  2528. int
  2529. zxcmd(filnum,comand) int filnum; char *comand; {
  2530.     int out;
  2531.     int pipes[2];
  2532.     extern int kactive;                 /* From ckcpro.w and ckcmai.c */
  2533.     if (nopush) {
  2534.         debug(F100,"zxcmd fails: nopush","",0);
  2535.         return(-1);
  2536.     }
  2537.     debug(F111,"zxcmd",comand,filnum);
  2538.     if (chkfn(filnum) < 0) return(-1);  /* Need a valid Kermit file number. */
  2539.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  2540.       return(0);
  2541.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  2542.     debug(F101,"zxcmd out",comand,out);
  2543. /* Output to a command */
  2544.     if (out) {                          /* Need popen() to do this. */
  2545. #ifdef NOPOPEN
  2546.         return(0);                      /* no popen(), fail. */
  2547. #else
  2548. /* Use popen() to run the command. */
  2549. #ifdef _POSIX_SOURCE
  2550. /* Strictly speaking, popen() is not available in POSIX.1 */
  2551. #define DCLPOPEN
  2552. #endif /* _POSIX_SOURCE */
  2553.         if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL)) {
  2554.             return(0);
  2555.         } else {
  2556. #ifdef COMMENT
  2557. /* I wonder what this is all about... */
  2558.             close(pipes[0]);                   /* Don't need the input side */
  2559.             fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
  2560.             fp[ZSYSFN] = fp[filnum];           /* Remember. */
  2561. #endif /* COMMENT */
  2562.             ispipe[filnum] = 1;
  2563.             zoutcnt = 0;                       /* (PWP) reset input buffer */
  2564.             zoutptr = zoutbuffer;
  2565.             return(1);
  2566.         }
  2567. #endif /* NOPOPEN */
  2568.     }
  2569. /* Input from a command */
  2570. #ifdef SNI541
  2571.     /* SINIX-L 5.41 does not like fdopen() */
  2572.     return(0);
  2573. #else
  2574.     if (pipe(pipes) != 0) {
  2575.         debug(F100,"zxcmd pipe failure","",0);
  2576.         return(0);                      /* can't make pipe, fail */
  2577.     }
  2578. /* Create a fork in which to run the named process */
  2579.     if ((
  2580. #ifdef aegis
  2581.          pid = vfork()                  /* child */
  2582. #else
  2583.          pid = fork()                   /* child */
  2584. #endif /* aegis */
  2585.          ) == 0) {
  2586. /* We're in the fork. */
  2587.         char *shpath, *shname, *shptr;  /* Find user's preferred shell */
  2588. #ifndef aegis
  2589.         struct passwd *p;
  2590.         char *defshell;
  2591. #ifdef HPUX10                           /* Default shell */
  2592.         defshell = "/usr/bin/sh";
  2593. #else
  2594. #ifdef Plan9
  2595.         defshell = "/bin/rc";
  2596. #else
  2597.         defshell = "/bin/sh";
  2598. #endif /* Plan9 */
  2599. #endif /* HPUX10 */
  2600. #endif /* aegis */
  2601.         if (priv_can()) exit(1);        /* Turn off any privileges! */
  2602.         debug(F101,"zxcmd pid","",pid);
  2603.         close(pipes[0]);                /* close input side of pipe */
  2604.         close(0);                       /* close stdin */
  2605.         if (open("/dev/null",0) < 0) return(0); /* replace input by null */
  2606. #ifndef OXOS
  2607. #ifndef SVORPOSIX
  2608.         dup2(pipes[1],1);               /* BSD: replace stdout & stderr */
  2609.         dup2(pipes[1],2);               /* by the pipe */
  2610. #else
  2611.         close(1);                       /* AT&T: close stdout */
  2612.         if (dup(pipes[1]) != 1)         /* Send stdout to the pipe */
  2613.           return(0);
  2614.         close(2);                       /* Send stderr to the pipe */
  2615.         if (dup(pipes[1]) != 2)
  2616.           return(0);
  2617. #endif /* SVORPOSIX */
  2618. #else /* OXOS */
  2619.         dup2(pipes[1],1);
  2620.         dup2(pipes[1],2);
  2621. #endif /* OXOS */
  2622.         close(pipes[1]);                /* Don't need this any more. */
  2623. #ifdef aegis
  2624.         if ((shpath = getenv("SERVERSHELL")) == NULL)
  2625.           shpath = "/bin/sh";
  2626. #else
  2627.         shpath = getenv("SHELL");       /* What shell? */
  2628.         if (shpath == NULL) {
  2629.             p = getpwuid( real_uid() ); /* Get login data */
  2630.             debug(F111,"zxcmd shpath","getpwuid()",p);
  2631.             if (p == (struct passwd *)NULL || !*(p->pw_shell))
  2632.               shpath = defshell;
  2633.             else shpath = p->pw_shell;
  2634.         }
  2635. #endif /* aegis */
  2636.         shptr = shname = shpath;
  2637.         while (*shptr != '')
  2638.           if (*shptr++ == '/')
  2639.             shname = shptr;
  2640.         debug(F110,shpath,shname,0);
  2641. restorsigs(); /* Restore ignored signals */
  2642.         execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
  2643.         exit(0);                        /* just punt if it failed. */
  2644.     } else if (pid == (PID_T) -1) {
  2645.         debug(F100,"zxcmd fork failure","",0);
  2646.         return(0);
  2647.     }
  2648.     debug(F101,"zxcmd pid","",pid);
  2649.     close(pipes[1]);                    /* Don't need the output side */
  2650.     ispipe[filnum] = 1;                 /* Remember it's a pipe */
  2651.     fp[filnum] = fdopen(pipes[0],"r");  /* Open a stream for input. */
  2652. #ifdef DONDELAY
  2653.     if (filnum == ZIFILE && kactive) {  /* Make pipe reads nonblocking */
  2654.         int flags, x;
  2655.         if ((flags = fcntl(fileno(fp[filnum]),F_GETFL,0)) > -1) {
  2656.             debug(F101,"zxcmd fcntl 1 pipe flags","",flags);
  2657.             x = fcntl(fileno(fp[filnum]),F_SETFL, flags |
  2658. #ifdef QNX
  2659.                   O_NONBLOCK
  2660. #else
  2661.                   O_NDELAY
  2662. #endif /* QNX */
  2663.                   );
  2664.             debug(F101,"zxcmd fcntl 2 result","",x);
  2665.         }
  2666.     }
  2667. #endif /* DONDELAY */
  2668. #endif /* SNI541 */
  2669.     fp[ZSYSFN] = fp[filnum];            /* Remember. */
  2670.     zincnt = 0;                         /* (PWP) reset input buffer */
  2671.     zinptr = zinbuffer;
  2672.     return(1);
  2673. } /* zxcmd */
  2674. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  2675. /*  Used internally by zclose - returns -1 on failure, 1 on success. */
  2676. int
  2677. zclosf(filnum) int filnum; {
  2678.     int wstat, out;
  2679.     int statusp;
  2680.     debug(F101,"zclosf filnum","",filnum);
  2681.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  2682.     debug(F101,"zclosf out","",out);
  2683. #ifndef NOPOPEN
  2684.     if (ispipe[filnum]
  2685.         /* In UNIX we use popen() only for output files */
  2686.         && out
  2687.         ) {
  2688.         int x;
  2689.         x = pclose(fp[filnum]);
  2690.         pexitstat = x >> 8;
  2691.         debug(F101,"zclosf pclose","",x);
  2692.         debug(F101,"zclosf pexitstat","",pexitstat);
  2693.         fp[filnum] = fp[ZSYSFN] = NULL;
  2694.         ispipe[filnum] = 0;
  2695.         return((x != 0) ? -1 : 1);
  2696.     }
  2697. #endif /* NOPOPEN */
  2698.     debug(F101,"zclosf fp[filnum]","", fp[filnum]);
  2699.     debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
  2700.     if (pid != (PID_T) 0) {
  2701.         debug(F101,"zclosf killing pid","",pid);
  2702. #ifdef Plan9
  2703.         kill(pid, SIGKILL);
  2704. #else
  2705.         kill(pid,9);
  2706. #endif /* Plan9 */
  2707. #ifndef CK_CHILD
  2708. /*
  2709.   This is the original code (before 20 April 1997) and has proven totally
  2710.   portable.  But it does not give us the process's return code.
  2711. */
  2712.         while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
  2713. #else
  2714. /* Here we try to get the return code.  Let's hope this is portable too. */
  2715.         while ((wstat = wait(&statusp)) != pid && wstat != -1) ;
  2716.         pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
  2717.         debug(F101,"zclosf wait statusp","",statusp);
  2718.         debug(F101,"zclosf wait pexitstat","",pexitstat);
  2719. #endif /* CK_CHILD */
  2720.         pid = 0;
  2721.     }
  2722.     fclose(fp[filnum]);
  2723.     fp[filnum] = fp[ZSYSFN] = NULL;
  2724.     ispipe[filnum] = 0;
  2725.     debug(F101,"zclosf fp[filnum]","",fp[filnum]);
  2726. #ifdef CK_CHILD
  2727.     return(pexitstat == 0 ? 1 : -1);
  2728. #else
  2729.     return(1);
  2730. #endif /* CK_CHILD */
  2731. }
  2732. #else  /* NOPUSH */
  2733. int
  2734. zxcmd(filnum,comand) int filnum; char *comand; {
  2735.     return(0);
  2736. }
  2737. int
  2738. zclosf(filnum) int filnum; {
  2739.     return(EOF);
  2740. }
  2741. #endif /* NOPUSH */
  2742. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  2743. /*
  2744.   As of C-Kermit 7.0, this API is obsolete, replaced by nzxpand(), and this
  2745.   function is only used internally.  See nzxpand() below.
  2746.   Returns the number of files that match fnarg, with data structures set up
  2747.   so that first file (if any) will be returned by the next znext() call.
  2748.   Depends on external variable wildxpand: 0 means we expand wildcards
  2749.   internally, nonzero means we call the shell to do it.
  2750. */
  2751. static int xdironly = 0;
  2752. static int xfilonly = 0;
  2753. static int xmatchdot = 0;
  2754. static int xrecursive = 0;
  2755. static int xnobackup = 0;
  2756. #ifndef pdp11
  2757. static
  2758. #endif /* pdp11 */
  2759. int
  2760. zxpand(fnarg) char *fnarg; {
  2761.     char fnbuf[CKMAXPATH+8];
  2762.     char * fn;
  2763.     char *p, *s;
  2764. #ifdef DTILDE                           /* Built with tilde-expansion? */
  2765.     char *tnam;
  2766. #endif /* DTILDE */
  2767.     int x;
  2768.     if (!fnarg)                         /* If no argument provided */
  2769.       return(0);                        /* Return zero files found */
  2770.     debug(F110,"zxpand entry",fnarg,0);
  2771.     debug(F101,"zxpand xdironly","",xdironly);
  2772.     debug(F101,"zxpand xfilonly","",xfilonly);
  2773. #ifdef COMMENT
  2774. /*
  2775.   This would have been perfect, except it makes us return fully qualified
  2776.   pathnames for all files.
  2777. */
  2778.     zfnqfp(fnarg,CKMAXPATH,fnbuf);
  2779.     debug(F110,"zxpand zfnqfp",fnbuf,0);
  2780.     s = zgtdir();
  2781.     debug(F110,"zxpand zgtdir",s,0);
  2782.     p = fnbuf;
  2783.     while (*p && *s)                    /* Make it relative */
  2784.       if (*s++ != *p++)
  2785.         break;
  2786.     fn = (*s) ? fnbuf : p;
  2787.     debug(F110,"zxpand fn 0",fn,0);
  2788.     if (!*fn) {
  2789.         fn = fnbuf;
  2790.         fnbuf[0] = '*';
  2791.         fnbuf[1] = '';
  2792.     }
  2793.     debug(F110,"zxpand fn 0.5",fn,0);
  2794. #else
  2795. #ifdef DTILDE                           /* Built with tilde-expansion? */
  2796.     if (*fnarg == '~') {                /* Starts with tilde? */
  2797.         tnam = tilde_expand(fnarg);     /* Try to expand it. */
  2798.         ckstrncpy(fnbuf,tnam,CKMAXPATH);
  2799.     } else
  2800. #endif /* DTILDE */
  2801.       ckstrncpy(fnbuf,fnarg,CKMAXPATH);
  2802.     fn = fnbuf;                         /* Point to what we'll work with */
  2803. #endif /* COMMENT */
  2804.     debug(F110,"zxpand fn 1",fn,0);
  2805.     if (!*fn)                           /* But make sure something is there */
  2806.       return(0);
  2807.     p = fn + (int)strlen(fn) - 1;
  2808.     if (*p == '/') {                    /* If last char = / it must be a dir */
  2809.         strcat(fn, "*");                /* so append '*' */
  2810.     } else if (p > fn) {                /* If ends in "/." */
  2811.         if (*(p-1) == '/' && *p == '.') /* change '.' to '*' */
  2812.           *p = '*';
  2813.     } else if (p == fn) {               /* If it's '.' alone */
  2814.         if (*p == '.')                  /* change '.' to '*' */
  2815.           *p = '*';
  2816.     }
  2817.     debug(F110,"zxpand fn 2",fn,0);
  2818.     x = isdir(fn);                      /* Is it a directory? */
  2819.     debug(F111,"zxpand isdir 1",fn,x);
  2820.     if (x) {                            /* If so, make it into a wildcard */
  2821.         if ((x = strlen(fn)) > 0) {
  2822.             if (!ISDIRSEP(fn[x-1]))
  2823.               fn[x++] = DIRSEP;
  2824.             fn[x++] = '*';
  2825.             fn[x] = '';
  2826.         }
  2827.     }
  2828.     debug(F110,"zxpand fn 3",fn,0);
  2829. #ifndef NOPUSH
  2830.     if (!nopush && wildxpand)           /* Who is expanding wildcards? */
  2831.       fcount = (mtchs == NULL &&        /* Shell */
  2832.                 (mtchs = (char **)malloc(MAXWLD * sizeof(*mtchs))) == NULL)
  2833.         ? 0
  2834.           :  shxpand(fn,mtchs,MAXWLD);
  2835.     else
  2836. #endif /* NOPUSH */
  2837.       fcount = (mtchs == NULL &&        /* Kermit */
  2838.                 (mtchs = (char **)malloc(MAXWLD * sizeof(*mtchs))) == NULL)
  2839.         ? 0
  2840.           : fgen(fn,mtchs,MAXWLD);      /* Look up the file. */
  2841.     mtchptr = mtchs;                    /* Save pointer for next. */
  2842.     nxpand = fcount;
  2843. #ifdef DEBUG
  2844.     if (deblog) {
  2845.         if (fcount > 1)
  2846.           debug(F111,"zxpand ok",mtchs[0],fcount);
  2847.         else
  2848.           debug(F101,"zxpand fcount","",fcount);
  2849.     }
  2850. #endif /* DEBUG */
  2851.     return(fcount);
  2852. }
  2853. /*  N Z X P A N D  --  Expland a file list, with options.  */
  2854. /*
  2855.   Call with:
  2856.    s = pointer to filename or pattern.
  2857.    flags = option bits:
  2858.      flags & ZX_FILONLY   Match regular files
  2859.      flags & ZX_DIRONLY   Match directories
  2860.      flags & ZX_RECURSE   Descend through directory tree
  2861.      flags & ZX_MATCHDOT  Match "dot files"
  2862.      flags & ZX_NOBACKUP  Don't match "backup files"
  2863.    Returns the number of files that match s, with data structures set up
  2864.    so that first file (if any) will be returned by the next znext() call.
  2865. */
  2866. int
  2867. nzxpand(s,flags) char * s; int flags; {
  2868.     int x;
  2869.     debug(F111,"nzxpand",s,flags);
  2870.     x = flags & (ZX_DIRONLY|ZX_FILONLY);
  2871.     xdironly = (x == ZX_DIRONLY);
  2872.     xfilonly = (x == ZX_FILONLY);
  2873.     if (xdironly && xfilonly) {
  2874.         xdironly = 0;
  2875.         xfilonly = 0;
  2876.     }
  2877.     xmatchdot  = (flags & ZX_MATCHDOT);
  2878.     xrecursive = (flags & ZX_RECURSE);
  2879.     xnobackup  = (flags & ZX_NOBACKUP);
  2880.     debug(F101,"nzxpand xdironly","",xdironly);
  2881.     debug(F101,"nzxpand xfilonly","",xfilonly);
  2882.     debug(F101,"nzxpand xmatchdot","",xmatchdot);
  2883.     debug(F101,"nzxpand xrecursive","",xrecursive);
  2884.     debug(F101,"nzxpand xnobackup","",xnobackup);
  2885.     x = zxpand(s);
  2886.     xdironly = 0;
  2887.     xfilonly = 0;
  2888.     xmatchdot = 0;
  2889.     xrecursive = 0;
  2890.     xnobackup = 0;
  2891.     return(x);
  2892. }
  2893. /*  Z X R E W I N D  --  Rewinds the zxpand() list */
  2894. int
  2895. zxrewind() {
  2896.     if (!mtchs) return(-1);
  2897.     fcount = nxpand;
  2898.     mtchptr = mtchs;
  2899.     return(nxpand);
  2900. }
  2901. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  2902. /*
  2903.   Returns >0 if there's another file, with its name copied into the arg string,
  2904.   or 0 if no more files in list.
  2905. */
  2906. int
  2907. znext(fn) char *fn; {
  2908.     if (fcount-- > 0) {
  2909.         ckstrncpy(fn,*mtchptr++,CKMAXPATH);
  2910.     } else {
  2911.         fn[0] = '';
  2912.     }
  2913. #ifndef COMMENT
  2914.     debug(F111,"znext",fn,fcount+1);
  2915.     return(fcount+1);
  2916. #else
  2917.     debug(F111,"znext",fn,fcount);      /* Return 0 if no filename to return */
  2918.     return(fcount);
  2919. #endif /* COMMENT */
  2920. }
  2921. /*  Z C H K S P A  --  Check if there is enough space to store the file  */
  2922. /*
  2923.  Call with file specification f, size n in bytes.
  2924.  Returns -1 on error, 0 if not enough space, 1 if enough space.
  2925. */
  2926. int
  2927. #ifdef CK_ANSIC
  2928. zchkspa(char *f, long n)
  2929. #else
  2930. zchkspa(f,n) char *f; long n;
  2931. #endif /* CK_ANSIC */
  2932. /* zchkspa() */ {
  2933.     /* In UNIX there is no good (and portable) way. */
  2934.     return(1);                          /* Always say OK. */
  2935. }
  2936. #ifdef COMMENT /* (not used) */
  2937. /*  I S B A C K U P  --  Tells if given file has a backup suffix  */
  2938. /*
  2939.    Returns:
  2940.    -1: Invalid argument
  2941.     0: File does not have a backup suffix
  2942.    >0: Backup suffix number
  2943. */
  2944. int
  2945. isbackup(fn) char * fn; { /* Get backup suffix number */
  2946.     int i, j, k, x, state, flag;
  2947.     if (!fn) /* Watch out for null pointers. */
  2948.       return(-1);
  2949.     if (!*fn) /* And empty names. */
  2950.       return(-1);
  2951.     flag = state = 0;
  2952.     for (i = (int)strlen(fn) - 1; (!flag && (i > 0)); i--) {
  2953. switch (state) {
  2954.   case 0: /* State 0 - final char */
  2955.     if (fn[i] == '~') /* Is tilde */
  2956.       state = 1; /* Switch to next state */
  2957.     else /* Otherwise */
  2958.       flag = 1; /* Quit - no backup suffix. */
  2959.     break;
  2960.   case 1: /* State 1 - digits */
  2961.     if (fn[i] == '~'  && fn[i-1] == '.') { /* Have suffix */
  2962. return(atoi(&fn[i+1]));
  2963.     } else if (fn[i] >= '0' && fn[i] <= '9') { /* In number part */
  2964. continue; /* Keep going */
  2965.     } else { /* Something else */
  2966. flag = 1; /* Not a backup suffix - quit. */
  2967.     }
  2968.     break;
  2969. }
  2970.     }
  2971.     return(0);
  2972. }
  2973. #endif /* COMMENT */
  2974. /*  Z N E W N  --  Make a new name for the given file  */
  2975. /*
  2976.   Given the name, fn, of a file that already exists, this function builds a
  2977.   new name of the form "<oldname>.~<n>~", where <oldname> is argument name
  2978.   (fn), and <n> is a version number, one higher than any existing version
  2979.   number for that file, up to 99999.  This format is consistent with that used
  2980.   by GNU EMACS.  If the constructed name is too long for the system's maximum,
  2981.   enough characters are truncated from the end of <fn> to allow the version
  2982.   number to fit.  If no free version numbers exist between 1 and 99999, a
  2983.   version number of "xxxx" is used.  Returns a pointer to the new name in
  2984.   argument s.
  2985. */
  2986. #ifdef pdp11
  2987. #define ZNEWNBL 63                      /* Name buffer length */
  2988. #define ZNEWNMD 3                       /* Max digits for version number */
  2989. #else
  2990. #define ZNEWNBL CKMAXPATH
  2991. #define ZNEWNMD 4
  2992. #endif /* pdp11 */
  2993. #define MAXBUDIGITS 5
  2994. VOID
  2995. znewn(fn,s) char *fn, **s; {
  2996.     static char buf[ZNEWNBL+12];        /* Buffer for new name */
  2997.     char * xp, * namepart = NULL;       /* Pointer to filename part */
  2998.     struct zfnfp * fnfp;                /* znfqfp() result struct pointer */
  2999.     int d = 0, t, fnlen, buflen;
  3000.     int n, i, k, x, flag, state;
  3001.     int max = MAXNAMLEN;                /* Maximum name length */
  3002.     char * dname = NULL;
  3003.     *s = NULL;                          /* Initialize return value */
  3004.     if (!fn) fn = "";                   /* Check filename argument */
  3005.     i = strlen(fn);
  3006. /* If incoming file already has a backup suffix, remove it. */
  3007. /* Then we'll tack a new on later, which will be the highest for this file. */
  3008.     if (i <= max && i > 0 && fn[i-1] == '~') {
  3009. char * p;
  3010. i--;
  3011. debug(F111,"znewn suffix removal",fn,i);
  3012. if (dname = (char *)malloc(i+1)) {
  3013.     strcpy(dname,fn);
  3014.     p = dname;
  3015.     for (flag = state = 0; (!flag && (i > 0)); i--) {
  3016. switch (state) {
  3017.   case 0: /* State 0 - final char */
  3018.     if (p[i] == '~') /* Is tilde */
  3019.       state = 1; /* Switch to next state */
  3020.     else /* Otherwise */
  3021.       flag = 1; /* Quit - no backup suffix. */
  3022.     break;
  3023.   case 1: /* State 1 - digits */
  3024.     if (p[i] == '~'  && p[i-1] == '.') { /* Have suffix */
  3025. p[i-1] = NUL; /* Trim it */
  3026. fn = dname;
  3027. debug(F111,"znewn suffix removal 2",fn,i);
  3028. flag = 1; /* done */
  3029.     } else if (p[i] >= '0' && p[i] <= '9') { /* Number part */
  3030. continue; /* Keep going */
  3031.     } else { /* Something else */
  3032. flag = 1; /* Not a backup suffix - quit. */
  3033.     }
  3034.     break;
  3035. }
  3036.     }
  3037. }
  3038.     }
  3039.     if ((fnlen = strlen(fn)) < 1) { /* Get length */
  3040. if (dname) free(dname);
  3041. return;
  3042.     }
  3043.     debug(F111,"znewn",fn,fnlen);
  3044.     debug(F101,"znewn max 1","",max);
  3045.     if (max < 14) max = 14;             /* Make max reasonable for any UNIX */
  3046.     if (max > ZNEWNBL) max = ZNEWNBL;
  3047.     debug(F101,"znewn max 2","",max);
  3048.     if (fnfp = zfnqfp(fn, ZNEWNBL, buf)) { /* Get fully qualified name */
  3049.         namepart = fnfp->fname;         /* Isolate the filename */
  3050.         k = strlen(fn);                 /* Length of name part */
  3051.         debug(F111,"znewn namepart",namepart,k);
  3052.     } else {
  3053. if (dname) free(dname);
  3054. return;
  3055.     }
  3056.     buflen = fnfp->len;                 /* Length of fully qualified name */
  3057.     debug(F111,"znewn len",buf,buflen);
  3058.     if (k + MAXBUDIGITS + 3 < max) {    /* Backup name fits - no overflow */
  3059.         strcpy(buf+buflen,".~*~");      /* Make pattern for backup names */
  3060.         n = nzxpand(buf,ZX_FILONLY);    /* Expand the pattern */
  3061.         debug(F111,"znewn A matches",buf,n);
  3062.         while (n-- > 0) {               /* Find any existing name.~n~ files */
  3063.             xp = *mtchptr++;            /* Point at matching name */
  3064.             t = atoi(xp+buflen+2);      /* Get number */
  3065.             if (t > d) d = t;           /* Save d = highest version number */
  3066.         }
  3067.         sprintf(buf+buflen,".~%d~",d+1); /* Yes, make "name.~<d+1>~" */
  3068.         debug(F110,"znewn A new name",buf,0);
  3069.     } else {                            /* Backup name would be too long */
  3070.         int xlen;                       /* So we have to eat back into it */
  3071.         int delta;
  3072.         char buf2[ZNEWNBL+12];
  3073.         delta = max - k;
  3074.         debug(F101,"znewn B delta","",delta);
  3075.         for (i = MAXBUDIGITS; i > 0; i--) { /* In this case the format of */
  3076.             strcpy(buf2,buf);               /* the backup name depends on */
  3077.             xlen = buflen - i - 3 + delta;  /* how many digits are in the */
  3078.             strcpy(buf2+xlen,".~*~");       /* the backup number... */
  3079.             n = nzxpand(buf2,ZX_FILONLY);
  3080.             debug(F111,"znewn B matches",buf2,n);
  3081.             if (n > 0)
  3082.               break;
  3083.         }
  3084.         while (n-- > 0) {               /* Find any existing name.~n~ files */
  3085.             xp = *mtchptr++;            /* Point at matching name */
  3086.             t = atoi(xp+xlen+2);        /* Get number */
  3087.             if (t > d) d = t;           /* Save d = highest version number */
  3088.         }
  3089.         if (d > 0)                      /* If the odometer turned over... */
  3090.           if ((d % 10) == 9)            /* back up one space. */
  3091.             xlen--;
  3092.         sprintf(buf2+xlen,".~%d~",d+1); /* This just fits */
  3093.         strcpy(buf,buf2);               /* (we could be more clever here...) */
  3094.         debug(F110,"znewn B new name",buf,0);
  3095.     }
  3096.     *s = buf;                           /* Point to new name */
  3097.     ck_znewn = d+1;                     /* Also make it available globally */
  3098.     if (dname) free(dname);
  3099.     return;
  3100. }
  3101. /*  Z R E N A M E  --  Rename a file  */
  3102. /*
  3103.    Call with old and new names.
  3104.    If new name is the name of a directory, the 'old' file is moved to
  3105.    that directory.
  3106.    Returns 0 on success, -1 on failure.
  3107. */
  3108. int
  3109. zrename(old,new) char *old, *new; {
  3110.     char *p = NULL, *s = new;
  3111.     int x;
  3112.     debug(F110,"zrename old",old,0);
  3113.     debug(F110,"zrename new",s,0);
  3114. #ifdef IKSD
  3115. #ifdef CK_LOGIN
  3116.     if (inserver && isguest)
  3117.       return(-1);
  3118. #endif /* CK_LOGIN */
  3119. #endif /* IKSD */
  3120.     if (isdir(new)) {
  3121.         char *q = NULL;
  3122.         x = strlen(new);
  3123.         if (!(p = malloc(strlen(new) + strlen(old) + 2)))
  3124.           return(-1);
  3125.         strcpy(p,new);                  /* Directory part */
  3126.         if (!ISDIRSEP(*(new+x-1)))      /* Separator, if needed */
  3127.           strcat(p,"/");
  3128.         zstrip(old,&q);                 /* Strip path part from old name */
  3129.         strcat(p,q);                    /* Concatenate to new directory */
  3130.         s = p;
  3131.         debug(F110,"zrename dir",s,0);
  3132.     } else debug(F110,"zrename no dir",s,0);
  3133. #ifdef RENAME
  3134. /*
  3135.   Atomic, preferred, uses a single system call, rename(), if available.
  3136.   OS/2 rename() returns nonzero, but not necessarily -1 (?), on failure.
  3137. */
  3138.     x = rename(old,s);
  3139.     if (x) x = -1;
  3140. #else /* !RENAME */
  3141. /*
  3142.   This way has a window of vulnerability.
  3143. */
  3144.     x = -1;                             /* Return code. */
  3145.     if (link(old,s) < 0) {              /* Make a link with the new name. */
  3146.         debug(F111,"zrename link fails, errno",old,errno);
  3147.     } else if (unlink(old) < 0) {       /* Unlink the old name. */
  3148.         debug(F111,"zrename unlink fails, errno",old,errno);
  3149.     } else
  3150.       x = 0;
  3151. #endif /* RENAME */
  3152. #ifdef CKSYSLOG
  3153.     if (ckxsyslog >= SYSLG_FC && ckxlogging) {
  3154.         fullname[0] = '';
  3155.         zfnqfp(old,CKMAXPATH,fullname);
  3156.         tmp2[0] = '';
  3157.         zfnqfp(s,CKMAXPATH,tmp2);
  3158.         if (x)
  3159.           syslog(LOG_INFO,"file[] %s: rename to %s failed (%m)",fullname,tmp2);
  3160.         else
  3161.           syslog(LOG_INFO,"file[] %s: renamed to %s ok", fullname, tmp2);
  3162.     }
  3163. #endif /* CKSYSLOG */
  3164.     if (p) free(p);
  3165.     return(x);
  3166. }
  3167. /*  Z C O P Y  --  Copy a single file. */
  3168. /*
  3169.   Call with source and destination names.
  3170.   If destination is a directory, the source file is
  3171.   copied to that directory with its original name.
  3172.   Returns:
  3173.    0 on success.
  3174.   <0 on failure:
  3175.   -2 = source file is not a regular file.
  3176.   -3 = source file not found.
  3177.   -4 = permission denied.
  3178.   -5 = source and destination are the same file.
  3179.   -6 = i/o error.
  3180.   -1 = other error.
  3181. */
  3182. int
  3183. zcopy(source,destination) char *source, *destination; {
  3184.     char *src = source, *dst = destination; /* Local pointers to filenames */
  3185.     int x, y, rc;                       /* Workers */
  3186.     int in = -1, out = -1;              /* i/o file descriptors */
  3187.     struct stat srcbuf;                 /* Source file info buffer */
  3188.     int perms;                          /* Output file permissions */
  3189.     char buf[1024];                     /* File copying buffer */