/*
 * misc.c
 */

#include <ctype.h>

#include "ipxtunnel.h"
#include "misc.h"

#define LOOKUP(a, b)	(!strncmp((a), (b), strlen(b)))
#define SKIPWS(str)	while(*str && (*str == ' ' || *str == '\t')) \
				str++

static void InsertHost(struct config *config, char *name, int port);
static void InsertInterface(struct config *config, char *interface);

struct config *
ReadConfigFile(char *fname)
{
	FILE		*fp;
	char		line[MAXLINE];
	struct config	*config;
	int		lineNo = 0;
	char		*host, *interface, *str;
	int		port;

	if(!(fp = fopen(fname, "r"))) {
		perror(fname);
		exit(1);
	}

	config = (struct config *) Malloc(sizeof(struct config));
	config->hosts = NULL;
	config->interfaces = NULL;
	config->port = DEFAULT_PORT;

	while(fgets(line, MAXLINE, fp)) {
		lineNo++;
		if(*line == '#' || *line == '\n' || *line == ' ')
			continue;
		if(LOOKUP(line, "remote")) {
			str = line + strlen("remote") + 1;
			SKIPWS(str);
			if(!*str || *str == '\n') {
				fprintf(stderr, "%s (line %d): no hostname\n",
					fname, lineNo);
				exit(1);
			}
			host = str;
			port = DEFAULT_PORT;
			if((str = strpbrk(str, " \t\n"))) {
				if(*str == '\n') {
					*str = '\0';
				} else {
					*str++ = '\0';
					while(*str && (*str == ' '
					|| *str == '\t'))
						str++;
					if(*str && isdigit(*str))
						port = atoi(str);
				}
			}
			InsertHost(config, host, port);
		} else if(LOOKUP(line, "interface")) {
			str = line + strlen("interface") + 1;
			SKIPWS(str);
			if(!*str || *str == '\n') {
				fprintf(stderr, "%s (line %d): no interface\n",
					fname, lineNo);
				exit(1);
			}
			interface = str;
			if((str = strchr(str, '\n')))
				*str = '\0';
			InsertInterface(config, interface);
		} else if(LOOKUP(line, "port")) {
			str = line + strlen("port") + 1;
			SKIPWS(str);
			if(!*str) {
				fprintf(stderr, "%s (line %d): no port\n",
					fname, lineNo);
				exit(1);
			}
			config->port = atoi(str);
		} else {
			fprintf(stderr, "%s (line %d): garbage\n", fname,
				lineNo);
			exit(1);
		}

	}

	fclose(fp);
	return config;
}


void *
Malloc(size_t size)
{
	void *p;

	if(!(p = malloc(size))) {
		perror("malloc()");
		exit(1);
	}

	return p;
}

static void
InsertHost(struct config *config, char *name, int port)
{
	struct host *host = Malloc(sizeof(struct host));

	host->host = strdup(name);
	host->port = (unsigned short) port;

	if(!config->hosts) {
		config->hosts = (struct host **)
			Malloc(2 * sizeof(struct host *));
		config->hosts[0] = host;
		config->hosts[1] = NULL;
	} else {
		int no = 0;
		while(config->hosts[no])
			no++;
		if(!(config->hosts = (struct host **)
			realloc(config->hosts,
				sizeof(struct host *) * (no + 2)))) {
			perror("realloc()");
			exit(1);
		}
		config->hosts[no] = host;
		config->hosts[no + 1] = NULL;
	}
}

static void
InsertInterface(struct config *config, char *interface)
{
	if(!config->interfaces) {
		config->interfaces = Malloc(2 * sizeof(char *));
		config->interfaces[0] = strdup(interface);
		config->interfaces[1] = NULL;
	} else {
		int no = 0;
		while(config->interfaces[no])
			no++;
		if(!(config->interfaces = (char **) realloc(config->interfaces,
				sizeof(char *) * (no + 2)))) {
			perror("realloc()");
			exit(1);
		}
		config->interfaces[no] = strdup(interface);
		config->interfaces[no + 1] = NULL;
	}
}

#ifdef GONZO
/* DONTUSE */
int
Compress(unsigned char *ib, unsigned char *ob, int len)
{
	register unsigned char	*ibEnd, *obEnd;

	ibEnd = ib + len;
	obEnd = ob + len;
	while(ib < ibEnd && ob < obEnd - 1) {
		*ob++ = *ib;
		*ob = 1;
		while(*ib == *(ib + 1) && ib < ibEnd && *ob < 0xff) {
			(*ob)++;
			ib++;
		}
		if(*ob == 0xff) {
			ob++;
			continue;
		}
		ob++;
		ib++;
	}
	return ob >= obEnd
		? 0
		: len - (obEnd - ob);
}

int
Uncompress(unsigned char *ib, unsigned char *ob, int len)
{
	register unsigned char	cnt;
	unsigned char		*ibEnd;
	unsigned char		*obStart;

	ibEnd = ib + len;
	obStart = ob;
	while(ib < ibEnd) {
		for(cnt = 0; cnt < *(ib + 1); cnt++)
			*ob++ = *ib;
		ib += 2;
	}
	return ob - obStart;
}
#endif /* GONZO */
	
void
PrintHex(char *s, int len)
{
        int i;

        for(i = 0; i < len; i++) {
                printf("%02x ", ((unsigned char) s[i]) & 0xFF);
                if(i && (i % 25 == 0))
                	putchar('\n');
	}
}

void
PrintIPX(ipx_packet *pkt)
{
	printf("IPX: chk "); PrintHex((char *) &pkt->ipx_checksum, 2);
	printf("\nsize: "); PrintHex((char *) &pkt->ipx_pktsize, 2);
	printf("\ntctrl: %02x", (unsigned short) pkt->ipx_pktsize & 0xFF);
	printf("\ntype: %02x", (unsigned short) pkt->ipx_pktsize & 0xFF);
	printf("\ndest.net: "); PrintHex((char *) &pkt->ipx_dest.net, 4);
	printf("\ndest.node: "); PrintHex((char *) &pkt->ipx_dest.node, 6);
	printf("\ndest.sock: "); PrintHex((char *) &pkt->ipx_dest.sock, 2);
	printf("\nsrc.net: "); PrintHex((char *) &pkt->ipx_source.net, 4);
	printf("\nsrc.node: "); PrintHex((char *) &pkt->ipx_source.node, 6);
	printf("\nsrc.sock: "); PrintHex((char *) &pkt->ipx_source.sock, 2);
	putchar('\n');
}
