home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc095.zip / ckufio.c < prev    next >
C/C++ Source or Header  |  1989-08-31  |  45KB  |  1,568 lines

  1. char *ckzv = "Unix file support, 4E(039) 19 Jun 89";
  2.  
  3. /* C K U F I O  --  Kermit file system support for Unix systems */
  4.  
  5. /*
  6.  Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  7.  Columbia University Center for Computing Activities.
  8.  First released January 1985.
  9.  Copyright (C) 1985, 1989, Trustees of Columbia University in the City of New 
  10.  York.  Permission is granted to any individual or institution to use, copy, or
  11.  redistribute this software so long as it is not sold for profit, provided this
  12.  copyright notice is retained. 
  13. */
  14. /* Includes */
  15.  
  16. #include <sys/types.h>            /* Data types */
  17. #include "ckcker.h"            /* Kermit definitions */
  18. #include "ckcdeb.h"            /* Typedefs, debug formats, etc */
  19. #include <ctype.h>            /* Character types */
  20. #include <stdio.h>            /* Standard i/o */
  21. #include <sys/dir.h>            /* Directory structure */
  22. #include <pwd.h>            /* Password file for shell name */
  23.  
  24. /* File date material */
  25.  
  26. #ifdef BSD4
  27. #define TIMESTAMP
  28. #include <time.h>
  29. #include <sys/timeb.h>
  30. #ifdef NOT_YET
  31. static long timezone;
  32. #endif /* NOT_YET - see comments in front of mktime() below */
  33. #endif /* BSD4 */
  34.  
  35. #ifdef UXIII
  36. #define TIMESTAMP
  37. #include <time.h>
  38. #ifdef NOT_YET
  39. void tzset();
  40. extern long timezone;
  41. #endif /* NOT_YET - see comments in front of mktime() below */
  42. #endif /* uxiii */
  43.  
  44. /* Is `y' a leap year? */
  45. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  46.  
  47. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  48. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  49.  
  50. /* Number of days in each month of the year. */
  51. static char monlens[] =
  52. {
  53.   31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  54. };
  55.  
  56. #ifdef CIE
  57. #include <stat.h>            /* File status */
  58. #else
  59. #include <sys/stat.h>
  60. #endif
  61.  
  62. /* Support for tilde-expansion in file and directory names */
  63.  
  64. #ifdef BSD4
  65. #define NAMEENV "USER"            /* Environment variable for tilde */
  66. #endif /* BSD4 */
  67.  
  68. #ifdef UXIII
  69. #define NAMEENV "LOGNAME"        /* Environment variable for tilde */
  70. #endif /* UXIII */
  71.  
  72. /* Berkeley Unix Version 4.x */
  73. /* 4.1bsd support from Charles E Brooks, EDN-VAX */
  74.  
  75. #ifdef BSD4
  76. #ifdef MAXNAMLEN
  77. #define BSD42
  78. #ifdef BSD43
  79. char *ckzsys = " 4.3 BSD";
  80. #else
  81. #ifdef SUNOS4
  82. char *ckzsys = " SUNOS 4.x";
  83. #else
  84. #ifdef ultrix
  85. char *ckzsys = " VAX/Ultrix";
  86. #else
  87. char *ckzsys = " 4.2 BSD";
  88. #endif /* ultrix */
  89. #endif /* sunos4 */
  90. #endif /* bsd43 */
  91. #else
  92. #ifdef FT18
  93. #define BSD41
  94. char *ckzsys = " Fortune For:Pro 1.8";
  95. #else
  96. #define BSD41
  97. char *ckzsys = " 4.1 BSD";
  98. #endif
  99. #endif
  100. #endif
  101.  
  102. /* 2.9bsd support contributed by Bradley Smith, UCLA */
  103. #ifdef BSD29
  104. char *ckzsys = " 2.9 BSD";
  105. #endif
  106.  
  107. /* Version 7 Unix  */
  108. #ifdef V7
  109. char *ckzsys = " Version 7 Unix";
  110. #endif
  111.  
  112. /* DEC Professional-300 series with Venturcom Venix v1 */
  113. #ifdef PROVX1
  114. char *ckzsys = " DEC Pro-3xx/Venix v1";
  115. #endif
  116.  
  117. /* NCR Tower support contributed by John Bray, Auburn, AL. */
  118. /* Tower OS is like Sys III but with BSD features -- mostly follows BSD. */
  119. #ifdef TOWER1
  120. char *ckzsys = " NCR Tower 1632, OS 1.02";
  121. #endif
  122.  
  123. /* Sys III/V, Xenix, PC/IX,... support by Herm Fischer, Litton Data Systems */
  124. #ifdef UXIII
  125. #ifdef XENIX
  126. #ifdef M_I386
  127. char *ckzsys = " Xenix/386";
  128. #else
  129. #ifdef M_I286
  130. char *ckzsys = " Xenix/286";
  131. #else
  132. #ifdef TRS16
  133. char *ckzsys = " Xenix/68000";
  134. #else
  135. char *ckzsys = " Xenix/86";
  136. #endif
  137. #endif
  138. #endif
  139. #else
  140. #ifdef PCIX
  141. char *ckzsys = " PC/IX";
  142. #else
  143. #ifdef ISIII
  144. char *ckzsys = " Interactive Systems Corp, System III";
  145. #else
  146. #ifdef ZILOG
  147. char *ckzsys = " Zilog S8000 Zeus 3.21+";
  148. #else
  149. #ifndef TRS16
  150. char *ckzsys = " AT&T System III/System V";
  151. #endif
  152. #endif
  153. #endif
  154. #endif
  155. #endif
  156. #endif
  157.  
  158. /* Definitions of some Unix system commands */
  159.  
  160. char *DELCMD = "rm -f ";        /* For file deletion */
  161. char *PWDCMD = "pwd ";            /* For saying where I am */
  162.  
  163. #ifdef FT18
  164. char *DIRCMD = "ls -l | more ";        /* For directory listing */
  165. char *TYPCMD = "more ";            /* For typing a file */
  166. #else
  167. char *TYPCMD = "cat ";            /* For typing a file */
  168. char *DIRCMD = "ls -l ";        /* For directory listing */
  169. #endif
  170.  
  171. #ifdef FT18
  172. #undef BSD4
  173. #endif
  174.  
  175. #ifdef BSD4
  176. char *SPACMD = "pwd ; quota ; df .";    /* Space/quota of current directory */
  177. #else
  178. #ifdef FT18
  179. char #SPACMD = "pwd ; du ; df .";
  180. #else
  181. char *SPACMD = "df ";
  182. #endif
  183. #endif
  184.  
  185. char *SPACM2 = "df ";            /* For space in specified directory */
  186.  
  187. #ifdef FT18
  188. #define BSD4
  189. #endif
  190.  
  191. #ifdef BSD4
  192. char *WHOCMD = "finger ";        /* For seeing who's logged in */
  193. #else
  194. char *WHOCMD = "who ";            /* For seeing who's logged in */
  195. #endif
  196.  
  197. /*
  198.   Functions (n is one of the predefined file numbers from ckermi.h):
  199.  
  200.    zopeni(n,name)   -- Opens an existing file for input.
  201.    zopeno(n,name)   -- Opens a new file for output.
  202.    zclose(n)        -- Closes a file.
  203.    zchin(n,&c)      -- Gets the next character from an input file.
  204.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  205.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  206.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  207.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  208.    zchki(name)      -- Check if named file exists and is readable, return size.
  209.    zchko(name)      -- Check if named file can be created.
  210.    znewn(name,s)    -- Make a new unique file name based on the given name.
  211.    zdelet(name)     -- Delete the named file.
  212.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  213.    znext(string)    -- Returns the next file from the list in "string".
  214.    zxcmd(cmd)       -- Execute the command in a lower fork.
  215.    zclosf()         -- Close input file associated with zxcmd()'s lower fork.
  216.    zrtol(n1,n2)     -- Convert remote filename into local form.
  217.    zltor(n1,n2)     -- Convert local filename into remote form.
  218.    zchdir(dirnam)   -- Change working directory.
  219.    zhome()          -- Return pointer to home directory name string.
  220.    zkself()         -- Kill self, log out own job.
  221.    zsattr(struc zattr *) -- Return attributes for file which is being sent.
  222.  */
  223.  
  224. #ifdef FT18
  225. #define PROVX1
  226. #endif
  227.  
  228. /* Which systems include <sys/file.h>... */
  229. #ifndef PROVX1
  230. #ifndef aegis
  231. #ifndef CIE
  232. #ifndef XENIX
  233. #ifndef unos
  234. /* Watch out, some versions of Xenix might need to do this include, */
  235. /* but reportedly SCO Xenix 2.2 on an 80x86 system does not. */
  236. #include <sys/file.h>            /* File access */
  237. #endif
  238. #endif
  239. #endif
  240. #endif
  241. #endif
  242.  
  243. #ifdef FT18
  244. #undef PROVX1
  245. #endif
  246.  
  247. /* Some systems define these symbols in include files, others don't... */
  248. #ifndef R_OK
  249. #define R_OK 4                /* For access */
  250. #endif
  251.  
  252. #ifndef W_OK
  253. #define W_OK 2
  254. #endif
  255.  
  256. #ifdef PROVX1
  257. #define MAXNAMLEN DIRSIZ        /* Max file name length */
  258. #endif
  259.  
  260. #ifdef UXIII
  261. #include <fcntl.h>
  262. #ifndef MAXNAMLEN
  263. #define MAXNAMLEN DIRSIZ
  264. #endif
  265. #endif
  266.  
  267. #ifndef O_RDONLY
  268. #define O_RDONLY 000
  269. #endif
  270.  
  271. #ifndef MAXNAMLEN
  272. #define MAXNAMLEN 14            /* If still not defined... */
  273. #endif
  274.  
  275. #ifdef PROVX1
  276. #define MAXWLD 50            /* Maximum wildcard filenames */
  277. #else
  278. #ifdef BSD29
  279. #define MAXWLD 50            /* Maximum wildcard filenames */
  280. #else
  281. #define MAXWLD 500
  282. #endif
  283. #endif
  284.  
  285. /* Declarations */
  286.  
  287. FILE *fp[ZNFILS] = {             /* File pointers */
  288.     NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  289.  
  290. /* (PWP) external def. of things used in buffered file input and output */
  291. extern CHAR zinbuffer[], zoutbuffer[];
  292. extern CHAR *zinptr, *zoutptr;
  293. extern int zincnt, zoutcnt;
  294.  
  295. static long iflen = -1;            /* Input file length */
  296. static long oflen = -1;            /* Output file length */
  297.  
  298. static int pid = 0;            /* pid of child fork */
  299. static int fcount;            /* Number of files in wild group */
  300. static char nambuf[MAXNAMLEN+2];    /* Buffer for a filename */
  301. static char zmbuf[200];            /* For mail, remote print strings */
  302. char *malloc(), *getenv(), *strcpy();    /* System functions */
  303. extern errno;                /* System error code */
  304.  
  305. static char *mtchs[MAXWLD],        /* Matches found for filename */
  306.      **mtchptr;                /* Pointer to current match */
  307.  
  308. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  309.  
  310. /* Note, should get current pid, but if your system doesn't have */
  311. /* getppid(), then just kill(0,9)...  */
  312.  
  313. zkself() {                /* For "bye", but no guarantee! */
  314. #ifdef PROVX1
  315.     return(kill(0,9));
  316. #else
  317. #ifdef V7
  318.     return(kill(0,9));
  319. #else
  320. #ifdef TOWER1
  321.     return(kill(0,9));
  322. #else
  323. #ifdef FT18
  324.     return(kill(0,9));
  325. #else
  326. #ifdef aegis
  327.     return(kill(0,9));
  328. #else
  329.     return(kill(getppid(),1));
  330. #endif
  331. #endif
  332. #endif
  333. #endif
  334. #endif
  335. }
  336.  
  337. /*  Z O P E N I  --  Open an existing file for input. */
  338.  
  339. zopeni(n,name) int n; char *name; {
  340.     debug(F111," zopeni",name,n);
  341.     debug(F101,"  fp","",(int) fp[n]);
  342.     if (chkfn(n) != 0) return(0);
  343.     zincnt = 0;                /* Reset input buffer */
  344.     if (n == ZSYSFN) {            /* Input from a system function? */
  345.         debug(F110," invoking zxcmd",name,0);
  346.     *nambuf = '\0';            /* No filename this time... */
  347.     return(zxcmd(name));        /* Try to fork the command */
  348.     }
  349.     if (n == ZSTDIO) {            /* Standard input? */
  350.     if (isatty(0)) {
  351.         ermsg("Terminal input not allowed");
  352.         debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  353.         return(0);
  354.     }
  355.     fp[ZIFILE] = stdin;
  356.     return(1);
  357.     }
  358.     fp[n] = fopen(name,"r");        /* Real file. */
  359.     debug(F111," zopeni", name, (int) fp[n]);
  360.     if (fp[n] == NULL) perror("zopeni");
  361.     return((fp[n] != NULL) ? 1 : 0);
  362. }
  363.  
  364. /*  Z O P E N O  --  Open a new file for output.  */
  365.  
  366. zopeno(n,name) int n; char *name; {
  367.  
  368. /** suid stuff commented out, probably needs work to apply to all the Unix **/
  369. /** variants supported by this program.  Maybe use setreuid()? **/
  370. /** The code shown allegedly works in 4.xBSD, Ultrix, etc.     **/
  371.  
  372. /*  int uid, euid;            /** suid variables...  */
  373.     
  374.     if (n != ZDFILE)
  375.       debug(F111," zopeno",name,n);
  376.     if (chkfn(n) != 0) return(0);
  377.     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
  378.     fp[ZOFILE] = stdout;
  379.     if (n != ZDFILE)
  380.       debug(F101," fp[]=stdout", "", (int) fp[n]);
  381.     zoutcnt = 0;
  382.     zoutptr = zoutbuffer;
  383.     return(1);
  384.     }
  385. /*  uid = getuid(); euid = geteuid();    /** In case running suid to uucp, */
  386. /*  seteuid(uid);            /** etc, get user's own id.  */
  387.     fp[n] = fopen(name,"w");        /* A real file, try to open. */
  388. /*  seteuid(uid);            /** Put back program's suid. */
  389.     if (fp[n] == NULL) {
  390.         perror("zopeno can't open");
  391.     } else {
  392.     chown(name, getuid(), getgid());     /* In case set[gu]id */
  393.         if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
  394.     }
  395.     zoutcnt = 0;        /* (PWP) reset output buffer */
  396.     zoutptr = zoutbuffer;
  397.     if (n != ZDFILE)
  398.       debug(F101, " fp[n]", "", (int) fp[n]);
  399.     return((fp[n] != NULL) ? 1 : 0);
  400. }
  401.  
  402. /*  Z C L O S E  --  Close the given file.  */
  403.  
  404. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  405.  
  406. zclose(n) int n; {
  407.     int x, x2;
  408.     if (chkfn(n) < 1) return(0);    /* Check range of n */
  409.  
  410.     if ((n == ZOFILE) && (zoutcnt > 0))    /* (PWP) output leftovers */
  411.       x2 = zoutdump();
  412.     else
  413.       x2 = 0;
  414.  
  415.     x = 0;                /* Initialize return code */
  416.     if ((n == ZIFILE) && fp[ZSYSFN]) {    /* If system function */
  417.         x = zclosf();            /* do it specially */
  418.     } else {
  419.         if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
  420.     fp[n] = NULL;
  421.     }
  422.     iflen = -1;                /* Invalidate file length */
  423.     if (x == EOF)            /* if we got a close error */
  424.     return (-1);
  425.     else if (x2 < 0)        /* or an error flushing the last buffer */
  426.     return (-1);        /* then return an error */
  427.     else
  428.     return (1);
  429. }
  430.  
  431. /*  Z C H I N  --  Get a character from the input file.  */
  432.  
  433. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  434.  
  435. zchin(n,c) int n; char *c; {
  436.     int a;
  437.  
  438.     /* (PWP) Just in case this gets called when it shoudn't */
  439.     if (n == ZIFILE)
  440.     return (zminchar());
  441.  
  442.     /* if (chkfn(n) < 1) return(-1); */
  443.     a = getc(fp[n]);
  444.     if (a == EOF) return(-1);
  445.     *c = a & 0377;
  446.     return(0);
  447. }
  448.  
  449. /*
  450.  * (PWP) (re)fill the buffered input buffer with data.  All file input
  451.  * should go through this routine, usually by calling the zminchar()
  452.  * macro (in ckcker.h).
  453.  */
  454.  
  455. zinfill() {
  456.     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  457.     if (zincnt == 0) return (-1); /* end of file */
  458.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  459.     zincnt--;            /* one less char in buffer */
  460.     return((int)(*zinptr++) & 0377); /* because we return the first */
  461. }
  462.  
  463. /*  Z S O U T  --  Write a string out to the given file, buffered.  */
  464.  
  465. zsout(n,s) int n; char *s; {
  466.     if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
  467.     fputs(s,fp[n]);
  468.     return(0);
  469. }
  470.  
  471. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  472.  
  473. zsoutl(n,s) int n; char *s; {
  474.     /* if (chkfn(n) < 1) return(-1); */
  475.     fputs(s,fp[n]);
  476.     fputs("\n",fp[n]);
  477.     return(0);
  478. }
  479.  
  480. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  481.  
  482. zsoutx(n,s,x) int n, x; char *s; {
  483.     /* if (chkfn(n) < 1) return(-1); */
  484. /*  return(write(fp[n]->_file,s,x));  */
  485.     return(write(fileno(fp[n]),s,x));
  486. }
  487.  
  488.  
  489. /*  Z C H O U T  --  Add a character to the given file.  */
  490.  
  491. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  492.  
  493. zchout(n,c) register int n; char c; {
  494.     /* if (chkfn(n) < 1) return(-1); */
  495.     if (n == ZSFILE)
  496.         return(write(fileno(fp[n]),&c,1)); /* Use unbuffered for session log */
  497.     else {                /* Buffered for everything else */
  498.     if (putc(c,fp[n]) == EOF)    /* If true, maybe there was an error */
  499.         return(ferror(fp[n])?-1:0);    /* Check to make sure */
  500.     else                /* Otherwise... */
  501.         return(0);            /* There was no error. */
  502.     }
  503. }
  504.  
  505. /* (PWP) buffered character output routine to speed up file IO */
  506.  
  507. zoutdump() {
  508.     int x;
  509.     zoutptr = zoutbuffer;        /* reset buffer pointer in all cases */
  510.     debug(F101,"zoutdump chars","",zoutcnt);
  511.     if (zoutcnt == 0) {            /* nothing to output */
  512.     return(0);
  513.     } else if (zoutcnt < 0) {        /* unexpected negative value */
  514.     zoutcnt = 0;            /* reset output buffer count */
  515.     return(-1);            /* and fail. */
  516.     }
  517.     if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {
  518.     debug(F101,"zoutdump fwrite wrote","",x);
  519.     zoutcnt = 0;            /* reset output buffer count */
  520.     return(0);            /* things worked OK */
  521.     } else {
  522.     zoutcnt = 0;            /* reset output buffer count */
  523.     x = ferror(fp[ZOFILE]);        /* get error code */
  524.     debug(F101,"zoutdump fwrite error","",x);
  525.     return(x ? -1 : 0);        /* return failure if error */
  526.     }
  527. }
  528.  
  529. /*  C H K F N  --  Internal function to verify file number is ok  */
  530.  
  531. /*
  532.  Returns:
  533.   -1: File number n is out of range
  534.    0: n is in range, but file is not open
  535.    1: n in range and file is open
  536. */
  537. chkfn(n) int n; {
  538.     switch (n) {
  539.     case ZCTERM:
  540.     case ZSTDIO:
  541.     case ZIFILE:
  542.     case ZOFILE:
  543.     case ZDFILE:
  544.     case ZTFILE:
  545.     case ZPFILE:
  546.     case ZSFILE:
  547.     case ZSYSFN: break;
  548.     default:
  549.         debug(F101,"chkfn: file number out of range","",n);
  550.         fprintf(stderr,"?File number out of range - %d\n",n);
  551.         return(-1);
  552.     }
  553.     return( (fp[n] == NULL) ? 0 : 1 );
  554. }
  555.  
  556. /*  Z C H K I  --  Check if input file exists and is readable  */
  557.  
  558. /*
  559.   Returns:
  560.    >= 0 if the file can be read (returns the size).
  561.      -1 if file doesn't exist or can't be accessed,
  562.      -2 if file exists but is not readable (e.g. a directory file).
  563.      -3 if file exists but protected against read access.
  564. */
  565. /*
  566.  For Berkeley Unix, a file must be of type "regular" to be readable.
  567.  Directory files, special files, and symbolic links are not readable.
  568. */
  569. long
  570. zchki(name) char *name; {
  571.     struct stat buf;
  572.     int x; long y; 
  573.  
  574.     x = stat(name,&buf);
  575.     if (x < 0) {
  576.     debug(F111,"zchki stat fails",name,errno);
  577.     return(-1);
  578.     }
  579.     x = buf.st_mode & S_IFMT;        /* Isolate file format field */
  580.     if ((x != 0) && (x != S_IFREG)) {
  581.     debug(F111,"zchki skipping:",name,x);
  582.     return(-2);
  583.     }
  584.     debug(F111,"zchki stat ok:",name,x);
  585.  
  586.     if ((x = access(name,R_OK)) < 0) {     /* Is the file accessible? */
  587.     debug(F111," access failed:",name,x); /* No */
  588.         return(-3);            
  589.     } else {
  590.     iflen = buf.st_size;              /* Yes, remember size */
  591.     strncpy(nambuf,name,MAXNAMLEN);          /* and name globally. */
  592.     debug(F111," access ok:",name,(int) iflen);
  593.     return( (iflen > -1) ? iflen : 0 );
  594.     }
  595. }
  596.  
  597. /*  Z C H K O  --  Check if output file can be created  */
  598.  
  599. /*
  600.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  601. */
  602. zchko(name) char *name; {
  603.     int i, x;
  604.     char s[50], *sp;    
  605.  
  606.     sp = s;                /* Make a copy, get length */
  607.     x = 0;
  608.     while ((*sp++ = *name++) != '\0')
  609.         x++;
  610.     if (x == 0) return(-1);        /* If no filename, fail. */
  611.  
  612.     debug(F101," length","",x);
  613.     for (i = x; i > 0; i--)        /* Strip filename. */
  614.     if (s[i-1] == '/') break;
  615.     
  616.     debug(F101," i","",i);
  617.     if (i == 0)                /* If no path, use current directory */
  618.         strcpy(s,"./");            
  619.     else                /* Otherwise, use given one. */
  620.         s[i] = '\0';
  621.  
  622.     x = access(s,W_OK);            /* Check access of path. */
  623.     if (x < 0) {
  624.     debug(F111,"zchko access failed:",s,errno);
  625.     return(-1);
  626.     } else {
  627.     debug(F111,"zchko access ok:",s,x);
  628.     return(0);
  629.     }
  630. }
  631.  
  632. /*  Z D E L E T  --  Delete the named file.  */
  633.  
  634. zdelet(name) char *name; {
  635.     unlink(name);
  636. }
  637.  
  638.  
  639. /*  Z R T O L  --  Convert remote filename into local form  */
  640.  
  641. /*  For UNIX, this means changing uppercase letters to lowercase.  */
  642.  
  643. zrtol(name,name2) char *name, *name2; {
  644.     for ( ; *name != '\0'; name++) {
  645.         *name2++ = isupper(*name) ? tolower(*name) : *name;
  646.     }
  647.     *name2 = '\0';
  648.     debug(F110,"zrtol:",name2,0);
  649. }
  650.  
  651.  
  652. /*  Z L T O R  --  Local TO Remote */
  653.  
  654. /*  Convert filename from local format to common (remote) form.  */
  655.  
  656. zltor(name,name2) char *name, *name2; {
  657.     char work[100], *cp, *pp;
  658.     int dc = 0;
  659. #ifdef aegis
  660.     char *getenv(), *index(), *namechars;
  661.     int tilde = 0, bslash = 0;
  662.  
  663.     if ((namechars = getenv("NAMECHARS")) != NULL) {
  664.         if (index(namechars, '~' ) != NULL) tilde  = '~';
  665.         if (index(namechars, '\\') != NULL) bslash = '\\';
  666.     } else {
  667.         tilde = '~';
  668.         bslash = '\\';
  669.     }
  670. #endif
  671.  
  672.     debug(F110,"zltor",name,0);
  673.     pp = work;
  674. #ifdef aegis
  675.     cp = name;
  676.     if (tilde && *cp == tilde)
  677.         ++cp;
  678.     for (; *cp != '\0'; cp++) {    /* strip path name */
  679.         if (*cp == '/' || *cp == bslash) {
  680. #else
  681.     for (cp = name; *cp != '\0'; cp++) {    /* strip path name */
  682.         if (*cp == '/') {
  683. #endif
  684.         dc = 0;
  685.         pp = work;
  686.     }
  687.     else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
  688.     else if (*cp == '~') *pp++ = 'X';    /* Change tilde to 'X' */
  689.     else if (*cp == '#') *pp++ = 'X';    /* Change number sign to 'X' */
  690.     else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
  691.     else *pp++ = *cp;
  692.     }
  693.     *pp = '\0';                /* Tie it off. */
  694.     cp = name2;                /* If nothing before dot, */
  695.     if (*work == '.') *cp++ = 'X';    /* insert 'X' */
  696.     strcpy(cp,work);
  697.     debug(F110," name2",name2,0);
  698. }    
  699.  
  700.  
  701. /*  Z C H D I R  --  Change directory  */
  702.  
  703. zchdir(dirnam) char *dirnam; {
  704.     char *hd;
  705.     if (*dirnam == '\0') hd = getenv("HOME");
  706.     else hd = dirnam;
  707.     return((chdir(hd) == 0) ? 1 : 0);
  708. }
  709.  
  710.  
  711. /*  Z H O M E  --  Return pointer to user's home directory  */
  712.  
  713. char *
  714. zhome() {
  715.     return(getenv("HOME"));
  716. }
  717.  
  718. /*  Z G T D I R  --  Return pointer to user's current directory  */
  719.  
  720. char *
  721. zgtdir() {
  722.  
  723. #ifdef MAXPATHLEN
  724. #define CWDBL MAXPATHLEN
  725. #else
  726. #define CWDBL 100
  727. #endif
  728.  
  729. #ifdef UXIII
  730.     char cwdbuf[CWDBL+1];
  731.     char *buf;
  732.     char *getcwd();
  733.     buf = cwdbuf;
  734.     return(getcwd(buf,CWDBL));
  735. #else
  736. #ifdef BSD4
  737.     char cwdbuf[CWDBL+1];
  738.     char *buf;
  739.     char *getwd();
  740.     buf = cwdbuf;
  741.     return(getwd(buf));
  742. #else
  743.     return("(directory unknown)");
  744. #endif
  745. #endif
  746. }
  747.  
  748. /*  Z X C M D -- Run a system command so its output can be read like a file */
  749.  
  750. zxcmd(comand) char *comand; {
  751.     int pipes[2];
  752.     if (pipe(pipes) != 0) {
  753.     debug(F100,"zxcmd pipe failure","",0);
  754.     return(0);            /* can't make pipe, fail */
  755.     }
  756. #ifdef aegis
  757.     if ((pid = vfork()) == 0) {        /* child */
  758. #else
  759.     if ((pid = fork()) == 0) {        /* child */
  760. #endif
  761.  
  762.  
  763. /*#if BSD4*/        /* Code from Dave Tweten@AMES-NAS */
  764.             /* readapted to use getpwuid to find login shell */
  765.             /*   -- H. Fischer */
  766.     char *shpath, *shname, *shptr;    /* to find desired shell */
  767. #ifndef aegis
  768.     struct passwd *p;
  769.     extern struct passwd * getpwuid();
  770.     extern int getuid();
  771.     char *defShel = "/bin/sh";    /* default shell */
  772. #endif
  773.  
  774.     close(pipes[0]);        /* close input side of pipe */
  775.     close(0);            /* close stdin */
  776.     if (open("/dev/null",0) < 0) return(0);    /* replace input by null */
  777.  
  778. #ifndef UXIII
  779.     dup2(pipes[1],1);        /* replace stdout & stderr */
  780.     dup2(pipes[1],2);        /* by the pipe */
  781. #else
  782.     close(1);            /* simulate dup2 */
  783.     if (dup(pipes[1]) != 1 )
  784.         conol("trouble duping stdout in routine zxcmd\n");
  785.     close(2);            /* simulate dup2 */
  786.     if (dup(pipes[1]) != 2 )
  787.         conol("trouble duping stderr in routine zxcmd\n");
  788. #endif
  789.  
  790.     close(pipes[1]);        /* get rid of this copy of the pipe */
  791.  
  792. #ifdef aegis
  793.     if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh";
  794. #else
  795.     shpath = getenv("SHELL");    /* What shell? */
  796.     if (shpath == NULL) {
  797.       p = getpwuid( getuid() );    /* get login data */
  798.       if (p == (struct passwd *) NULL || !*(p->pw_shell)) shpath = defShel;
  799.       else shpath = p->pw_shell;
  800.         }
  801. #endif
  802.     shptr = shname = shpath;
  803.     while (*shptr != '\0') if (*shptr++ == '/') shname = shptr;
  804.     debug(F100,"zxcmd...","",0);
  805.     debug(F110,shpath,shname,0);
  806.  
  807. /* Remove the following uid calls if they cause trouble... */
  808. #ifdef BSD4
  809. #ifndef BSD41
  810.     setegid(getgid());        /* Override 4.3BSD csh */
  811.     seteuid(getuid());        /*  security checks */
  812. #endif /* bsd41 */
  813. #endif /* bsd4 */
  814.  
  815.     execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
  816.     exit(0);            /* just punt if it failed. */
  817.     } else if (pid == -1) {
  818.     debug(F100,"zxcmd fork failure","",0);
  819.     return(0);
  820.     }
  821.     close(pipes[1]);            /* don't need the output side */
  822.     fp[ZIFILE] = fdopen(pipes[0],"r");    /* open a stream for it */
  823.     fp[ZSYSFN] = fp[ZIFILE];        /* Remember. */
  824.     return(1);
  825. }
  826.  
  827. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  828.  
  829. zclosf() {
  830.     int wstat;
  831.     if (pid != 0) {
  832.     debug(F101,"zclosf pid =","",pid);
  833.     kill(pid,9);
  834.         while ((wstat = wait((int *)0)) != pid && wstat != -1) ;
  835.         pid = 0;
  836.     }
  837.     fclose(fp[ZIFILE]);
  838.     fp[ZIFILE] = fp[ZSYSFN] = NULL;
  839.     return(1);
  840. }
  841.  
  842. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  843. /*
  844.   Returns the number of files that match fn1, with data structures set up
  845.   so that first file (if any) will be returned by the next znext() call.
  846. */
  847. zxpand(fn) char *fn; {
  848.     fcount = fgen(fn,mtchs,MAXWLD);    /* Look up the file. */
  849.     if (fcount > 0) {
  850.     mtchptr = mtchs;        /* Save pointer for next. */
  851.     }
  852.     debug(F111,"zxpand",mtchs[0],fcount);
  853.     return(fcount);
  854. }
  855.  
  856.  
  857. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  858. /*
  859.  Returns >0 if there's another file, with its name copied into the arg string,
  860.  or 0 if no more files in list.
  861. */
  862. znext(fn) char *fn; {
  863.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  864.     else *fn = '\0';
  865.     debug(F111,"znext",fn,fcount+1);
  866.     return(fcount+1);
  867. }
  868.  
  869.  
  870. /*  Z N E W N  --  Make a new name for the given file  */
  871.  
  872. znewn(fn,s) char *fn, **s; {
  873. #ifdef BSD4
  874.     static char buf[256];
  875. #else
  876.     static char buf[100];
  877. #endif
  878.     char *bp, *xp;
  879.     int len = 0, n = 0, d = 0, t, i, power = 1;
  880. #ifdef MAXNAMLEN
  881.     int max = MAXNAMLEN;
  882. #else
  883.     int max = 14;
  884. #endif
  885.     bp = buf;
  886.     while (*fn) {            /* Copy name into buf */
  887.     *bp++ = *fn++;
  888.     len++;
  889.     }
  890.     if (len > max-2) {             /* Don't let it get too long */
  891.     bp = buf + max-2;
  892.     len = max - 2;
  893.     }
  894.     
  895.     for (i = 1; i < 4; i++) {        /* Try up to 999 times */
  896.     power *= 10;
  897.     *bp++ = '*';            /* Put a star on the end */
  898.     *bp-- = '\0';
  899.     
  900.     n = zxpand(buf);        /* Expand the resulting wild name */
  901.     
  902.     while (n-- > 0) {        /* Find any existing name~d files */
  903.         xp = *mtchptr++;
  904.         xp += len;
  905.         if (*xp == '~') {
  906.         t = atoi(xp+1);
  907.         if (t > d) d = t;    /* Get maximum d */
  908.         }
  909.     }
  910.     if (d < power-1) {
  911.         sprintf(bp,"~%d",d+1);    /* Make name~(d+1) */
  912.         *s = buf;
  913.         return;
  914.     }
  915.     bp--; len--;
  916.     }
  917. /* If we ever get here, we'll overwrite the xxx~100 file... */
  918. }
  919.  
  920. /*  Z S A T T R */
  921. /*
  922.  Fills in a Kermit file attribute structure for the file which is to be sent.
  923.  Returns 0 on success with the structure filled in, or -1 on failure.
  924.  If any string member is null, then it should be ignored.
  925.  If any numeric member is -1, then it should be ignored.
  926. */
  927. zsattr(xx) struct zattr *xx; {
  928.     long k;
  929.     char *zfcdat();
  930.  
  931.     k = iflen % 1024L;            /* File length in K */
  932.     if (k != 0L) k = 1L;
  933.     xx->lengthk = (iflen / 1024L) + k;
  934.     xx->type.len = 0;            /* File type can't be filled in here */
  935.     xx->type.val = "";
  936. debug(F110,"before calling zfcdat",nambuf,0);
  937.     if (nambuf) {
  938.     xx->date.val = zfcdat(nambuf);    /* File creation date */
  939.     xx->date.len = strlen(xx->date.val);
  940.     } else {
  941.     xx->date.len = 0;
  942.     xx->date.val = "";
  943.     }
  944. debug(F111,"attr date",xx->date.val,xx->date.len);
  945.     xx->creator.len = 0;        /* File creator */
  946.     xx->creator.val = "";
  947.     xx->account.len = 0;        /* File account */
  948.     xx->account.val = "";
  949.     xx->area.len = 0;            /* File area */
  950.     xx->area.val = "";
  951.     xx->passwd.len = 0;            /* Area password */
  952.     xx->passwd.val = "";
  953.     xx->blksize = -1L;            /* File blocksize */
  954.     xx->access.len = 0;            /* File access */
  955.     xx->access.val = "";
  956.     xx->encoding.len = 0;        /* Transfer syntax */
  957.     xx->encoding.val = 0;
  958.     xx->disp.len = 0;            /* Disposition upon arrival */
  959.     xx->disp.val = "";
  960.     xx->lprotect.len = 0;        /* Local protection */
  961.     xx->lprotect.val = "";
  962.     xx->gprotect.len = 0;        /* Generic protection */
  963.     xx->gprotect.val = "";
  964.     xx->systemid.len = 2;        /* System ID */
  965.     xx->systemid.val = "U1";
  966.     xx->recfm.len = 0;            /* Record format */
  967.     xx->recfm.val = "";
  968.     xx->sysparam.len = 0;        /* System-dependent parameters */
  969.     xx->sysparam.val = "";
  970.     xx->length = iflen;            /* Length */
  971.     return(0);
  972. }
  973.  
  974. /* Z F C D A T -- Return a string containing the time stamp for a file */
  975.  
  976. char *
  977. zfcdat(name) char *name; {
  978.  
  979. #ifdef TIMESTAMP
  980.  
  981.     struct stat buffer;
  982.     struct tm *time_stamp, *localtime();
  983.     static char datbuf[20];
  984.  
  985.     datbuf[0] = '\0';
  986.     if(stat(name,&buffer) != 0) {
  987.     debug(F110,"zcfdat stat failed",name,0);
  988.     return("");
  989.     }
  990.     time_stamp = localtime(&(buffer.st_mtime));
  991.     if (time_stamp->tm_year < 1900) time_stamp->tm_year += 1900;
  992.     sprintf(datbuf,"%-4.4d%02.2d%02.2d %002.2d:%002.2d:%002.2d",
  993.         time_stamp->tm_year,
  994.         time_stamp->tm_mon + 1,
  995.         time_stamp->tm_mday,
  996.         time_stamp->tm_hour,
  997.         time_stamp->tm_min,
  998.         time_stamp->tm_sec);
  999.     debug(F111,"zcfdat",datbuf,strlen(datbuf));
  1000.     return(datbuf);
  1001. #else
  1002.     return("");
  1003. #endif /* TIMESTAMP */
  1004. }
  1005.  
  1006. #ifdef NOT_YET
  1007. /*
  1008.   Don't try this yet.  Apparently, the definition of timezone is a big
  1009.   problem.  Every computer I looked at deals with it in a different way.
  1010.   On the SUN with SUNOS 4.0, you have to declare it yourself.  On a VAX
  1011.   with Ultrix, it's declared in <time.h> as "char * timezone()" for BSD,
  1012.   or as "extern long timezone" for System V.  So to use this, it looks
  1013.   like we'll need an #ifdef per system, OS version, etc.
  1014. */  
  1015. /*
  1016.   ANSI C mktime for Unix
  1017.   by David MacKenzie <edf@rocky2.rockefeller.edu>
  1018.   and Michael Haertel <mike@stolaf.edu>
  1019.   08/09/89
  1020.  
  1021.   Convert the exploded time structure `tm', containing a local
  1022.   time and date, into the number of seconds past Jan 1, 1970 GMT.
  1023.   Sets `tm->tm_yday' and `tm->tm_wday' correctly, but
  1024.   doesn't set `tm->tm_isdst'.
  1025.   Doesn't return -1 if passed invalid values.
  1026. */
  1027. #ifdef TIMESTAMP
  1028. time_t
  1029. mktime (tm) struct tm *tm; {
  1030.     int years, months, days, hours, minutes, seconds;
  1031.  
  1032. #ifdef ANYBSD
  1033.     struct timeb *tbp;
  1034.  
  1035.     ftime(tbp);
  1036.     timezone = tbp->timezone * 60;
  1037.     if (tbp->dstflag)
  1038.       timezone -= 3600;
  1039. #endif
  1040.  
  1041. #ifdef UXIII
  1042.     tzset ();                /* Set `timezone'. */
  1043. #endif
  1044.  
  1045.     years = tm->tm_year + 1900;        /* year - 1900 -> year */
  1046.     months = tm->tm_mon;        /* 0..11 */
  1047.     days = tm->tm_mday - 1;        /* 1..31 -> 0..30 */
  1048.     hours = tm->tm_hour;        /* 0..23 */
  1049.     minutes = tm->tm_min;        /* 0..59 */
  1050.     seconds = tm->tm_sec;        /* 0..59 */
  1051.  
  1052.     /* Set `days' to the number of days into the year. */
  1053.     if (months > 1 && leap (years))
  1054.       ++days;
  1055.     while (months-- > 0)
  1056.       days += monlens[months];
  1057.     tm->tm_yday = days;
  1058.  
  1059.     /* Now set `days' to the number of days since Jan 1, 1970. */
  1060.     days += 365 * (years - 1970) + nleap (years);
  1061.     tm->tm_wday = (days + 4) % 7;    /* Jan 1, 1970 was Thursday. */
  1062.  
  1063.     return 86400 * days + 3600 * hours + 60 * minutes + seconds + timezone;
  1064. }
  1065. #endif /* TIMESTAMP */
  1066. #endif /* NOT_YET */
  1067.  
  1068. /* Find initialization file. */
  1069.  
  1070. zkermini() {
  1071. /*  nothing here for Unix.  This function added for benefit of VMS Kermit.  */
  1072.     return(0);
  1073. }
  1074.  
  1075. zmail(p,f) char *p; char *f; {        /* Send file f as mail to address p */
  1076.  
  1077. #ifdef BSD4
  1078. /* The idea is to use /usr/ucb/mail, rather than regular mail, so that   */
  1079. /* a subject line can be included with -s.  Since we can't depend on the */
  1080. /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
  1081. /* and even if Mail has been moved to somewhere else, this should still  */
  1082. /* find it... But there really should be a better way... */
  1083.  
  1084. /* Should also make some check on zmbuf overflow... */
  1085.  
  1086.     sprintf(zmbuf,"Mail -s %cfile %s%c %s < %s", '"', f, '"', p, f);
  1087.     system(zmbuf);
  1088. #else
  1089. #ifdef UXIII
  1090.     sprintf(zmbuf,"mail %s < %s", p, f);
  1091.     system(zmbuf);
  1092. #else
  1093.     *zmbuf = '\0';
  1094. #endif
  1095. #endif    
  1096.     return(0);
  1097. }
  1098.  
  1099. zprint(p,f) char *p; char *f; {        /* Print file f with options p */
  1100.  
  1101. #ifdef BSD4
  1102.     sprintf(zmbuf,"lpr %s %s", p, f); /* Construct print command */
  1103.     system(zmbuf);
  1104. #else
  1105. #ifdef UXIII
  1106.     sprintf(zmbuf,"lp %s %s", p, f);
  1107.     system(zmbuf);    
  1108. #else
  1109.     *zmbuf = '\0';
  1110. #endif
  1111. #endif
  1112.     return(0);
  1113. }
  1114.  
  1115.  
  1116. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  1117.  
  1118. /*
  1119.  * The path structure is used to represent the name to match.
  1120.  * Each slash-separated segment of the name is kept in one
  1121.  * such structure, and they are linked together, to make
  1122.  * traversing the name easier.
  1123.  */
  1124.  
  1125. struct path {
  1126.               char npart[MAXNAMLEN];    /* name part of path segment */
  1127.               struct path *fwd;        /* forward ptr */
  1128.             };
  1129.  
  1130. #ifdef PROVX1
  1131. #define SSPACE 500
  1132. #else
  1133. #ifdef BSD29
  1134. #define SSPACE 500
  1135. #else
  1136. #ifdef aegis
  1137. #define SSPACE 10000            /* size of string-generating buffer */
  1138. static char bslash;            /* backslash character if active */
  1139. #else
  1140. #define SSPACE 2000            /* size of string-generating buffer */
  1141. #endif
  1142. #endif
  1143. #endif
  1144. static char sspace[SSPACE];             /* buffer to generate names in */
  1145. static char *freeptr,**resptr;             /* copies of caller's arguments */
  1146. static int remlen;                      /* remaining length in caller's array*/
  1147. static int numfnd;                      /* number of matches found */
  1148.  
  1149. /*
  1150.  * splitpath:
  1151.  *  takes a string and splits the slash-separated portions into
  1152.  *  a list of path structures.  Returns the head of the list.  The
  1153.  *  structures are allocated by malloc, so they must be freed.
  1154.  *  Splitpath is used internally by the filename generator.
  1155.  *
  1156.  * Input: A string.
  1157.  * Returns: A linked list of the slash-separated segments of the input.
  1158.  */
  1159.  
  1160. struct path *
  1161. splitpath(p)
  1162. char *p;
  1163. {
  1164.  struct path *head,*cur,*prv;
  1165.  int i;
  1166.  head = prv = NULL;
  1167.  if (*p == '/') p++;            /* skip leading slash */
  1168.  while (*p != '\0')
  1169.  {
  1170.    cur = (struct path *) malloc(sizeof (struct path));
  1171.    debug(F101,"splitpath malloc","",cur);
  1172.    if (cur == NULL) fatal("malloc fails in splitpath()");
  1173.    cur -> fwd = NULL;
  1174.    if (head == NULL) head = cur;
  1175.    else prv -> fwd = cur;       /* link into chain */
  1176.    prv = cur;
  1177. #ifdef aegis
  1178.    /* treat backslash as "../" */
  1179.    if (bslash && *p == bslash) {
  1180.      strcpy(cur->npart, "..");
  1181.      ++p;
  1182.    } else {
  1183.      for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
  1184.        cur -> npart[i] = *p++;
  1185.      cur -> npart[i] = '\0';      /* end this segment */
  1186.      if (i >= MAXNAMLEN) while (*p && *p != '/' && *p != bslash) p++;
  1187.    }
  1188.    if (*p == '/') p++;
  1189. #else
  1190.    for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
  1191.      cur -> npart[i] = *p++;
  1192.    cur -> npart[i] = '\0';      /* end this segment */
  1193.    if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
  1194.    if (*p == '/') p++;
  1195. #endif
  1196.  }
  1197.  return(head);
  1198. }
  1199.  
  1200. /*
  1201.  * fgen:
  1202.  *  This is the actual name generator.  It is passed a string,
  1203.  *  possibly containing wildcards, and an array of character pointers.
  1204.  *  It finds all the matching filenames and stores them into the array.
  1205.  *  The returned strings are allocated from a static buffer local to
  1206.  *  this module (so the caller doesn't have to worry about deallocating
  1207.  *  them); this means that successive calls to fgen will wipe out
  1208.  *  the results of previous calls.  This isn't a problem here
  1209.  *  because we process one wildcard string at a time.
  1210.  *
  1211.  * Input: a wildcard string, an array to write names to, the
  1212.  *        length of the array.
  1213.  * Returns: the number of matches.  The array is filled with filenames
  1214.  *          that matched the pattern.  If there wasn't enough room in the
  1215.  *        array, -1 is returned.
  1216.  * By: Jeff Damens, CUCCA, 1984.
  1217.  */
  1218.  
  1219. fgen(pat,resarry,len)
  1220. char *pat,*resarry[];
  1221. int len;
  1222. {
  1223.  struct path *head;
  1224.  char scratch[100],*sptr;
  1225. #ifdef aegis
  1226.  char *getenv(), *index(), *namechars;
  1227.  int tilde = 0, bquote = 0;
  1228.  
  1229.  if ((namechars = getenv("NAMECHARS")) != NULL) {
  1230.   if (index(namechars, '~' ) != NULL) tilde  = '~';
  1231.   if (index(namechars, '\\') != NULL) bslash = '\\';
  1232.   if (index(namechars, '`' ) != NULL) bquote = '`';
  1233.  }
  1234.  else { tilde = '~'; bslash = '\\'; bquote = '`'; }
  1235.  
  1236.  sptr = scratch;
  1237.  /* copy "`node_data", etc. anchors */
  1238.  if (bquote && *pat == bquote)
  1239.   while (*pat && *pat != '/' && *pat != bslash)
  1240.    *sptr++ = *pat++;
  1241.  else if (tilde && *pat == tilde)
  1242.   *sptr++ = *pat++;
  1243.  while (*pat == '/')
  1244.   *sptr++ = *pat++;
  1245.  if (sptr == scratch)
  1246.  {
  1247.   strcpy(scratch,"./");
  1248.   sptr = scratch+2;
  1249.  }                    /* init buffer correctly */
  1250.  head = splitpath(pat);
  1251. #else
  1252.  head = splitpath(pat);
  1253.  if (*pat == '/')
  1254.  {
  1255.   scratch[0] = '/';
  1256.   sptr = scratch+1;
  1257.  }
  1258.  else
  1259.  {
  1260.   strcpy(scratch,"./");
  1261.   sptr = scratch+2;
  1262.  }                    /* init buffer correctly */
  1263. #endif
  1264.  numfnd = 0;                            /* none found yet */
  1265.  freeptr = sspace;            /* this is where matches are copied */
  1266.  resptr = resarry;            /* static copies of these so*/
  1267.  remlen = len;                /* recursive calls can alter them */
  1268.  traverse(head,scratch,sptr);        /* go walk the directory tree */
  1269.  for (; head != NULL; head = head -> fwd)
  1270.    free(head);                /* return the path segments */
  1271.  return(numfnd);            /* and return the number of matches */
  1272. }
  1273.  
  1274. /* traverse:
  1275.  *  Walks the directory tree looking for matches to its arguments.
  1276.  *  The algorithm is, briefly:
  1277.  *   If the current pattern segment contains no wildcards, that
  1278.  *   segment is added to what we already have.  If the name so far
  1279.  *   exists, we call ourselves recursively with the next segment
  1280.  *   in the pattern string; otherwise, we just return.
  1281.  *
  1282.  *   If the current pattern segment contains wildcards, we open the name
  1283.  *   we've accumulated so far (assuming it is really a directory), then read
  1284.  *   each filename in it, and, if it matches the wildcard pattern segment, add
  1285.  *   that filename to what we have so far and call ourselves recursively on the
  1286.  *   next segment.
  1287.  *
  1288.  *   Finally, when no more pattern segments remain, we add what's accumulated
  1289.  *   so far to the result array and increment the number of matches.
  1290.  *
  1291.  * Input: a pattern path list (as generated by splitpath), a string
  1292.  *      pointer that points to what we've traversed so far (this
  1293.  *      can be initialized to "/" to start the search at the root
  1294.  *      directory, or to "./" to start the search at the current
  1295.  *      directory), and a string pointer to the end of the string
  1296.  *      in the previous argument.
  1297.  * Returns: nothing.
  1298.  */
  1299. traverse(pl,sofar,endcur)
  1300. struct path *pl;
  1301. char *sofar,*endcur;
  1302. {
  1303. #ifdef BSD42
  1304.  DIR *fd, *opendir();
  1305.  struct direct *dirbuf;
  1306. #else
  1307. #ifdef BSD29
  1308.  DIR *fd, *opendir();
  1309.  struct direct *dirbuf;
  1310. #else
  1311.  int fd;
  1312.  struct direct dir_entry;
  1313.  struct direct *dirbuf = &dir_entry;
  1314. #endif
  1315. #endif
  1316.  struct stat statbuf;
  1317.  if (pl == NULL)
  1318.  {
  1319.   *--endcur = '\0';                    /* end string, overwrite trailing / */
  1320.   addresult(sofar);
  1321.   return;
  1322.  }
  1323.  if (!iswild(pl -> npart))
  1324.  {
  1325.   strcpy(endcur,pl -> npart);
  1326.   endcur += strlen(pl -> npart);
  1327.   *endcur = '\0';                         /* end current string */
  1328.   if (stat(sofar,&statbuf) == 0)    /* if current piece exists */
  1329.   {
  1330.       *endcur++ = '/';                  /* add slash to end */
  1331.       *endcur = '\0';            /* and end the string */
  1332.       traverse(pl -> fwd,sofar,endcur);
  1333.   }
  1334.   return;
  1335.  }
  1336. /* cont'd... */
  1337.  
  1338. /*...traverse, cont'd */
  1339.  
  1340. /* segment contains wildcards, have to search directory */
  1341.  *endcur = '\0';                            /* end current string */
  1342.  if (stat(sofar,&statbuf) == -1) return;       /* doesn't exist, forget it */
  1343.  if ((statbuf.st_mode & S_IFDIR) == 0) return;  /* not a directory, skip */
  1344. #ifdef BSD42            /* ==BSD4 */
  1345.  if ((fd = opendir(sofar)) == NULL) return;      /* can't open, forget it */
  1346.  while (dirbuf = readdir(fd))
  1347. #else
  1348. #ifdef BSD29            /* ==BSD29 */
  1349.  if ((fd = opendir(sofar)) == NULL) return;      /* can't open, forget it */
  1350.  while (dirbuf = readdir(fd))
  1351. #else
  1352.  
  1353.  if ((fd = open(sofar,O_RDONLY)) < 0) return;      /* can't open, forget it */
  1354.  while ( read(fd,dirbuf,sizeof dir_entry) )
  1355. #endif
  1356. #endif
  1357. {
  1358.   strncpy(nambuf,dirbuf->d_name,MAXNAMLEN); /* Get a null terminated copy!!! */
  1359.   nambuf[MAXNAMLEN] = '\0';
  1360. #ifdef unos  
  1361.   if (dirbuf->d_ino != -1 && match(pl -> npart,nambuf)) {
  1362. #else
  1363.   if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) {
  1364. #endif
  1365.     char *eos;
  1366.     strcpy(endcur,nambuf);
  1367.     eos = endcur + strlen(nambuf);
  1368.     *eos = '/';                    /* end this segment */
  1369.     traverse(pl -> fwd,sofar,eos+1);
  1370.   }
  1371. }
  1372. #ifdef BSD42            /* ==BSD4 */
  1373.  closedir(fd);
  1374. #else
  1375. #ifdef BSD29
  1376.  closedir(fd);
  1377. #else
  1378.  close(fd);
  1379. #endif
  1380. #endif
  1381. }
  1382.  
  1383. /*
  1384.  * addresult:
  1385.  *  Adds a result string to the result array.  Increments the number
  1386.  *  of matches found, copies the found string into our string
  1387.  *  buffer, and puts a pointer to the buffer into the caller's result
  1388.  *  array.  Our free buffer pointer is updated.  If there is no
  1389.  *  more room in the caller's array, the number of matches is set to -1.
  1390.  * Input: a result string.
  1391.  * Returns: nothing.
  1392.  */
  1393.  
  1394. addresult(str)
  1395. char *str;
  1396. {
  1397.  int l;
  1398.  if (strncmp(str,"./",2) == 0) str += 2;
  1399.  if (--remlen < 0) {
  1400.   numfnd = -1;
  1401.   return;
  1402.  }
  1403.  l = strlen(str) + 1;            /* size this will take up */
  1404.  if ((freeptr + l) > &sspace[SSPACE-1]) {
  1405.     numfnd = -1;            /* do not record if not enough space */
  1406.     return;
  1407.   }
  1408.  strcpy(freeptr,str);
  1409.  *resptr++ = freeptr;
  1410.  freeptr += l;
  1411.  numfnd++;
  1412. }
  1413.  
  1414. iswild(str)
  1415. char *str;
  1416. {
  1417.  char c;
  1418.  while ((c = *str++) != '\0')
  1419.    if (c == '*' || c == '?') return(1);
  1420.  return(0);
  1421. }
  1422.  
  1423. /*
  1424.  * match:
  1425.  *  pattern matcher.  Takes a string and a pattern possibly containing
  1426.  *  the wildcard characters '*' and '?'.  Returns true if the pattern
  1427.  *  matches the string, false otherwise.
  1428.  * by: Jeff Damens, CUCCA
  1429.  *
  1430.  * Input: a string and a wildcard pattern.
  1431.  * Returns: 1 if match, 0 if no match.
  1432.  */
  1433.  
  1434. match(pattern,string) char *pattern,*string; {
  1435.     char *psave,*ssave;            /* back up pointers for failure */
  1436.     psave = ssave = NULL;
  1437.     while (1) {
  1438.     for (; *pattern == *string; pattern++,string++)  /* skip first */
  1439.         if (*string == '\0') return(1);    /* end of strings, succeed */
  1440.     if (*string != '\0' && *pattern == '?') {
  1441.         pattern++;            /* '?', let it match */
  1442.         string++;
  1443.     } else if (*pattern == '*') {    /* '*' ... */
  1444.         psave = ++pattern;        /* remember where we saw it */
  1445.         ssave = string;        /* let it match 0 chars */
  1446.     } else if (ssave != NULL && *ssave != '\0') {    /* if not at end  */
  1447.                       /* ...have seen a star */
  1448.         string = ++ssave;        /* skip 1 char from string */
  1449.         pattern = psave;        /* and back up pattern */
  1450.     } else return(0);        /* otherwise just fail */
  1451.     }
  1452. }
  1453.  
  1454. /* The following two functions are for expanding tilde in filenames */
  1455. /* Contributed by Howie Kaye, CUCCA, developed for CCMD package. */
  1456. /* 
  1457.  
  1458. /* 
  1459.  * WHOAMI:
  1460.  * 1) Get real uid
  1461.  * 2) See if the $USER environment variable is set ($LOGNAME on AT&T)
  1462.  * 3) If $USER's uid is the same as realuid, realname is $USER
  1463.  * 4) Otherwise get logged in user's name
  1464.  * 5) If that name has the same uid as the real uid realname is loginname
  1465.  * 6) Otherwise, get a name for realuid from /etc/passwd
  1466.  */
  1467.  
  1468. char *
  1469. whoami () {
  1470. #ifdef DTILDE
  1471.   static char realname[256];        /* user's name */
  1472.   static int realuid = -1;        /* user's real uid */
  1473.   char loginname[256], envname[256];    /* temp storage */
  1474.   char *getlogin(), *getenv(), *c;
  1475.   struct passwd *p, *getpwnam(), *getpwuid(), *getpwent();
  1476.  
  1477.   if (realuid != -1)
  1478.     return(realname);
  1479.  
  1480.   realuid = getuid ();            /* get our uid */
  1481.  
  1482.   /* how about $USER or $LOGNAME? */
  1483.   if ((c = getenv(NAMEENV)) != NULL) {    /* check the env variable */
  1484.     strcpy (envname, c);        
  1485.     p = getpwnam(envname);
  1486.     if (p->pw_uid == realuid) {        /* get passwd entry */
  1487.                     /* for envname */
  1488.       strcpy (realname, envname);    /* if the uid's are the same */
  1489.       return(realname);
  1490.     }
  1491.   }
  1492.  
  1493.   /* can we use loginname() ? */
  1494.   if ((c =  getlogin()) != NULL) {    /* name from utmp file */
  1495.     strcpy (loginname, c);    
  1496.     if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
  1497.       if (p->pw_uid == realuid) {    /* for loginname */ 
  1498.     strcpy (realname, loginname);    /* if the uid's are the same */
  1499.     return(realname);
  1500.       }
  1501.   }
  1502.  
  1503.   /* Use first name we get for realuid */
  1504.   if ((p = getpwuid(realuid)) == NULL) { /* name for uid */
  1505.     realname[0] = '\0';            /* no user name */
  1506.     realuid = -1;
  1507.     return(NULL);
  1508.   }
  1509.   strcpy (realname, p->pw_name);    
  1510.   return(realname);
  1511. #else
  1512.   return(NULL);
  1513. #endif /* dtilde */
  1514. }
  1515.  
  1516. /*
  1517.  * expand ~user to the user's home directory.
  1518.  */
  1519.  
  1520. #define DIRSEP '/'
  1521.  
  1522. char *
  1523. tilde_expand(dirname) char *dirname; {
  1524. #define BUFLEN 256
  1525. #ifdef DTILDE
  1526.   struct passwd *user, *getpwuid(), *getpwnam();
  1527.   static char olddir[BUFLEN];
  1528.   static char oldrealdir[BUFLEN];
  1529.   static char temp[BUFLEN];
  1530.   int i, j;
  1531.   char *whoami();
  1532.  
  1533.   debug(F111,"tilde_expand dirname",dirname,dirname[0]);
  1534.  
  1535.   if (dirname[0] != '~') return(dirname); /* not a tilde...return param */
  1536.   if (!strcmp(olddir,dirname)) return(oldrealdir); /* same as last time. */
  1537.                     /* so return old answer */
  1538.   else {
  1539.  
  1540.     j = strlen(dirname);
  1541.     for (i = 0; i < j; i++)        /* find username part of string */
  1542.       if (dirname[i] != DIRSEP)
  1543.     temp[i] = dirname[i];
  1544.       else break;
  1545.     temp[i] = '\0';            /* tie off with a NULL */
  1546.     if (i == 1) {            /* if just a "~" */
  1547.       user = getpwnam(whoami());    /*  get info on current user */
  1548.     }
  1549.     else {
  1550.       user = getpwnam(&temp[1]);    /* otherwise on the specified user */
  1551.     }
  1552.   }
  1553.   if (user != NULL) {            /* valid user? */
  1554.     strcpy(olddir, dirname);        /* remember the directory */
  1555.     strcpy(oldrealdir,user->pw_dir);    /* and their home directory */
  1556.     strcat(oldrealdir,&dirname[i]);
  1557.     return(oldrealdir);
  1558.   }
  1559.   else {                /* invalid? */
  1560.     strcpy(olddir, dirname);        /* remember for next time */
  1561.     strcpy(oldrealdir, dirname);
  1562.     return(oldrealdir);
  1563.   }
  1564. #else
  1565.   return(NULL);
  1566. #endif /* dtilde */
  1567. }
  1568.