/*	Copyright (c) 1990 UNIX System Laboratories, Inc.	*/
/*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF     	*/
/*	UNIX System Laboratories, Inc.                     	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * Copyright  (c) 1985 AT&T
 *	All Rights Reserved
 */
#ident	"@(#)fmli:sys/genfind.c	1.8"

#include	<pwd.h>
#include	<stdio.h>
#include	<string.h>
#include	<time.h>
#include	<values.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	"wish.h"
#undef	min
#undef	max
#include	"typetab.h"		/* for ott masks ott_tab ott_entry() */
#include	"partabdefs.h"
#include	"var_arrays.h"		/* for array_len() */
#include 	"sizes.h"

#ifndef TEST

#include	"eval.h"

#else  /* TEST */
#define IOSTRUCT	FILE
#define putac		putc
#define putastr		fputs
#define mess_temp	puts
#endif /* TEST */

#define DAY	(24L * 60L * 60L)

extern struct ott_entry	*Cur_entry;
extern struct opt_entry	Partab[];
extern char *Oasys;

static char	any[] = "any";
static char path_buf[PATHSIZ];

#ifdef TEST
main(argc, argv)
int	argc;
char	*argv[];
{
	wish_init(argc, argv);
	odftread();
	genfind(argc, argv, stdin, stdout);
	exit(0);
}
#endif /* TEST */

/*
 * usage: genfind path filename type owner age
 */
genfind(argc, argv, instr, outstr, errstr)
int	argc;
char	*argv[];
IOSTRUCT	*instr;
IOSTRUCT	*outstr;
IOSTRUCT *errstr;
{
	FILE	*fp;
	register pid_t	uid;	/* EFT abs k16 */
	int	min_days;
	int	max_days;
	int	do_traverse;
	int	origin;
	int	pathpos;
	int	namepos;
	char	path[PATHSIZ];
	char	buf[BUFSIZ];
	char 	*type;
	char	*dtype;
	char	allpath[PATHSIZ];
	char 	*Allfile="/info/OH/externals/allobjs";
	register int i;
	register char	*pattern;
	register struct	passwd *passwdptr;
	char	*myregcmp();
	struct	passwd *getpwnam();

	if (argc < 6 && argc > 8) {
		mess_temp("Arguments invalid");
		return FAIL;
	}
	i = 1;
	origin = 0;
	if (strcmp(argv[i], "-1") == 0) {
		origin = 1;
		i++;
	}
	else
		do_traverse = TRUE;
	if (strcmp(argv[i], "-n") == 0) {
		do_traverse = FALSE;
		i++;
	}
	else
		do_traverse = TRUE;
	pathpos = i;
	/* traverse assumes at least 1 extra byte available in path */
	if ((int)strlen(argv[i]) > PATHSIZ - 2) {        /* EFT k16 */
		mess_temp("Path too long");
		return FAIL;
	}
	strncpy(path, argv[i], PATHSIZ);
	path[sizeof(path) - 1] = '\0';
	if ((pattern = myregcmp(argv[++i])) == NULL) {
		mess_temp("Name invalid");
		return FAIL;
	}
	namepos = ++i;
	if (strCcmp(argv[++i], any)) {
		if ((passwdptr = getpwnam(argv[i])) == NULL) {
			mess_temp("Owner invalid");
			return FAIL;
		}
		uid = passwdptr->pw_uid;
	}
	else
		uid = -1;
	if (strCcmp(argv[++i], any)) {
		if (range(argv[i], origin, &min_days, &max_days) < 0) {
			mess_temp("Age invalid");
			return FAIL;
		}
	}
	else
		min_days = -1;

	(void) strcpy(allpath, Oasys);
	(void) strcat(allpath, Allfile);


	if ((fp = fopen(allpath, "r")) == NULL) 
		type=NULL;
	else 
		while(fgets(buf,BUFSIZ,fp)) {
			type=strtok(buf,"\t");
			dtype=strtok(NULL,"\n");
			if (strcmp(argv[namepos],dtype) == 0)
				break;
			type=NULL;
		}
	fclose(fp);

	traverse(path, pattern, uid, strCcmp(argv[namepos], any) ? argv[namepos] : NULL, min_days, max_days, argv[pathpos], do_traverse, outstr, type );
	return SUCCESS;
}

static
traverse(path, pattern, uid, objtype, min_days, max_days, prefix, do_traverse, outstr, type)
char	*path;
char	*pattern;
int	uid;
char	*objtype;
int	min_days;
int	max_days;
char	*prefix;
int	do_traverse;
IOSTRUCT	*outstr;
char	*type;
{
    register int	i;
    register int	length;
    register int	ott_len;
    register int	numdays;
    char	*basename;
    char	*objname;
    char	*typename;
    char	*intobj;
    long	mask;
    time_t	now;           /* EFT abs k16 */
    struct	stat	filestat;
    struct tm	*t;
    struct ott_tab	*ott;
    struct ott_tab	*ott_get();
    struct ott_entry	*entry;
    char	*bsd_path_to_title();
    char	*regex();
    time_t	time();		/* EFT abs k16 */
    struct tm	*localtime();

    /* check to see if enough space to put file names */
    if ((length = strlen(path)) >= PATHSIZ - 2)
	return;
    if ((ott = ott_get(path, OTT_SALPHA, 0, 0, 0)) == NULL)
	return;
    entry = Cur_entry;
    ott_len = array_len(ott->parents);
    now = time(NULL);
    t = localtime(&now);
    now += (60 - t->tm_sec) + 60 * ((59 - t->tm_min) + 60 * (23 - t->tm_hour));
    for (i = 0; i < ott_len; ++i) {
	/* shorter names */
	basename = entry[ott->parents[i]].name;
	objname = entry[ott->parents[i]].dname;
	typename = entry[ott->parents[i]].display;
	intobj = entry[ott->parents[i]].objtype;
	mask = entry[ott->parents[i]].objmask;
	/* object's name not viewable or marked deleted */
	if (basename[0] == '\0' || (mask & M_WB) || (mask & M_DL))
	    continue;
	/*
	 * these tests are performed in order of increasing
	 * computational cost
	 */
	path[length] = '/';
	strncpy(&path[length + 1], basename, PATHSIZ - length - 2);

	if ((!objtype || !strcmp(objtype, typename) ||
	     !strcmp(intobj, type)) && regex(pattern, objname)) {
	    numdays = (int) ((now - entry[ott->parents[i]].mtime) / DAY);
	    if (min_days < 0 || (numdays >= min_days && numdays <= max_days)) {
		if (uid >= 0 && stat(path, &filestat))
		    continue;
		if (uid < 0 || filestat.st_uid == uid) {
		    putastr(path, outstr);
		    putac(';', outstr);
		    putastr(entry[ott->parents[i]].objtype, outstr);
		    putac(';', outstr);
		    path[length] = '\0';
		    if (do_traverse) {

			strcpy(path_buf,path);
			strcat(path_buf,"/");
			strcat(path_buf,objname);
			putastr(bsd_path_to_title(&path_buf[strlen(prefix)+1],
				COLS - 30), outstr);
		    } else
			putastr(objname, outstr);
		    path[length] = '/';
		    putac(';', outstr);
		    putastr(typename, outstr);
		    putac('\n', outstr);
		}
	    }
	}
	if (mask & CL_DIR) {
	    /* object is a directory and not deleted, search */
	    if (do_traverse)
		traverse(path, pattern, uid, objtype, min_days, max_days,
			 prefix, do_traverse, outstr, type);
	    path[length] = '\0';
	    if ((ott = ott_get(path, OTT_SALPHA, 0, 0, 0)) == NULL)
		return;
	    entry = Cur_entry;
	    ott_len = array_len(ott->parents);
	}
    }				/* end of for loop */
}

static int
range(s, origin, mindays, maxdays)
char	*s;
int	origin;
int	*mindays;
int	*maxdays;
{
	char	*s1;
	long	strtol();

	switch (*s) {
	case '<':
		*mindays = 0;
		*maxdays = (int) strtol(s + 1, &s1, 10);
		break;
	case '>':
		*maxdays = MAXINT;
		*mindays = (int) strtol(s + 1, &s1, 10);
		break;
	default:
		*mindays = (int) strtol(s, &s1, 10);
		if (s1 == s)
			return FAIL;
		if (*s1 == '-')
			*maxdays = (int) strtol(s1 + 1, &s1, 10);
		else if (*s1 == '.' && s1[1] == '.')
			*maxdays = (int) strtol(s1 + 2, &s1, 10);
		else
			*maxdays = *mindays;
		break;
	}
	if (origin && *mindays == 1)
		*mindays = 0;
	if (*mindays < 0 || *maxdays < 0)
		return FAIL;
	return (*s1 == '\0') ? SUCCESS : FAIL;
}

static char *
myregcmp(s)
char	*s;
{
	register char	*p;
	register char	*q;
	register int	len;
	static char	special[] = "+.${}()";
	char	*regcmp();
	char	*strnsave();
	char	*_backslash();

	len = strlen(s) * 2 + 4;
	p = strnsave("^", len);
	(void) strcat(p, s);
	(void) _backslash(p, len, special, special);
	(void) strcat(p, "$");
	for (q = p; *q; q++)
		switch (*q) {
		case '*':
			memshift(q + 1, q, strlen(q) + 1);
			*q++ = '.';
			break;
		case '?':
			*q = '.';
			break;
		case '\\':
			if (!*++q)
				q--;
			break;
		case '[':
			if (q[1] == '!')
				q[1] = '^';
			break;
		default:
			break;
		}
	q = regcmp(p, NULL);
	free(p);
	return q;
}
