/*************************************************************************/
/*                  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 <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include "proto.h"

/******* Globals ********/

extern int errno;

char	*prog_name;
char 	hostname[32];
struct	in_addr our_ipaddr;
struct	sockaddr_in sock_in;
int	logsw=0;
int	sock;
u_int	port;

int	samplesize = -1;
long	dsp_speed = -1;
int	dsp_stereo = -1;
char	audio_dev[128];
char	*au_user;
char	*audio_file;

/******** Code ********/

void main(int argc, char *argv[])
{
	struct ping_cmd pcmd;
	struct vresp vr;
	fd_set rfdset;
	char buf[255];
	int tmp_fd;

	extern int sock;
	extern struct sockaddr_in sock_in;
	
	init(argc, argv);

#ifndef VPING_INETD
	for(;;)
	{
		FD_ZERO(&rfdset);
		FD_SET(sock, &rfdset);

		if(select(FD_SETSIZE, &rfdset, (fd_set *) 0, (fd_set *) 0, 0) < 0)
		{
			perror(prog_name);
			exit(1);
		}

		if(FD_ISSET(sock, &rfdset))
		{
			if((tmp_fd = accept(sock, NULL, 0)) == -1)
			{
				perror(prog_name);
			}			
			else
			{
#else
				tmp_fd = sock;
#endif
				if(read(tmp_fd, &pcmd, sizeof(struct ping_cmd)) == sizeof(struct ping_cmd))
				{
					if(read(tmp_fd, &buf[0], pcmd.len) == pcmd.len)
					{
						/* Nun gut ... hier haben wir nun also eine */
						/* korrekte serverabfrage bekommen, und nun */
						/* wollen wir mal sehen was man denn von    */
						/* uns ueberhaupt will .... :-)             */

						buf[pcmd.len] = '\0';

						switch(pcmd.cmd)
						{
							case P_PING:	ping(tmp_fd, &pcmd, (char *)&buf);
									log(LOG_INFO, "[REQUEST: ring] %s@%s (%s) -> %s",
									pcmd.user, pcmd.host, pcmd.nick, buf);
									break;
							case P_WHO:	put_sysinf(tmp_fd);
									log(LOG_INFO, "[REQUEST: info] %s@%s (%s)",
									pcmd.user, pcmd.host, pcmd.nick);
									break;
							default:	log(LOG_NOTICE, "[REQUEST: not recognized ($%x)",
									pcmd.cmd);
									break;
						}
						close(tmp_fd);
					}
					else
					{
						vr.stat = BAD_DATA;
						vr.len = 0;
						write(tmp_fd, &vr, sizeof(struct vresp));
						sleep(1);
						close(tmp_fd);
					}
				}
				else
				{
					/* short or missing command packet */

					vr.stat = BAD_CMD;
					vr.len = 0;
					write(tmp_fd, &vr, sizeof(struct vresp));
					sleep(1);
					close(tmp_fd);
				}
#ifndef VPING_INETD
			}
		}
	}
#else
	close(sock);
	exit(0);
#endif
}

void ping(int fd, struct ping_cmd *pcmd, char *arg)
{
	struct vresp vr;
	char *tty;
	char buf[256];
	char tbuf[32];
	int tfdsc;
	time_t now;
	struct tm *ltm;

	extern char *au_user;

	tty = logged_in(arg);

	if((long)tty)
	{
		if((tfdsc = open(tty, O_WRONLY | O_NDELAY)) >= 0)
		{
			time(&now);
			ltm = localtime(&now);
			(void)strftime((char *)&tbuf, 32, "%a, %d %b %y - %T", ltm);

			sprintf(buf, "\n\n\007"
			"**** Message from vping-daemon@%s on %s   \n"
			"**** User %s@%s (%s) would like to chat to you.   \n"
			"**** Use 'vchat -s %s' to get into the dialogue.   \n\n",
			hostname, tbuf, pcmd->user, pcmd->host, pcmd->nick, pcmd->sv_host);

			write(tfdsc, &buf, strlen(buf));
			close(tfdsc);

			log(LOG_INFO, "Rang %s on %s",arg, tty);
 
			vr.stat = OK;
			vr.len = 0;
		}
		else
		{
			log(LOG_INFO, "Unable to open %s for output.", tty);

			vr.stat = TTY_OFAIL;	/* Open failed */
			vr.len = 0;		/* No further data */
		}
	}
	else if((long)tty == 0)
	{
		log(LOG_INFO, "Cannot ring %s (not logged in).", arg);
		vr.stat = NO_LOGIN;
		vr.len = 0;
	}
	else if((long)tty == -1)
	{
		log(LOG_NOTICE, "WARNING: Unable to open %s.", _PATH_UTMP);
		vr.stat = UTMP_OFAIL;
		vr.len = 0;
	}
	else if((long)tty == -2)
	{
		log(LOG_INFO, "No permission to open %s for output.", tty);
		vr.stat = NO_ACCESS;
		vr.len = 0;
	}
	write(fd, &vr, sizeof(struct vresp));

#ifdef AUDIO
	if(strcmp(au_user, arg) == 0 || strlen(au_user) == 0)
	{
		audio_out();
	}
#endif
}

char *logged_in(char *user)
{
	struct utmp ut;
	struct stat st;
	char terminal[128];
	static char ri_tty[128];
	int ufd;
	int n = 0;
	long atime = 0;


	if((ufd = open(_PATH_UTMP, O_RDONLY, 0)) == 0)
	{
		perror(prog_name);
		return((char *)-1);
	}

	while(read(ufd, &ut, sizeof(struct utmp)) == sizeof(struct utmp))
	{
		if(strncmp(ut.ut_name, user, strlen(user)) == 0)
		{
			sprintf(terminal, "/dev/%s", ut.ut_line);

			n++;

			if(access(terminal, W_OK) == 0)
			{
				if(stat(terminal, &st) == 0)
				{
					if(st.st_atime > atime || atime == 0)
					{
						strcpy(ri_tty, terminal);
						atime = st.st_atime;
					}	
				}
			}
		}
	}

	close(ufd);

	if(n == 0)			/* Keine logins gefunden */
	{
		return(NULL);
	}
	else if(n && !strlen(ri_tty))		/* Keine Zugreifbaren ttys */
	{
		return((char *)-2);
	}
	else				/* Alles klar ... */
	{
		return((char *)&ri_tty);
	}
}
