/* fwhois.c by Ang3ldust (Chris Cappuccio) <ccappuc@santafe.edu>
 * Networking code taken and modified from net.c in the finger source code
 *
 * Added :port notation to the hostname
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef _WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#  include <winsock2.h>
#  include <io.h>
#else
#  include <sys/types.h>
#  include <sys/socket.h>
#  include <netinet/in.h>
#  include <netdb.h>
#  define __cdecl         /*nothing*/
#endif

#ifndef _WIN32
#  define SOCKET			int
#  define closesocket(fd)	close(fd)
#endif

static unsigned int portno = 43;		/* tcp/43 = "whois" -- this won't change much */
static char         whobuf[256];

static void netfinger(char *name);

int __cdecl main(int argc, char **argv)
{
	if ( argc != 2 )
	{
		printf("usage: fwhois user[@<whois.server> [:portno] ]\n");
		exit(1);
	}

	strcpy(whobuf, argv[1]);

	if ( strchr(whobuf, '@') == 0 )
		strcat(whobuf, "@whois.internic.net");

	netfinger(whobuf);

	exit(EXIT_SUCCESS);
}

/*
 * init_winsock()
 *
 *	Initialize the Winsock systems
 */

#ifdef _WIN32
static void init_winsock()
{
WORD	wVersion = MAKEWORD(2,2);
WSADATA	wsaData;
DWORD	err;

	if ( (err = (DWORD)WSAStartup(wVersion, &wsaData)) != 0 )
	{
		fprintf(stderr, "ERROR: got err#%d from Winsock init\n", err);
		exit(EXIT_FAILURE);
	}

}
#endif

static void netfinger(char *name)
{
	int      nr;
	char *pport;
	char  iobuf[256];
	register int lastc = 0;
	struct in_addr defaddr;
	struct hostent *hp, def;
	struct sockaddr_in sin;
	SOCKET s;
	char *alist[1], *host;

	if ((host = strrchr(name, '@')) == 0 )
	{
		fprintf(stderr, "ERROR: don't know what host to query\n");
		return;
	}

	*host++ = '\0';	/* smoosh the @ sign to separate name from host */

	if ( (pport = strchr(host, ':')) != 0 )
	{
		*pport++ = '\0';
		portno = atoi(pport);
	}

#ifdef _WIN32
	init_winsock();
#endif

	if (!(hp = gethostbyname(host)))
	{
		defaddr.s_addr = inet_addr(host);
		if (defaddr.s_addr == -1)
		{
			fprintf(stderr, "fwhois: unknown host: %s\n",host);
			return;
		}
		def.h_name = host;
		def.h_addr_list = alist;
		def.h_addr = (char *)&defaddr;
		def.h_length = sizeof(struct in_addr);
		def.h_addrtype = AF_INET;
		def.h_aliases = 0;
		hp = &def;
	}

	/*----------------------------------------------------------------
	 * Look up the port name if the user didn't give one. This is
	 * nearly always "whois"
	 */
	if ( portno == 0 )
	{
	struct servent *sp;

		if ( (sp = getservbyname("whois", "tcp")) == 0 )
		{
			fprintf(stderr, "fwhois: tcp/whois: unknown service\n");
			return;
		}

		portno = ntohs(sp->s_port);
	}

	sin.sin_family = hp->h_addrtype;
/*	bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); */
	memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);

	sin.sin_port = htons((short)portno);

#ifdef _WIN32
	if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) == INVALID_SOCKET )
#else
	if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
#endif
	{
		perror("fwhois: socket");
		return;
	}

	/* have network connection; identify the host connected with */
	printf("[%s]\n", hp->h_name);

	if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	{
		perror("fwhois: connect");
		closesocket(s);
		return;
	}

	/* send the name followed by <CR><LF> */
	nr = sprintf(iobuf, "%s\r\n", name);

	send(s, iobuf, nr, 0);

	while ( (nr = recv(s, iobuf, sizeof iobuf, 0)) > 0 )
	{
		char *maxread = iobuf + nr;
		char *p       = iobuf;

		while ( p < maxread )
		{
			int	c = *p++ & 0x7F;

			if (c == '\r')
			{
				lastc = '\r';
				c = '\n';
			}
			else
			{
				if (!isprint(c) && !isspace(c))
					c |= 0x40;
				if (lastc != '\r' || c != '\n')
					lastc = c;	
				else
				{
					lastc = '\n';
					continue;
				}
			}
			putchar(c);
		}
	}

	if (lastc != '\n')
		putchar('\n');
	fflush(stdout);
}