/* 
 * resolv: the interface to /etc/resolv.conf
 *
 * Copyright (c) 1997 David L Parsons 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
 * to endorse or promote products derived from this software without
 * specific prior written permission.  THIS SOFTWARE IS PROVIDED
 * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 */
static const char rcsid[] = "$Id: s.Resolv.cc 1.7 01/03/11 17:58:55-08:00 orc@downbelow.pell.portland.or.us $";

extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>
}
#include <string.h>

#include "Resolv.H"
#include "util.H"

/*
 * load up resolv.cf, or suitable defaults
 */
Resolv::Resolv():KAarray()
{
    if (Refresh() == EOF) {
	/* No /etc/resolv.conf; build a suitable template file. */
	autoappend(1);	/* we can add to this array on the fly */
	changed(1);

	create("options");
	create("search");
	create("domain");
	create("nameserver");
	create("sortlist");
    }
    changed(0);
} /* Resolv::Resolv */

/*
 * if anything has changed, write it to disk.
 * 
 * TODO: file locking, dirty file checking.
 */
int
Resolv::commit()
{
    FILE *cf;

    if (changed()) {
	if (backup(RESOLV_CONF) != 0)
	    return EOF;
	if ((cf = fopen(RESOLV_CONF, "w")) == (FILE*)0)
	    return EOF;
	make_header(cf, 0);
	print(cf);
	fclose(cf);
	KAarray::changed(0);
    }
    return 0;
} /* Resolv::commit */


/*
 * has the disk configuration file been touched since we last loaded it in?
 */
int
Resolv::dirty()
{
    return 0;
}

/*
 * Refresh() the configuration from the disk image 
 */
int
Resolv::Refresh()
{
    FILE *cf;

    if ((cf = fopen(RESOLV_CONF, "r")) != (FILE*)0) {
	KAarray::Erase();		/* never merge configurations */
	KAarray::autoappend(1);
	read(cf);
	KAarray::changed(0);
	fclose(cf);
	return 0;
    }
    return EOF;
} /* Resolv::Refresh */


/*
 * read() a configuration file from the given file descriptor.
 */
int
Resolv::read(FILE *in)
{
    char bfr[200];
    char *token;
    char *ptr;

    while (fgets(bfr, sizeof bfr, in) != 0) {
	strtok(bfr, "\n#");

	token = strtok(bfr, "\t ");

	if (token && *token) {
	    register int i = locate(token);
	    KA& val = (i>=0) ? *(_list[i]._content) : create(token);

	    while ((ptr = strtok(NULL, "\t ")) != (char*)0)
		val += ptr;

	    /* domain and search are mutually exclusive, and the last
	     * one sticks.  We'll use create() to flush any values left
	     * over from the last.
	     */
	    if (strcasecmp(token, "domain") == 0)
		create("search");
	    else if (strcasecmp(token, "search") == 0)
		create("domain");

	}
    }
    return count();
} /* Resolv::read */


/*
 * print() writes the contents of resolv.conf out to the given FILE*
 */
int
Resolv::print(FILE *out)
{
    int i, j;

    static char *listopts[] = {
	"order",
	"search",
	"sortlist",
	"options",
	0
    };

    if ((i = locate("domain")) >= 0) {
	KA& val = *_list[i]._content;

	if (val.count() > 0)
	    fprintf(out, "domain %s\n", val[0]);
    }

    for (j=0;  listopts[j]; j++) {
	if ((i = locate(listopts[j])) >= 0) {
	    KA& val = *_list[i]._content;

	    if (val.count() > 0) {
		unsigned ii;
		fprintf(out, listopts[j]);
		for (ii=0; ii<val.count(); ii++)
		    fprintf(out, " %s", val[ii]);
		fputc('\n', out);
	    }
	}
    }

    if ((i = locate("nameserver")) >= 0) {
	KA& val = *_list[i]._content;

	unsigned ii;
	for (ii=0; ii<val.count(); ii++)
	    fprintf(out, "nameserver %s\n", val[ii]);
    }

    return 0;
} /* Resolv::print */
