/*
    Pirate Bulletin Board System
    Copyright (C) 1990, Edward Luke

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


    Email address:
    lush@Athena.EE.MsState.EDU
*/
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <sys/param.h>

#define MAXPORTS 32
#define YEA       1
#define NA        0


main(ac,av)
int ac ;
char **av ;
{
	int sock, msgsock, length, chatport ;
	struct sockaddr_in server ;
	int numports ;
	int portfds[MAXPORTS] ;
    char hostname[MAXHOSTNAMELEN] ;
    struct hostent *h ;

    if(gethostname(hostname,sizeof(hostname))) {
        perror("gethostname") ;
        exit(-1) ;
    }
    if(!(h = gethostbyname(hostname))) {
        perror("gethostbyname") ;
        exit(-1) ;
    }
            
	numports = 0 ;
	if(ac != 2) {
		fprintf(stderr,"Invalid arguments\n") ;
		exit(-1) ;
	}
    signal(SIGHUP,SIG_IGN) ;
	signal(SIGINT,SIG_IGN) ;
	signal(SIGQUIT,SIG_IGN) ;
	signal(SIGPIPE,SIG_IGN) ;
	signal(SIGALRM,SIG_IGN) ;
	signal(SIGTERM,SIG_IGN) ;
	signal(SIGURG,SIG_IGN) ;
	signal(SIGTSTP,SIG_IGN) ;
	signal(SIGTTIN,SIG_IGN) ;
	signal(SIGTTOU,SIG_IGN) ;	
    chatport = atoi(av[1]) ;
#ifndef DEBUG
	if (fork())
	  exit(0) ;
	{ int s, ndescriptors = getdtablesize() ;
	  for(s=0; s < ndescriptors; s++) ;
	  (void) close(s) ;
    }
	(void) open("/", O_RDONLY) ;
	(void) dup2(0, 1) ;
	(void) dup2(0, 2) ;
	{ int tt = open("/dev/tty", O_RDWR) ;
	  if(tt > 0) {
		  ioctl(tt, TIOCNOTTY, (char *) 0) ;
		  (void) close(tt) ;
	  }
    }
#endif
	openlog("chat.bbs", LOG_PID, LOG_DAEMON) ;
	sock = socket(AF_INET, SOCK_STREAM, 0) ;
	if(sock < 0) {
		syslog(LOG_ERR, "error on socket call: %m") ;
		return -1 ;
	}

	server.sin_family = AF_INET ;
	server.sin_addr.s_addr = INADDR_ANY ;
	server.sin_port = chatport ;
	if(bind(sock, (struct sockaddr *) & server, sizeof server) < 0) {
		syslog(LOG_ERR, "error on bind: %m") ;
		return -1 ;
	}
	length = sizeof server ;
	if(getsockname(sock, (struct sockaddr *) &server, &length) < 0) {
		syslog(LOG_ERR,"error on getting socket name: %m") ;
		return -1 ;
	}
	listen(sock,5) ;
	while(YEA) {
		fd_set readfds ;
		int sr ;
		int i ;

		FD_ZERO(&readfds) ;
		FD_SET(sock,&readfds) ;
		for(i = 0; i < numports; i++)
		  FD_SET(portfds[i],&readfds) ;
		if((sr = select(getdtablesize(), &readfds, NULL, NULL, NULL)) < 0) {
			syslog(LOG_ERR,"select: %m")  ;
			exit(-1) ;
		}
		if(sr == 0)
		  continue ;
		if(FD_ISSET(sock,&readfds)) {
			int s ;
			struct sockaddr_in name ;
            int len = sizeof(name) ;
            char *msg = "NON-LOCAL Connections to chatd not allowed\n" ;

			s = accept(sock, (struct sockaddr *)0, (int *) 0) ;
			if(s == -1) {
				syslog(LOG_ERR,"accept: %m") ;
				continue ;
			}
            if(getpeername(s,&name,&len) == -1) {
                syslog(LOG_ERR,"getpeername: %m") ;
                close(s) ;
                continue ;
            }
            if(bcmp(h->h_addr,&name.sin_addr,sizeof(name.sin_addr))) {
                write(s,msg,strlen(msg)) ;
                close(s) ;
                syslog(LOG_ERR,"NON-LOCAL connection booted") ;
                continue ;
            }

			portfds[numports] = s ;
			numports++ ;
			if(sr == 1)
			  continue ;
		}
		for(i = 0; i < numports; i++)
		  if(FD_ISSET(portfds[i],&readfds)) {
			  char buf[80];
			  int cc ;

			  cc = read(portfds[i],buf,80) ;
			  if(cc == 0) {
				  int j ;
				  close(portfds[i]) ;
				  for(j=i;j<numports-1;j++)
					bcopy(&portfds[j+1],&portfds[j],sizeof(int)) ;
				  numports-- ;
				  i-- ;
				  /* if(numports == 0)
					exit(0) ; */
				  continue ;
			  }
			  while(YEA) {
				  int j ;
				  for(j=0; j < numports; j++)
					write(portfds[j],buf,cc) ;
				  if(buf[cc-1] == '\0')
					break ;  /* all complete messages end in newline */
				  cc = read(portfds[i],buf,80) ;
				  if(cc <= 0)
					break ;
			  }
		  }
	}
}


