/*************************************************************************/
/*                  VChat interactive IP-level chat system               */
/*-----------------------------------------------------------------------*/
/*  (c) '93/'94 by Andreas S. Wetzel (mickey@deadline.bln.sub.org)       */
/*                 All rights reserverd.                                 */ 
/*-----------------------------------------------------------------------*/
/* See the file COPYRIGHT in the top level directory of VChat for        */
/* copyright notices and further disclaimers.                            */ 
/*************************************************************************/

/********** Includes *********/

#include "../config.h"
#include "../global.h"
#include "../version.h"
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include "proto.h"

void init(int argc, char *argv[])
{
	/* Ok .... Erstmal die initialisierung des ganzen */

	extern char *prog_name;
	extern char hostname[];
	extern char *optarg;
	extern int optind;
	extern int opterr;
	extern int optopt;
	extern struct in_addr our_ipaddr;
	extern struct sockaddr_in sock_in;
	extern int logsw;
	extern int port;
	extern int sock;

	extern int samplesize;
	extern long dsp_speed;
	extern int dsp_stereo;
	extern char audio_dev[];
	extern char *audio_file;
	extern char *au_user;

	struct hostent *h_ent;
	struct servent *sv;
	int sock_in_len = 0;
	int i, opt;
#ifdef SLIP_FIX
	struct timeval to;
#endif		
	prog_name = argv[0];

#ifndef VPING_INETD
	port = PING_PORT;
#endif

	/* So mal sehen ob wir was brauchbares auf der Commandline finden. */

#ifdef VPING_INETD
#ifdef AUDIO
	audio_dev[0] = '\0';

	while((opt = getopt(argc, argv, ":a:b:d:ls:Su:")) != -1)
#else
	while((opt = getopt(argc, argv, ":l")) != -1)
#endif
#else
#ifdef AUDIO
	audio_dev[0] = '\0';

	while((opt = getopt(argc, argv, ":a:b:d:lp:s:Su:")) != -1)
#else
	while((opt = getopt(argc, argv, ":lp:")) != -1)
#endif
#endif
	{
		switch(opt)
		{
#ifdef AUDIO
			case 'a':	audio_file = optarg;
					break;
			case 'b':	samplesize = atoi(optarg);
					if(samplesize != 8
					&& samplesize != 12
					&& samplesize != 16)
					{
						usage("Invalid samplesize (%d) -- must be 8, 12 or 16 bits/sample", samplesize);
						exit(1);
					}
					break;
			case 'd':	strcpy(audio_dev, optarg);
					break;
			case 's':	dsp_speed = atoi(optarg);
					break;
			case 'S':	dsp_stereo = 1;
					break;
			case 'u':	au_user = optarg;
					break;
#endif
			case 'l':	logsw = 0xff;
					break;
#ifndef VPING_INETD
			case 'p':	port = htons(atoi(optarg));
					break;
#endif
			case ':':	usage("Option -%c requires an argument.", optopt);
					exit(1);
					break;
			case '?':	usage("Unrecognized option: -%c", optopt);
					exit(1);
					break;

		}
	}

	/* Log oeffnen wenn gewuenscht. */

	if(logsw)
	{
		openlog(prog_name, LOG_NDELAY, LOG_LOCAL1);
	}

	/* So mal sehen wie die Kiste heisst auf der wir laufen. */

	if((char *)gethostname(hostname, 32) != NULL)
	{
		log(LOG_ERR, "%m");
		exit(1);
	}

	/* IP-Adresse unserer Kiste rausfinden. */

	if((h_ent = gethostbyname(hostname)) != NULL)
	{
		bzero(&our_ipaddr, sizeof(our_ipaddr));
		bcopy((char *)h_ent->h_addr_list[0], (char *)&our_ipaddr, h_ent->h_length);
	}
	else
	{
		log(LOG_ERR, "%m");
		exit(1);
	}

	bzero((char *)&sock_in, sizeof(sock_in));

#ifndef VPING_INETD
	sock_in.sin_family = AF_INET;
	sock_in.sin_port = port;
	sock_in.sin_addr.s_addr = INADDR_ANY;

	if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		log(LOG_ERR, "%m");
		exit(1);
	}
#ifdef SLIP_FIX
	to.tv_sec = RCVTMOUT_SEC;
	to.tv_usec = RCVTMOUT_USEC;

	if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *) &to, sizeof(to)) == -1)
	{
		log(LOG_ERR, "%m");
		close(sock);
		exit(1);
	}
#endif
	if(bind(sock, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
	{
		log(LOG_ERR, "%m");
		close(sock);
		exit(1);
	}
#else
	sock_in_len = sizeof(sock_in);
	sock = dup(0);

	if(getpeername(sock, (struct sockaddr *)&sock_in, &sock_in_len) < 0)
	{
		log(LOG_ERR, "%m");
		exit(1);
	}
#endif

#ifndef VPING_INETD
	if(listen(sock, 1))
	{
		log(LOG_ERR, "%m");
		close(sock);
		exit(1);
	}
#endif
}

void usage(char *fmt, ...)
{
	va_list ap;
	extern char *prog_name;

#ifdef SunOS
	va_start(ap);
#else
	va_start(ap, fmt);
#endif

	fprintf(stderr, "\n");
	fprintf(stderr, "Vchat interactive IP level chat system -- %s\n", VERSION);
	fprintf(stderr, "(c) 1993/94 by mickey@deadline.uucp (Andreas S. Wetzel)\n\n");
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, "\n\n");
#ifndef VPING_INETD
#ifdef AUDIO
	fprintf(stderr, "USAGE:    %s [-a <file>] [-b 8|12|16] [-d <dev>] [-l] [-p <port>]\n", prog_name);
	fprintf(stderr, "          %*s [-s <hz>] [-S] [-u <user>]\n\n", strlen(prog_name), " ");
#else
	fprintf(stderr, "USAGE: %s [-l] [-p <port>]\n\n", prog_name);
#endif
#else
#ifdef AUDIO
	fprintf(stderr, "USAGE:    %s [-a <file>] [-b 8|12|16] [-d <dev>] [-l] [-s <hz>] [-S]\n", prog_name);
	fprintf(stderr, "          %*s [-u <user>]\n\n", strlen(prog_name), " ");
#else
	fprintf(stderr, "USAGE:    %s [-l]\n\n", prog_name);
#endif /* AUDIO */
#endif /* !VPING_INETD */
#ifdef AUDIO
	fprintf(stderr, "OPTIONS:  -a <file>    Sample file for audio output.\n");
	fprintf(stderr, "          -b 8|12|16   Bits per sample.\n");
	fprintf(stderr, "          -d <dev>     Device for audio output.\n");
	fprintf(stderr, "          -l           Enable logging via syslog.\n");
#else
	fprintf(stderr, "OPTIONS:  -l           Enable logging via syslog.\n");
#endif
#ifndef VPING_INETD
	fprintf(stderr, "          -p <port>    Use TCP port <port>.\n");
#endif
#ifdef AUDIO
	fprintf(stderr, "          -s <hz>      Audio playback frequency.\n");
	fprintf(stderr, "          -S           Audio output stereo\n"); 
	fprintf(stderr, "          -u <user>    Username for audible chat bell.\n");
#endif
#ifdef VPING_INETD
	fprintf(stderr, "\n\n");
	fprintf(stderr, "NOTE:     This binary of the vping server is to be run under the\n");
	fprintf(stderr, "          inetd super-server only.\n");
#endif
	fprintf(stderr, "\n");

	va_end(ap);
}

void log(int pri, char *fmt, ...)
{
	va_list ap;
	extern int logsw;

#ifdef SunOS
	va_start(ap);
#else
	va_start(ap, fmt);
#endif

	if(logsw)
	{
		vsyslog(pri, fmt, ap);
	}

	va_end(ap);	
}

void put_sysinf(int fd)
{
	double	loadavg[3];
	time_t now;
	struct stat devstat;
	struct utmp myuser;
	static struct sysinfo sys;
	static struct u_info ut[MAXUSERS];

	char tmp[256];
	char *sulz;
	int nelem = 3;
	int i;
	long nusers = 0;
	FILE *uf;
	FILE *fp;

	/* Als erstes wollen wir die Load average des Systems */
	/* auf einer Basis von 15 min - 5 min - 1 min wissen. */

#if defined(SunOS)
	nelem = -1;
#elif defined(Linux)
	if((fp = fopen("/proc/loadavg", "r")) == NULL)
	{
		nelem = -1;
	}
	else
	{
		if(fscanf(fp, "%lf%lf%lf", &loadavg[2], &loadavg[1], &loadavg[0]) != 3)
			nelem = -1;
		else
			nelem = 3;

		fclose(fp);
	}
#else
	getloadavg(loadavg, nelem);
#endif

	if(nelem == -1)
	{
		sys.loadavg[0] = sys.loadavg[1] = sys.loadavg[2] = 0;
	}
	else
	{
		for(i=0; i<nelem; i++)
		{
			sys.loadavg[i] = loadavg[i];
		}
	}

	/* So jetzt wollen wir doch mal sehen was man aus */
	/* der utmp datei so alles rauspressen kann :-)   */

	time(&now);

	if((uf = fopen(_PATH_UTMP, "r")) == NULL)
	{
		sys.nusers = 0;
	}
	else
	{
		while((fread(&myuser, 1, sizeof(struct utmp), uf) == sizeof(struct utmp) && nusers < MAXUSERS))
		{
#ifdef Linux
			if(strlen(myuser.ut_user) == 0)
#else
			if(strlen(myuser.ut_name) == 0)
#endif
				continue;

			/* Berechnen der Daten fuer u_info */

#ifdef Linux
			strcpy((char *)&ut[nusers].u_name, myuser.ut_user);
#else
			strcpy((char *)&ut[nusers].u_name, myuser.ut_name);
#endif

			strcpy((char *)&ut[nusers].u_line, myuser.ut_line);
			strcpy((char *)&ut[nusers].u_host, myuser.ut_host);

			if((sulz = (char *)strchr(ut[nusers].u_host, '.')) != NULL)
				*sulz = '\0';

			ut[nusers].u_time = myuser.ut_time;

			ut[nusers].u_online = (now - ut[nusers].u_time);

			sprintf(tmp, "/dev/%s", ut[nusers].u_line);

			(void) stat(tmp, &devstat);		

			ut[nusers].u_idle = (now - devstat.st_atime);

			nusers++;
		}

		sys.nusers = nusers;
		fclose(uf);
	}		

	write(fd, &sys, sizeof(sys));

	for(i=0; i<nusers; i++)
	{
		write(fd, &ut[i], sizeof(struct u_info));
	}
}

