/***** **** *** ** *  *   *    *     *       *     *   *  * ** *** **** *****\

    logresolve 2.0 - http://www.net/~tomr/progs/logresolve/

    logresolve.c - logresolve 2.0b4

    Tom Rathborne - tomr@uunet.ca - http://www.net/~tomr/

\***** **** *** ** *  *   *    *     *       *     *   *  * ** *** **** *****/

/* System include files */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netdb.h>

/* Logresolve include files */

#include "logresolve.h"

#include "lr-nsrec.h"
#include "lr-stats.h"
#include "lr-ip.h"
#include "lr-hash.h"

#ifdef LR_DBM
#include "lr-dbm.h"
#endif

/*** FUNCTIONS BEGIN ********************************************************/

/* getline - gets a line from stdin to s - at most maxlength chars */

int
getline(s, maxlength, file)
    char *s;
    int maxlength;
    FILE *file;
{
    char *cp;

    if (!fgets(s, maxlength, file))
	return (TRUE);
    if ((cp = strchr(s, '\n')))
	*cp = '\0';
    return (FALSE);
}

/* die_error - dies with string to stderr */

void
die_error(error)
    char *error;
{
    fprintf(stderr, error);
    exit(1);
}

/* setopt - sets options from defaults, then processes command line */

void
setopt(opt, argc, argv)
    struct lr_opt *opt;
    int argc;
    char *argv[];
{
    int arg, plus;
    char *option;

#ifdef LR_DBM
    opt->dbm = TRUE;
#else
    opt->dbm = FALSE;
#endif

    opt->dbmname = (char *) malloc(strlen(LR_DBMNAME) + 1);
    strcpy(opt->dbmname, LR_DBMNAME);

    opt->lockname = (char *) malloc(strlen(LR_LOCKNAME) + 1);
    strcpy(opt->lockname, LR_LOCKNAME);

    opt->inname = (char *) malloc(strlen(LR_INNAME) + 1);
    strcpy(opt->inname, LR_INNAME);

    opt->outname = (char *) malloc(strlen(LR_OUTNAME) + 1);
    strcpy(opt->outname, LR_OUTNAME);

    opt->statsname = (char *) malloc(strlen(LR_STATSNAME) + 1);
    strcpy(opt->statsname, LR_STATSNAME);

    opt->expire = LR_EXPIRE;
    opt->retry = LR_RETRY;
    opt->keep = LR_KEEP;
    opt->tries = LR_TRIES;
    opt->stats = LR_STATS;
    opt->buckets = LR_BUCKETS;
    opt->nice = LR_NICE;

    for (arg = 1; arg < argc; arg++) {
	option = argv[arg];
	if (((plus = 0) || (*option == '-')) || ((*option == '+') && (plus = 1))) {
	    option++;
	    switch (*option) {
		case 's':
		    opt->stats = plus;
		    break;
		case 'd':
		    free(opt->dbmname);
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->dbmname = (char *) malloc(strlen(option) + 1);
		    strcpy(opt->dbmname, option);
		    break;
		case 'l':
		    free(opt->lockname);
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->lockname = (char *) malloc(strlen(option) + 1);
		    strcpy(opt->lockname, option);
		    break;
		case 'i':
		    free(opt->inname);
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->inname = (char *) malloc(strlen(option) + 1);
		    strcpy(opt->inname, option);
		    break;
		case 'o':
		    free(opt->outname);
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->outname = (char *) malloc(strlen(option) + 1);
		    strcpy(opt->outname, option);
		    break;
		case 't':
		    opt->stats = TRUE;
		    free(opt->statsname);
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->statsname = (char *) malloc(strlen(option) + 1);
		    strcpy(opt->statsname, option);
		    break;
		case 'a':
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->expire = atoi(option);
		    break;
		case 'r':
		    option++;
		    if (!*option)
			option = argv[++arg];
		    opt->retry = atoi(option);
		    break;
		case 'k':
		    opt->keep = plus;
		    break;
		default:
		    die_error("Invalid command line option!\n");
	    }
	} else {
	    die_error("Badly formatted command line!\n");
	}
    }

    return;
}

/* main - does it all! */

int
main(argc, argv)
    int argc;
    char *argv[];
{
    char *line, *chop;
    unsigned char ipnum[4];

    FILE *infile, *outfile;

    struct nsrec *record;
    struct nstab *table;
    struct lr_opt opt;

#ifdef LR_DBM
    struct nsdbm *lrdbm;

    setopt(&opt, argc, argv);

    if (opt.nice)
	setpriority(PRIO_PROCESS, getpid(), opt.nice);

    lrdbm = pdbm_open(opt.dbmname, opt.lockname, LR_READ);
#else
    setopt(&opt, argc, argv);

    if (opt.nice)
	setpriority(PRIO_PROCESS, getpid(), opt.nice);
#endif

    table = hash_new(opt.buckets);
    line = (char *) malloc(MAXLINE);

    sethostent(TRUE);

    if (!strcmp(opt.inname, "-")) {
	infile = stdin;
    } else {
	if (!(infile = fopen(opt.inname, "r")))
	    die_error("Couldn't open input file!\n");
    }

    if (!strcmp(opt.outname, "-")) {
	outfile = stdout;
    } else if (!strcmp(opt.outname, "=")) {
	outfile = stderr;
    } else {
	if (!(outfile = fopen(opt.outname, "w")))
	    die_error("Couldn't open output file!\n");
    }

/* Begin main loop. */

    while (!getline(line, MAXLINE, infile) && *line) {
	chop = line;

	if (!isdigit(line[0])) {	/* short cut */
	    fputs(line, outfile);
	    continue;
	}
	while (*chop && *chop != ' ')
	    chop++;

	if (*chop) {
	    *chop = 0;
	    chop++;
	}
	if (str_ip(line, ipnum)) {
	    if (!(record = hash_lookup(table, ipnum))) {
#ifdef LR_DBM
		if (!(record = pdbm_lookup(lrdbm, ipnum)))
#endif
		{
		    record = ip_lookup(ipnum);
		}
		record->usages++;

		hash_insert(table, record);
	    }
	    if ((record->lookuptime < (time(NULL) - opt.expire))
		|| ((record->status) && (record->lookuptime < (time(NULL) - opt.retry)))
		|| ((record->status == TRY_AGAIN)
		    && (record->tries <= opt.tries))) {
		ip_relookup(record);
	    }
	    fprintf(outfile, "%s %s\n", record->hostname, chop);

	} else {
	    fprintf(outfile, "%s %s\n", line, chop);
	}
    }

/* End main loop. */

    fclose(outfile);
    fclose(infile);

    endhostent();

#ifdef LR_DBM
    pdbm_close(lrdbm);
    hash_dumpto_pdbm(table, opt.dbmname, opt.lockname, opt.keep);
#endif

    if (opt.stats) {
	if (!strcmp(opt.statsname, "-")) {
	    outfile = stdout;
	} else if (!strcmp(opt.statsname, "=")) {
	    outfile = stderr;
	} else {
	    if (!(outfile = fopen(opt.statsname, "w")))
		die_error("Couldn't open statistics file!\n");
	}

	fprintf(outfile, "Imagine statistics here.\n");
	fclose(outfile);
    }
    return (0);
}

/*** end of logresolve.c ***/
