#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xauth.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>

#include "remove_xhosts.h"

char *XFamilyName(family)
{
	switch(family)
	{
#ifdef FamilyInternet
	case FamilyInternet: return "INET";
#endif
#ifdef FamilyDECnet
	case FamilyDECnet: return "DNET";
#endif
#ifdef FamilyChaos
	case FamilyChaos: return "NIS";
#endif
#ifdef FamilyKrb5Principal
	case FamilyKrb5Principal: return "KRB";
#endif
#ifdef FamilyLocalHost
	case FamilyLocalHost: return "LOCAL";
#endif
	}
	return "UnknownFamily";
}

char *HostName(char *address, int length)
{
	static char buf[1024];
	struct hostent *host;
	int i;
	char *p;

	host=gethostbyaddr(address, length, AF_INET);
	if (!host) return "UnknownHost";
	strncpy(buf, host->h_name, 1023);
	if (length>16) length=16; /* Shouldn't happen */
	buf[1021-4*length]=0; /* Truncate hostname */
	p=buf+strlen(buf);
	for (i=0; i<length; i++)
	{
		p+=sprintf(p, "%s%i", i?".":" [",
			(int)(unsigned char)address[i]);
	}
	*p++=']'; *p=0;

	return buf;
}

char *XHostName(XHostAddress *xhost)
{
	if (xhost->family!=FamilyInternet) return "";
	return HostName(xhost->address, xhost->length);
}

/* Print "Can't remove host hostname [ip] from access control list */
void ErrorRemoveHost(int dummy, void *vhost, XErrorEvent *event)
{
	XHostAddress *host=(XHostAddress *)vhost;
	char buf[1024];

	*buf=0;
	XGetErrorText(display, event->error_code, buf, 1024);

	fprintf(stderr, "Error: \"%s\" when removing host %s:%s from access "
		"control list for %s\n", buf, XFamilyName(host->family),
		XHostName(host), displayname);
}

void hosts_init()
{
	/* Get a host list and the current state of access control */
	ev_add(ErrorMessage, True, "Error: Couldn't get Xhostlist");
	hostlist=XListHosts(display, &hosts, &access_control);
}

void hosts_enableaccesscontrol()
{
	/* Enable access control if not already enabled */
	fprintf(stderr, "Warning: This X-server is insecure "
		"(now enabling access control)\n");
	ev_add(ErrorMessage, False, 
		"Couldn't enable access control");
	XEnableAccessControl(display);
}

void hosts_removeall()
{
	fprintf(stderr, "Warning: Removing all hosts from access control "
		"list for display %s.\n", displayname);
	ev_add(ErrorIgnore, False, NULL);
	XRemoveHosts(display, hostlist, hosts);
}

void hosts_remove(XHostAddress *host)
{
	fprintf(stderr, "Warning: Removing host %s:%s from access control"
		" list for display %s.\n", XFamilyName(host->family),
		XHostName(host), displayname);
	ev_add(ErrorRemoveHost, False, host);
	XRemoveHost(display, host);
}

void hosts_done()
{
	if (hostlist) XFree(hostlist);
}


