/*  $Revision: 1.1 $
**
**  Determine the hi and low water marks for a given newsgroup.
**
** By: chongo <Landon Curt Noll> /\oo/\	 chongo@toad.com
*/

#include "configdata.h"

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "clibrary.h"
#include "mydir.h"
#include "libinn.h"


/*
** HiLowWater - Given an newsgroup name determine the hi and low water marks
**
** Given:
**	name	name of newsgroup (in . notation)
**	hi	where to place the hi water mark value
**	low	where to place the low water mark value
**	oldhi	current hi water mark, or -1 to force to compute
**	oldlow	current low water mark, or -1 to force to compute
**
** Returns:
**	TRUE	newsgroup directory was found with files in it
**	FALSE	newsgroup directiry was not found, or did not contain
**		and files with all numeric (non-leading 0) names
**
** NOTE: This routine assumes that the current directory is $SPOOL.
*/
BOOL
HiLowWater(name, hi, low, oldhi, oldlow)
    char	*name;
    long	*hi;
    long	*low;
    long	oldhi;
    long	oldlow;
{
    int		dir_len;	/* length of newsgroup name */
    int		file_len;	/* length of the filename in the dir */
    char	dir[BUFSIZ];	/* name of directory to probe */
    char	path[BUFSIZ+SMBUF];	/* spool relative path of a file */
    DIR		*dp;		/* directory 'read descriptor' */
    DIRENTRY	*ep;		/* entry read from a directory */
    long	num;		/* numeric value of a filename */
    long	himark;		/* current hi water mark found */
    long	lowmark;	/* current low water mark found */
    BOOL	found_art;	/* TRUE => found an article */
    struct stat	statbuf;	/* stat of the file in the directory */
    char	*p;
    char	*q;

    /*
     * firewall
     */
    if (hi == NULL || low == NULL || name == NULL) {
	/* error - bogus args ... assume FALSE */
	return FALSE;
    }
    dir_len = strlen(name);
    if (dir_len == 0 || dir_len >= BUFSIZ) {
	/* newsgroup name length is bad, so punt on the search */
	return FALSE;
    }

    /*
     * assume current hi and low values unless we find otherwise
     *
     * force low > 0 && hi >= low-1
     */
    if (oldlow > 0) {
	*low = oldlow;
	lowmark = oldlow;
	if (oldhi < oldlow-1) {
	    oldhi = oldlow-1;
	}
    } else {
	*low = 1;
	lowmark = 0x7fffffff;
    }
    if (oldhi >= 0) {
	*hi = oldhi;
	himark = oldhi;
    } else {
	*hi = 0;
	himark = 0;
    }

    /* 
     * Turn group name into directory name
     */
    for (p=name, q=dir; *p; ++p, ++q) {
	if (*p == '.') {
	    *q = '/';
	} else {
	    *q = *p;
	}
    }
    *q = '\0';

    /*
     * attempt to open the directory
     */
    dp = opendir(dir);
    if (dp == NULL) {
	/* cannot scan the directory, assume not found or non-accessable */
	return FALSE;
    }

    /*
     * scan the directory for all numeric non-leading zero entries
     * looking for the lowest and highest values
     */
    found_art = FALSE;
    while ((ep = readdir(dp)) != NULL) {

	/*
	 * ignore if it it does not begin with [1-9]
	 */
	p = ep->d_name;
	if (!CTYPE(isdigit, *p) || *p == '0') {
	    /* first char is not [1-9], ignore */
	    continue;
	}

	/*
	 * ignore if contains a non-digit elsewhere in the name
	 */
	for (++p; *p; ++p) {
	    if (!CTYPE(isdigit, *p)) {
		break;
	    }
	}
	if (*p) {
	    /* found a non-digit, ignore this entry */
	    continue;
	}

	/*
	 * convert numeric file name to a digit
	 */
	num = atol(ep->d_name);

	/*
	 * look for a new low water mark
	 *
	 * Ignore this entry if it is not a file.
	 */
	if (num < lowmark) {

	    /*
	     * ignore if this entry is not a file
	     *
	     * If the numeric name is too long, assume we have a file
	     */
	    file_len = strlen(ep->d_name);
	    if (dir_len+1+file_len < BUFSIZ+SMBUF) {

		/* 
		 * form the filename 
		 */
		strncpy(path, dir, dir_len);
		path[dir_len] = '/';
		strncpy(path+dir_len+1, ep->d_name, file_len);
		path[dir_len+1+file_len] = '\0';

		/* 
		 * skip if fie is not found or if it is not a regular file
		 */
		if (stat(path, &statbuf) < 0 || !S_ISREG(statbuf.st_mode)) {
		    continue;
		}
	    }

	    /*
	     * we have a new low water mark
	     */
	    lowmark = num;
	}

	/*
	 * note that we saw a numeric non-learing 0 file
	 */
	found_art = TRUE;

	/*
	 * look for a new hi water mark
	 */
	if (num > himark) {
	    himark = num;
	}
    }

    /* 
     * if lowmark was never set, set it to 1
     */
    if (!found_art) {
	lowmark = himark+1;
    }

    /*
     * We know that lowmark is > 0, so now we will force hi >= low-1
     */
    if (himark < lowmark-1) {
	himark = lowmark-1;
    }

    /*
     * note new marks
     */
    *hi = himark;
    *low = lowmark;
    /* found new marks */
    return found_art;
}
