/*************************************************************************/
/*                  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.                            */ 
/*************************************************************************/

#include "../config.h"
#include "../global.h"
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include "proto.h"

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

void connect_server(void)
{
	/* Ok... hier wollen wir nun also den Vchat server */
	/* connecten, und vorallem auch erstmal sehen ob   */
	/* uns das ueberhaupt gelingt :-)                  */

	extern char *prog_name;
	extern char myhost[];
	extern char svhost[];
	extern char user[];
	extern char nick[];
	extern struct in_addr my_ip;
	extern struct in_addr sv_ip;

	extern struct sockaddr_in sock_in;
	extern struct client_data cl_dat;
	extern int sock;
	extern int port;
	extern int color;

	struct client_data rcv_dat;
#ifdef VSERVER_INETD
	struct servent *sv;
#endif

#ifdef SLIP_FIX
	struct timeval to;
#endif
	int c, i;

#ifdef VSERVER_INETD
	if(!(sv = getservbyname("vchat", "tcp")))
	{
		fprintf(stderr, "%s: tcp/vchat unknown service.\n\n", prog_name);
		exit(1);
	}

	if(port == htons(SERVER_PORT))
		sock_in.sin_port = sv->s_port;
	else
		sock_in.sin_port = port;
#else
	sock_in.sin_port = port;
#endif
	sock_in.sin_family = AF_INET;
	bcopy(&sv_ip, &sock_in.sin_addr, sizeof(sv_ip));
	
	if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror(prog_name);
		exit(1);
	}

/****** The following is alpha-code currently not supported by Linux ******/

#ifdef SLIP_FIX
	to.tv_sec = RCVTMOUT_SEC;
	to.tv_usec = RCVTMOUT_USEC;

	if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(struct timeval)) == -1)
	{
		perror(prog_name);
		exit(1);
	}
#endif

/***************************************************************************/

	printf("\nTrying to connect vchat server at %s [%s] port %d.\n",
		svhost, inet_ntoa(sock_in.sin_addr),
		ntohs(sock_in.sin_port));

	if(connect(sock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0)
	{
		fprintf(stderr, "Unable to connect server (%s)\n\n", strerror(errno));
		exit(1);
	}

	strcpy(cl_dat.user, user);
	strcpy(cl_dat.nick, nick);
	strcpy(cl_dat.host, myhost);
	cl_dat.channel = 0;
	bcopy(&my_ip, &cl_dat.ip_addr, sizeof(my_ip));
	cl_dat.fd = 0;

	printf("Connected -- ");
	write(sock, &cl_dat, sizeof(struct client_data));

	if((read(sock, &rcv_dat, sizeof(struct client_data)) == sizeof(struct client_data))\
	&& memcmp(&cl_dat, &rcv_dat, sizeof(struct client_data)) == 0)
	{
		fcntl(sock, F_SETOWN, getpid());
		printf("login ok.\n\n");
		sleep(1);
	}
	else
	{
		printf("login failed.\n\n");

		if(strcmp(rcv_dat.nick, "--invalid") == 0)
		{
			close(sock);
			fprintf(stderr, "%s: Specified nickname '%s' is already in use.\n", prog_name, cl_dat.nick);
			fprintf(stderr, "%*s  Start vchat using another nickname again.\n\n", strlen(prog_name), " ");
			exit(1);
		}
		else
		{
			close(sock);
			fprintf(stderr, "%s: failed server initialization sequence -- try again\n\n", prog_name);
			exit(1);
		}
	}
}

void rcv_sv_msg(void)
{
	/* Empfangen einer Servermessage. Diese Routine */
	/* prueft eingehende Daten auf auszufuehrende   */
	/* commands des servers.                        */

	extern int sock;
	static char buffer[SVMSGBUF];
	struct serv_msg svmsg;
	int c = 0;
	int i;
	int result;
	
	for(i=0; i<SVMSGBUF; i++)	/* Clear buffer */
		buffer[i] = '\0';

	if((result=read(sock, &svmsg, sizeof(struct serv_msg))) == sizeof(struct serv_msg))
	{
		if((result=read(sock, &buffer, svmsg.len)) == svmsg.len)
		{
			switch(svmsg.cmd)
			{
				case SERV_MSG:	cprintf(0, "%s",buffer);
						break;
				default:	cprintf(0, "* unknown command byte from server ($%x).\n",
							svmsg.cmd);
						break;
			}
		}
		else
		{
			cprintf(0, "* WARNING: received short data package from server.\n");
			if(result <= 0){
				sleep(1);
				quit(0,"* WARNING: server connection shutdown -- exiting.\n");
			}
		}
	}
	else
	{
		cprintf(0, "* WARNING: received short command sequence from server.\n");

		if(result <= 0)
		{
			sleep(1);
			quit(0,"* WARNING: server connection shutdown -- exiting.\n");
		} 
	}
}

void snd_serv(int cmd, char *data, long siz)
{
	extern int sock;
	struct serv_msg svmsg;
	char c;

	svmsg.cmd = cmd;
	svmsg.len = siz;

	write(sock, &svmsg, sizeof(struct serv_msg));

	if(data && siz)
		write(sock, data, siz);
}

void flush_buf(void)
{
	extern int sock;
	char c[1024];

	while(read(sock, &c, 1024) > 0);
}
