/* 
 * hosts: the interface to /etc/hosts
 *
 * 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.Hosts.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 <netdb.h>
#include <string.h>
}

#include "Hosts.H"
#include "Sysconfig.H"
#include "util.H"

/*
 * load up hosts.cf, or suitable defaults
 */
Hosts::Hosts():KAarray()
{
    if (Refresh() == EOF) {
	/* No /etc/hosts?; Do some emergency repair work */
	changed(1);

	create("127.0.0.1", "localhost");
    }
    changed(0);
} /* Hosts::Hosts */

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

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


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

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

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


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

    while (fgets(bfr, sizeof bfr, in) != 0) {
	for (ptr=bfr; *ptr && *ptr != '#' && *ptr != '\n'; ++ptr)
	    ;
	*ptr = 0;

	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) {
		if (val.count() > 0) {
		    /* strip duplicate domain entries off
		     * the hostname.
		     */
		    char *domain = strchr((char*)(val[0]), '.');
		    char *p = strchr(ptr, '.');
		    if (p && domain && !strcasecmp(domain, p))
			*p = 0;
		}
		val += ptr;
	    }
	    rc++;
	}
	memset(bfr, 0, sizeof bfr);
    }
    return rc;
} /* Hosts::read */


/*
 * print() writes the contents of hosts out to the given FILE*
 */
int
Hosts::print(FILE *out)
{
    unsigned int i, j;

    for (i=0; i<count(); i++)
	if (_list[i]._used) {
	    KA& val = *(_list[i]._content);

	    if (val.count() > 0) {
		fprintf(out, "%s", _list[i]._key);
		for (j=0; j<val.count(); j++)
		    fprintf(out,"%c%s", (j<2) ? '\t' : ' ', val[j]);
		fputc('\n', out);
	    }
	}
    return ferror(out);
} /* Hosts::print */
