/* Miscellaneous format conversion subroutines */

#include <ctype.h>
#include <stdio.h>
#include "global.h"
#include "netuser.h"
#include "internet.h"
int net_error;
extern char nospace[];
extern char cantopen[];

#define LINELEN 256

#ifndef MSDOS
/* define a hostname->ip_address cache, except for MS-DOS */
/* (MS-DOS machines already have enough memspace problems without it!) */
# define NULLHOST (struct host *) 0
static struct host {
	struct host *next;
	int32 ip_address;
	char hostname[2];
} *hostlist = NULLHOST;
#endif

/* Convert Internet address in ascii dotted-decimal format (44.0.0.1) to
 * binary IP address
 */
int32
aton(s)
register char *s;
{
	int32 n;
	register int i;

	n = 0;
	for(i=24;i>=0;i -= 8){
		n |= (int32)atoi(s) << i;
		if((s = index(s,'.')) == NULLCHAR)
			break;
		s++;
	}
	return n;
}
/* Resolve a host name into an IP address. IP addresses in dotted-decimal
 * notation are distinguished from domain names by enclosing them in
 * brackets, e.g., [44.64.0.1]
 */
int32
resolve(host)
char *host;
{
#ifdef MSDOS
	static struct {
		char *name;
		int32 address;
	} cache;
#else
	register struct host *hp;
	register struct host **hpp;
	int32 ip_address;
#endif
	register char *cp,*cp1;
	char *getnenv();
	FILE *sfile;
	int  len,l;
	char hostent[LINELEN];

	if(*host == '['){
		/* Brackets indicate IP address in dotted-decimal form */
		return aton(host + 1);
	}
#ifdef MSDOS
	if(cache.name != NULLCHAR && strcmp(cache.name,host) == 0)
		return cache.address;

	len = strlen(host);
#else
	len = strlen(host);

	/* Not a numerical IP address, look in in-memory host list */
	for(hpp = &hostlist; *hpp != NULLHOST; hpp = &hp->next){
	    hp = *hpp;
	    if(strlen(hp->hostname) == len &&
	       strncasecmp(host,hp->hostname,len) == 0)
		return hp->ip_address;
	}
#endif
	/* Not a numerical IP address, search the host table */
	if((sfile = fopen(cp = getnenv(HOSTS),"r")) == NULLFILE){
		printf(cantopen,cp);
		return 0;
	}
	while (fgets(hostent,LINELEN,sfile) != NULLCHAR){
		rip(hostent);
		cp = hostent;
		if(*cp == '#' || !isdigit(*cp))
			continue;	/* Comment or invalid line */
#ifndef MSDOS
		ip_address = aton(cp);
		/* skip to end of IP address */
		while(*cp != '\0' && *cp != ' ' && *cp != '\t')
			cp++;
#endif
		while(*cp){
			/* Skip white space */
			while(*cp == ' ' || *cp == '\t')
				cp++;
			if(*cp == '\0' || *cp == '#')
				break;
			/* Look for next token, find length of this one */
			for (cp1 = cp; *cp1 && *cp1 != ' ' && *cp1 != '\t'; cp1++)
				;
			l = (int) (cp1 - cp);
			if(len == l && strncasecmp(host,cp,l) == 0){
				/* Found it, put in cache */
				fclose(sfile);
#ifdef MSDOS
				if(cache.name != NULLCHAR)
					free(cache.name);
				if((cache.name = malloc((unsigned)l+1)) != NULLCHAR)
					strcpy(cache.name,host);
				cache.address = aton(hostent);
				return cache.address;
#else
				if ((hp = (struct host *) calloc(1,sizeof(struct host) + len - 1)) == NULLHOST){
					printf(nospace);
				} else {
					/* fill new host block */
					*hpp = hp;
					hp->ip_address = ip_address;
					strncpy(hp->hostname,cp,len);
				}
				return ip_address;
#endif
			}
			/* That one didn't match, try the next one */
			cp = cp1;
		}
	}
	/* No address found */
	fclose(sfile);
	return 0;
}

/* Convert an internet address (in host byte order) to a dotted decimal ascii
 * string, e.g., 255.255.255.255\0
 */
char *
inet_ntoa(a)
int32 a;
{
	static char buf[16];

	sprintf(buf,"%u.%u.%u.%u",
		hibyte(hiword(a)),
		lobyte(hiword(a)),
		hibyte(loword(a)),
		lobyte(loword(a)) );
	return buf;
}
/* Convert a socket (address + port) to an ascii string of the form
 * aaa.aaa.aaa.aaa:ppppp
 */
char *
psocket(s)
struct socket *s;
{
	static char buf[22];

	sprintf(buf,"%s:%u",inet_ntoa(s->address),s->port);
	return buf;
}
/* Convert an internet address (in host byte order) to first host name
 * from hosts file (if present) or else to dotted decimal
 */
char *
inet_n2h(a)
int32 a;
{
#ifdef MSDOS
	static struct {
		char *name;
		int32 address;
	} cache;
#else
	register struct host *hp;
	register struct host **hpp;
#endif
	register char *cp,*cp1;
	char *getnenv();
	FILE *sfile;
	char hostent[LINELEN];

	if(a == 0)
		return inet_ntoa(a);
	/* First look in the cache */
#ifdef MSDOS
	if(cache.name != NULLCHAR && cache.address == a)
		return cache.name;
#else
	for(hpp = &hostlist; *hpp != NULLHOST; hpp = &hp->next){
	    hp = *hpp;
	    if(a == hp->ip_address)
		return hp->hostname;
	}
#endif

	/* Not in the cache, search the host table */
	if((sfile = fopen(getnenv(HOSTS),"r")) == NULLFILE)
		return inet_ntoa(a);
	while (fgets(hostent,LINELEN,sfile) != NULLCHAR){
		rip(hostent);
		cp = hostent;
		if(*cp == '#' || !isdigit(*cp))
			continue;	/* Comment or invalid line */
		if(a == aton(cp)) {
			/* Found it, put in cache */
			fclose(sfile);
			/* Look for hostname, first skip numerical form */
			while(*cp != ' ' && *cp != '\t' && *cp)
				cp++;
			/* Skip white space */
			while(*cp == ' ' || *cp == '\t')
				cp++;
			if(*cp == '\0' || *cp == '#')
				return inet_ntoa(a);
			/* Look for end of token */
			for (cp1 = cp; *cp1 && *cp1 != ' ' && *cp1 != '\t'; cp1++)
				;
			/* Terminate the host name */
			*cp1 = '\0';
#ifdef MSDOS
			if(cache.name != NULLCHAR)
				free(cache.name);
			if((cache.name = malloc((unsigned)(strlen(cp)+1))) == NULLCHAR)
				return inet_ntoa(a);
			strcpy(cache.name,cp);
			cache.address = a;
			return cache.name;
#else
			if ((hp = (struct host *) calloc(1,sizeof(struct host)+strlen(cp)-1)) == NULLHOST){
				return inet_ntoa(a);
			}
			/* fill new host block */
			*hpp = hp;
			hp->ip_address = a;
			strcpy(hp->hostname,cp);
			return hp->hostname;
#endif
		}
	}
	/* No address found */
	fclose(sfile);
	return inet_ntoa(a);
}
/* Convert a socket (address + port) to an ascii string of the form
 * hostname:ppppp
 */
char *
phsocket(s)
struct socket *s;
{
	static char buf[80];

	sprintf(buf,"%s:%u",inet_n2h(s->address),s->port);
	return buf;
}
/* Convert hex-ascii string to long integer */
long
htol(s)
char *s;
{
	long ret;
	char c;

	ret = 0;
	while((c = *s++) != '\0'){
		c &= 0x7f;
		if(c >= '0' && c <= '9')
			ret = ret*16 + (c - '0');
		else if(c >= 'a' && c <= 'f')
			ret = ret*16 + (10 + c - 'a');
		else if(c >= 'A' && c <= 'F')
			ret = ret*16 + (10 + c - 'A');
		else
			break;
	}
	return ret;
}
/* convert TOS specification to binary value */
int
get_tos (tos_spec)
char *tos_spec;

{
	int tos = 0;
	int c;

	if(tos_spec != NULLCHAR) {
	    while ((c = *tos_spec++) != '\0') {
		switch (toupper(c))
		{
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		    tos |= (c & 7) << 5;
		    break;

		case 'D':
		    tos |= LOW_DELAY;
		    break;

		case 'T':
		    tos |= THROUGHPUT;
		    break;

		case 'R':
		    tos |= RELIABILITY;
		    break;
		}
	    }
	}

	return tos;
}
/* convert TOS to printable string */
char *
put_tos (tos)
int tos;
{
	static char result[5];
	register char *rp = result;

	*rp++ = PREC(tos) + '0';
	if (tos & LOW_DELAY)
		*rp++ = 'D';
	if (tos & THROUGHPUT)
		*rp++ = 'T';
	if (tos & RELIABILITY)
		*rp++ = 'R';
	*rp = '\0';
	return result;
}
