/*
 * Config file to binary file translator.  Reads in a pseudo NCSA telnet
 * file and produces a fixed format binary file for quick reads into
 * the X server.
 *
 * 2/2/90 PEY
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include <fcntl.h>
#include <errno.h>
#include <sys\types.h>
#include "config.h"

char	*keywords[] = {
	"myip",				/* 0 */
	"netmask",			/* 1 */
	"address",			/* 2 */
	"ioaddr",			/* 3 */
	"hostip",			/* 4 */
	"gateway",			/* 5 */
	"nameserver",			/* 6 */
	"hardware",			/* 7 */
	"domaintime",			/* 8 */
	"domainretry",			/* 9 */
	NULL
};

main(argc,argv)
	int	argc;
	char	*argv[];
{
	struct conf	hinfo;
	char		*cp;
	char		buf[256];
	FILE		*fp;
	int		fd;
	int		line = 0;
	char		**key;
	char		gateway;
	char		nameserver;
	long		hostip = 0L;
	char		hardware[80];
	char		*x11;
	char		*configtel;
	char		x11buf[128];

	/* Parse command line for alternate config file name */

	if ((x11 = getenv("X11")) == NULL) {
		fputs("X11 variable not set, unable to continue.\n", stderr);
		exit(1);
	}

	if ((configtel = getenv("CONFIG.TEL")) == NULL &&
	    (configtel = getenv("CONFIGTEL")) == NULL) {
		fputs("CONFIG.TEL variable not set, unable to continue.\n", stderr);
		exit(1);
	}

	sprintf(x11buf, "%s\\config.bin", x11);

	/* Clear the host information */
	memset (&hinfo, 0, sizeof(hinfo));
	if ((fp = fopen(configtel, "r")) == NULL) {
		fprintf(stderr, "%s: Unable to open config file: %s\n",
			argv[0], configtel);
		exit(1);
	}
	while (fgets(buf, sizeof(buf), fp) != NULL) {
		line++;
		if (buf[0] == '\n' || buf[0] == '#' || isspace(buf[0]))
			continue;
		if ((cp = strchr(buf, '\n')) != NULL) {
			*cp = '\0';
		} else {
			fprintf(stderr, "Invalid line (%d): %s\n", line, buf);
		}
		if ((cp = strchr(buf, '=')) == NULL) {
			fprintf(stderr, "Invalid line (%d): %s", line, buf);
			exit(1);
		}
		for (key = keywords; *key != NULL; key++) {
			if (strlen(*key) == cp - buf &&
				!strncmp(buf, *key, cp - buf))
					break;
		}
		if (*key == NULL) {
			continue;
		}
		switch (key - keywords) {
			case 0:			/* myip */

				/* Bootp ? */
				if (!strnicmp(cp + 1, "bootp", 5)) {
					if (!hinfo.flags) {
						hinfo.flags |= H_BOOTP;
					} else {
						fprintf(stderr,
						"Warning: Multiple flags (bootp)\n");
					}
					break;
				}

				/* Rarp? */
				if (!strnicmp(cp + 1, "rarp", 4)) {
					if (!hinfo.flags) {
						hinfo.flags |= H_RARP;
					} else {
						fprintf(stderr,
						"Warning: Multiple flags (rarp)\n");
					}
					break;
				}

				/* Must be IP address */
				if (hinfo.flags) {
					fprintf(stderr,
					"Too many \"myip\" keys\n");
				}
				if (parseip(cp + 1, &hinfo.myip)) {
					fprintf(stderr, "Bad IP address: %s\n",
						cp + 1);
					exit(1);
				}
				break;
			case 1:			/* netmask */
				if (parseip(cp + 1, &hinfo.snetmask)) {
					bad("Bad IP netmask", cp + 1);
				}
				break;
			case 2:			/* address */
				if (parsechar(cp + 1, &hinfo.address,
					0, MAX_ADDRESS, 1)) {
					bad("Bad packet driver class", cp + 1);
				}
				break;
			case 3:			/* ioaddr */
				if (parsechar(cp + 1, &hinfo.ioaddr, 0,
					MAX_IOADDR, 1)) {
					bad("Bad I/O address", cp + 1);
				}
				break;
			case 4:		/* hostip */
				if (parseip(cp + 1, &hostip)) {
					bad("Bad Host IP address",
						cp + 1);
				}
				break;
			case 5:		/* gateway (flag) */
				if (hostip == 0L) {
					fputs("No IP address to use for gateway\n", stderr);
					break;
				}
				if (parsechar(cp + 1, &gateway, 0,
					MAX_GATEWAY, 0)) {
					bad("Bad I/O address", cp + 1);
				}
				hinfo.gateip = (struct machinfo _far *)hostip;
				break;
			case 6:		/* nameserver (flag) */
				if (hostip == 0L) {
					fputs("No IP address to use for nameserver\n", stderr);
					break;
				}
				if (parsechar(cp + 1, &nameserver, 0,
					MAX_NAMESERVER, 0)) {
					bad("Bad I/O address", cp + 1);
				}
				hinfo.nsip = (struct machinfo _far *)hostip;
				break;
			case 7:		/* hardware */
				if (strncmp(cp + 1, "packet", 6)) {
					fprintf(stderr, "Warning: Bad hardware type: %s\n", cp + 1);
				}
				break;
			case 8:	/* domaintime */
				if (parsechar(cp + 1, &hinfo.domaintime, 0,
					MAX_DOMAINTIME, 0)) {
					bad("Bad domain timeout", cp + 1);
				}
				break;
			case 9:	/* domainretry */
				if (parsechar(cp + 1, &hinfo.domainretry, 0,
					MAX_DOMAINRETRY, 0)) {
					bad("Bad domain retry", cp + 1);
				}
				break;
			default:
				fprintf(stderr, "%s: Switch error 1: %d\n",
					argv[0], key - keywords);
				exit(2);
				break;
		}
	}
	if (!feof(fp)) {
		fprintf(stderr, "%s: File error: %s\n",
			argv[0], strerror(errno));
		exit(1);
	}

	if ((fd = open(x11buf, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
			fprintf(stderr,
				"%s: Unable to open binary file %s: %s\n",
				argv[0], x11buf, strerror(errno));
			exit(1);
	}
	write(fd, &hinfo, sizeof(hinfo));
	close(fd);
}

/* Parse an IP address, given a pointer to a dot notation address, and a
 * 4 byte buffer to fill.
 */

parseip(buf, ip)
	char		*buf;
	unsigned long	*ip;
{
	int	count;
	char	*cp;
	char	*sp;

	sp = buf;
	for (count = 0; count < 3; count++) {
		if ((cp = strchr(sp, '.')) == NULL) {
			fprintf(stderr, "parseip: Bad format\n");
			
		}
		if (!isdigit(*sp)) {
			fprintf(stderr, "parseip: Not a number\n");
			return -1;
		}
		*((char *)ip + count) = (char)atoi(sp);
		sp = cp + 1;
	}
	*((char *)ip + 3) = (char)atoi(sp);
	return 0;
}

/* Rudimentary number parsing, given a string representation of a number,
 * a pointer to an integer buffer, and a minimum and maximum allowed value.
 */
parsechar(string, number, minimum, maximum, hex)
	unsigned char	*string;
	unsigned char	*number;
	unsigned char	minimum;
	unsigned char	maximum;
{
	if (!isxdigit(*string))
		return -1;
	if (string[0] == '0' && string[1] == 'x') {
		hex = 1;
		string += 2;
	}
	if (hex)
		*number = (unsigned char)tohex(atoi(string));
	else
		*number = (unsigned char)atoi(string);
	if (*number < minimum || *number > maximum)
		return -1;
	if (minimum > maximum)
		return -1;
	return 0;
}

/* Print an error message */

bad(mesg, string)
	char	*mesg;
	char	*string;
{
	fprintf(stderr, "%s: %s\n", mesg, string);
	exit(1);
}

tohex(val)
	int		val;
{
	unsigned int	base = 1;
	unsigned int	radix = 16;
	unsigned int	total = 0;

	while (val) {
		total += val % 10 * base;
		base *= radix;
		val = val / 10;
	}
	return(total);
}
