/*  Class to act as a cover for Internet addresses.
 *
 *  Copyright (c) 1994 Christopher J. Kane.
 *
 *  This software is subject to the terms of the MiscKit license
 *  agreement. Refer to the license document included with the
 *  MiscKit distribution for these terms.
 *
 *  Version 1.0 BETA (20 April 1994)
 */

#import <misckit/MiscINETAddress.h>
#import <libc.h>
#import <netdb.h>
#import <sys/errno.h>
extern char *NXCopyStringBuffer(const char *);
extern int errno;

MiscINETAddress *localAddress = nil;

@implementation MiscINETAddress

+ localAddress
{
	if (localAddress == nil) {
		struct sockaddr_in sockaddr;
		int len = sizeof(sockaddr), old_errno = errno;
		int sock = socket(PF_INET, SOCK_DGRAM, 0);
		if (0 <= sock && 0 <= getsockname(sock, (struct sockaddr *)&sockaddr, &len)) {
			close(sock);
			errno = old_errno;
			localAddress = [[MiscINETAddress alloc] initTo:sockaddr.sin_addr];
		} else {
			char host[MAXHOSTNAMELEN+1];
			gethostname(host, MAXHOSTNAMELEN);
			errno = old_errno;
			localAddress = [[MiscINETAddress alloc] initFromName:host];
		}
	}
	return localAddress;
}

- init
{
	if (hostname != NULL)
		free(hostname);
	address.s_addr = 0;
	hostname = NULL;
	return self;
}

- initFromName:(const char *)name
{
	int old_errno = errno;
	struct hostent *hent = gethostbyname((char *)name);
	[self init];
	if (hent == NULL) {
		unsigned long tmp = inet_addr((char *)name);
		if (tmp == -1) {
			errno = EINVAL;
			return [super free];
		}
		address.s_addr = tmp;
	} else
		memcpy(&address, hent->h_addr, hent->h_length);
	hostname = NULL;
	errno = old_errno;
	return self;
}

- initTo:(struct in_addr)addr
{
	[self init];
	if (addr.s_addr == -1) {
		errno = EINVAL;
		return [super free];
	}
	address = addr;
	return self;
}

- copyFromZone:(NXZone *)zone
{
	MiscINETAddress *copy = [super copyFromZone:zone];
	if (hostname != NULL)
		copy->hostname = NXCopyStringBuffer(hostname);
	return copy;
}

- free
{
	if (hostname != NULL)
		free(hostname);
	return [super free];
}

- read:(NXTypedStream *)stream;
{
	[super read:stream];
	NXReadTypes(stream, "L*", &(address.s_addr), &hostname);
	return self;
}

- write:(NXTypedStream *)stream
{
	[super write:stream];
	NXWriteTypes(stream, "L*", &(address.s_addr), &hostname);
	return self;
}

- (struct in_addr)address
{
	return address;
}

- (char *)hostname
{
	int old_errno = errno;
	if (hostname == NULL) {
		struct hostent *hent = gethostbyaddr((char *)&address, sizeof(address), AF_INET);
		if (hent == NULL || hent->h_name == NULL)
			hostname = NXCopyStringBuffer(inet_ntoa(address));
		else
			hostname = NXCopyStringBuffer(hent->h_name);
	}
	errno = old_errno;
	return hostname;
}

- (char *)stringAddress
{
	return inet_ntoa(address);
}

@end
