/* Autoconf patching by David Hedbor, neotron@lysator.liu.se */
/*********************************************************************/
/* file: net.c - do all the net stuff                                */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/

#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif

#include <ctype.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include "tintin.h"

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <arpa/inet.h>
#endif

/* NOTE!  Some systems might require a #include <net/errno.h>,
 * try adding this if you are really stuck and net.c won't compile.
 * Thanks to Brian Ebersole [Harm@GrimneMUD] for this suggestion.
 */

void do_telnet_protecol();

extern int sessionsstarted, ticker_interrupted;
extern struct listnode *common_aliases, *common_actions, *common_subs;
extern struct session *sessionlist, *activesession;
extern int errno;

static void alarm_handler( /* void */ )
{
/* do nothing; the connect will fail, returning -1, with errno = EINTR */
}

/**************************************************/
/* try connect to the mud specified by the args   */
/* return fd on success / 0 on failure            */
/**************************************************/
int connect_mud(host, port, ses)
     char *host;
     char *port;
     struct session *ses;
{
	int sock, connectresult;
	struct sockaddr_in sockaddr;

	if (isdigit(*host))	/* interprete host part */
		sockaddr.sin_addr.s_addr = inet_addr(host);
	else {
		struct hostent *hp;
		if ((hp = gethostbyname(host)) == NULL) {
			tintin_puts("#ERROR - UNKNOWN HOST.", ses);
			prompt(NULL);
			return 0;
		}
		memcpy((char *) &sockaddr.sin_addr, hp->h_addr, sizeof(sockaddr.sin_addr));
	}

	if (isdigit(*port))
		sockaddr.sin_port = htons(atoi(port));	/* inteprete port part */
	else {
		tintin_puts("#THE PORT SHOULD BE A NUMBER.", ses);
		prompt(NULL);
		return 0;
	}

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		syserr("socket");

	sockaddr.sin_family = AF_INET;


	tintin_puts("#Trying to connect..", ses);

	/* ignore the alarm: it'll cause the connect to return -1 with errno=EINTR */
	if (signal(SIGALRM, alarm_handler) < 0)
		syserr("signal SIGALRM");
	alarm(30);		/* We'll allow connect to hang in 15seconds! NO MORE! */

#ifdef SOCKS
	connectresult = Rconnect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr));
#else
	connectresult = connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr));
#endif

	alarm(0);

	if (connectresult) {
		close(sock);
		switch (errno) {
		case EINTR:
			tintin_puts("#CONNECTION TIMED OUT.", ses);
			break;
		case ECONNREFUSED:
			tintin_puts("#ERROR - CONNECTION REFUSED.", ses);
			break;
		case ENETUNREACH:
			tintin_puts("#ERROR - THE NETWORK IS NOT REACHABLE FROM THIS HOST.", ses);
			break;
		default:
			tintin_puts("#Couldn't connect", ses);
		}
		prompt(NULL);
		return 0;
	}
	return sock;
}

/************************************************************/
/* write line to the mud ses is connected to - add \n first */
/************************************************************/
void write_line_mud(line, ses)
     char *line;
     struct session *ses;
{
	char outtext[BUFFER_SIZE + 2];

	strcpy(outtext, line);
	strcat(outtext, "\n\r");

	if (write(ses->socket, outtext, strlen(outtext)) == -1)
		syserr("write in write_to_mud");
}


/*******************************************************************/
/* read at most BUFFER_SIZE chars from mud - parse protecol stuff  */
/*******************************************************************/
int read_buffer_mud(buffer, ses)
     char *buffer;
     struct session *ses;
{
	int i, didget;
	char tmpbuf[BUFFER_SIZE], *cpsource, *cpdest;
	didget = read(ses->socket, tmpbuf, 512);
	ses->old_more_coming = ses->more_coming;
	if (didget == 512)
		ses->more_coming = 1;
	else
		ses->more_coming = 0;
	if (didget < 0)
		return 0;	/*syserr("read from socket");  we do this here instead - dunno quite 
				   why, but i got some mysterious connection read by peer on some hps */

	else if (didget == 0)
		return 0;

	else {
		cpsource = tmpbuf;
		cpdest = buffer;
		i = didget;
		while (i > 0) {
			if (*(unsigned char *) cpsource == 255) {
				do_telnet_protecol(*cpsource, *(cpsource + 1), *(cpsource + 2), ses);
				i -= 3;
				cpsource += 3;
			}
			else {
				*cpdest++ = *cpsource++;
				i--;
			}
		}
	}
	*cpdest = '\0';
	return didget;
}


/*****************************************************************/
/* respond according to the telnet protecol - weeeeelllllll..... */
/*****************************************************************/
void do_telnet_protecol(dat0, dat1, dat2, ses)
     int dat0;
     int dat1;
     int dat2;
     struct session *ses;
{
/* we don't do anything here.. why should we? add the stuff yourself if
   you feel like being nice..... */
}