#include "global.h"
#include "commands.h"
#include "mbuf.h"
#include "netuser.h"
#include "tcp.h"
#include "domain.h"
#include "x.h"
#include "stats.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: x.c,v 1.17 1997/08/19 01:19:22 root Exp $";
#endif

#ifdef XSERVER

#ifdef HOLDMONITOR
extern int HOLDindicator;
#endif
#ifdef ALERTMONITOR
extern int ALERTindicator;
#endif

static struct xcontrol *Xclients = NULLX;
static struct xhost *Xhosts = NULLXHOST;

#ifdef ALLSERV
extern int ScreenedCall;
extern char *ScreenedCaller;
#endif
static int Sx = -1;
static const char xlistener[] = "Xwindows listener";
static const char xserver[] = "Xwindows server";
void variable_expansion (struct mbuf **bp);

#ifdef CONVERS
int CountConfUsers (void);
#endif
extern struct cmds Cmds[];
extern char *NextCmdMsg;
extern short NextCmd;


static int xhostlookup (char *name);
static void xserv (int s, void *ds, void *p);
static char *xhostchk (int s);
static int doxhosts (int argc,char *argv[],void *p);
static int doxconnected (int argc,char *argv[],void *p);


/* xwindows subcommand table */
static struct cmds Xtab[] = {
	{ "connected",		doxconnected,		0, 0, NULLCHAR },
	{ "hosts",		doxhosts,		0, 0, NULLCHAR },
	{ NULLCHAR,		NULL,			0, 0, NULLCHAR }
};



int
doxwindows (int argc, char *argv[], void *p)
{
	return subcmd(Xtab,argc,argv,p);
}



static int
doxhosts (int argc, char *argv[], void *p OPTIONAL)
{
struct xhost *x;
int i;

	if(argc == 1)		{ 	/*just list them*/
		for (x = Xhosts; x != NULLXHOST; x = x->next)
			tprintf("%s ", x->host);
		tputc('\n');
	} else { 	/* add some xhost(s) */
		for(i = 1; i < argc; i++) {
			x = callocw(1,sizeof(struct xhost));
	                x->host = strdup(argv[i]);
               		/* add to list */
	                x->next = Xhosts;
               		Xhosts = x;
        	}
       	}
       	return 0;
}



static int
doxconnected (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct xcontrol *x;

	for (x = Xclients; x != NULLX; x = x->next)
		tprintf("%s ", x->host);
	tputc('\n');
       	return 0;
}



int
xserver0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	return (deleteserver (&Sx));
}



int
xserver1 (int argc, char *argv[], void *p OPTIONAL)
{
int port = IPPORT_X;

	if (argc > 1)	{
		port = atoi (argv[1]);
		tprintf ("Starting Xserver on port %d\n", port);
	}
	return (installserver (argc, argv, &Sx, xlistener, port,
		INADDR_ANY, xserver, xserv, 512, NULL));

}



static void
xserv (int s, void *ds OPTIONAL, void *p OPTIONAL)
{
struct mbuf *bp;
int datalen;
struct xcontrol *x;

	x = (struct xcontrol *) mallocw (sizeof (struct xcontrol));
	if (x == NULLX)
		return;

	(void) sockowner(s,Curproc);	/* We own it now */
	/* Secede from the parent's sockets, and use the network socket that
	 * was passed to us for both input and output. The reference
	 * count on this socket will still be 1; this allows the domboxbye()
	 * command to work by closing that socket with a single call.
	 * If we return, the socket will be closed automatically.
	 */
	close_s(Curproc->output);
	close_s(Curproc->input);
	Curproc->output = Curproc->input = x->s = s;

	if ((x->host = xhostchk (s)) == NULLCHAR)	{
		usprintf (s,"TNOS XSession denied! No permission........\n");
		log (s, "XServer access denied!");
	} else	{
	
		log(s, "open Xserver");
#ifdef STATS_USE
		STATS_adduse (1);
		MiscUsers++;
#endif
		x->txstatusinfo = 0;
		x->next = Xclients;
		Xclients = x;
		netPrompt();
	
		/* Process input on the connection */
		for ( ; ; )	{
			if((datalen = socklen(s,0)) > 0)	{
				if (recv_mbuf(s,&bp,0,NULLCHAR,0) == -1)
					break;
				variable_expansion (&bp);
				if (!strnicmp ((char *)bp->data, "ex", 2))
					break;
				if (!strnicmp ((char *)bp->data, "bbs", 2))	{
					tprintf (SCMD"start_bbs_session"ECMD);
					continue;
				}
				if (!strnicmp ((char *)bp->data, "txstat", 6))	{
					char *cp;
					cp = skipnonwhite ((char *)bp->data);
					cp = skipwhite (cp);
					x->txstatusinfo = atoi(cp);
					xnotify (X_ALL);
				} else
					(void)cmdparse(Cmds, (char *)bp->data, NULL);
				free_p(bp);
				netPrompt();
			} else if(datalen < 0)
				break;
			if (!datalen)
				(void) kpause (500);
		}
#ifdef STATS_USE
		MiscUsers--;
#endif
		free (x->host);

		if (Xclients == x)
			Xclients = x->next;
		else	{
			struct xcontrol *xp;

			for (xp = Xclients; xp != NULLX; xp = xp->next)	{
				if (xp->next == x)	{
					xp->next = x->next;
					break;
				}
			}
		}
	}
	close_s(s);
	s = -1;
}



void
xnotify (int which)
{
struct xcontrol *x;

	for (x = Xclients; x != NULLX; x = x->next)	{
		if (!x->txstatusinfo)
			continue;
		if (which & X_BBS)
			usprintf (x->s, SCMD"set STATbbs %d"ECMD, BbsUsers);
#ifdef CONVERS
		if (which & X_CONF)
			usprintf (x->s, SCMD"set STATconf %d"ECMD, CountConfUsers());
#endif
		if (which & X_FTP)
			usprintf (x->s, SCMD"set STATftp %d"ECMD, FtpUsers);
		if (which & X_TUT)
			usprintf (x->s, SCMD"set STATtut %d"ECMD, Tutored);
#ifdef ALLSERV		
		if (which & X_SCREEN)  {
			usprintf (x->s, SCMD"set STATscreencaller %s"ECMD,
				(ScreenedCaller) ? ScreenedCaller : "(none)");
			usprintf (x->s, SCMD"set STATscreen %d"ECMD, ScreenedCall);
		}
#endif	
#ifdef HOLDMONITOR
		if (which & X_HOLD)
			usprintf (x->s, SCMD"set STAThold %d"ECMD, HOLDindicator);
#endif
#ifdef ALERTMONITOR
		if (which & X_ALERT)
			usprintf (x->s, SCMD"set STATalert %d"ECMD, ALERTindicator);
#endif
		if (which & X_MSG)	{
			char *cp, *cp2;
			cp = strdup ((NextCmd) ? NextCmdMsg : "");
			while ((cp2 = strpbrk (cp, "[]{}")) != NULLCHAR)
				*cp2 = ' ';
			usprintf (x->s, SCMD"set STATmsg { %s}"ECMD, cp);
			free (cp);
		}
	}
}



static char *
xhostchk (int s)
{
struct sockaddr fsocket;
int i, trans;
char *retval = NULLCHAR;
char *cptr, *cptr2;

	i = SOCKSIZE;
	trans = DTranslate; /* Save IP address translation state */
	DTranslate = 0;     /* Force output to be numeric IP addr*/
	if (getpeername(s,(char *)&fsocket,&i) != -1)	{
		cptr = psocket(&fsocket);
		if ((cptr2 = strchr(cptr, ':')) != NULLCHAR)
			*cptr2 = 0;
		if (xhostlookup (cptr))
			retval = strdup (cptr);
	}
	DTranslate = trans;             /* Restore original state */
	return retval;
}



static int
xhostlookup (char *name)
{
struct xhost *x;

	for (x = Xhosts; x != NULLXHOST; x = x->next) {
		if (!stricmp (x->host, name))
			return 1;
	}
	return 0;
}


#endif /* XSERVER */
