/*
 * bbsend.c 
 *
 * BIG BROTHER CLIENT PROGRAM FUNCTION
 * Sean MacGuire
 * Version 1.9 
 * Mar 13th, 2002
 *
 * (c) Copyright Quest Software, Inc.  1997-2002  All rights reserved.
 *
 * FUNCTION THAT SENDS THE INPUT LINE TO THE DAEMON ON THE BIG BROTHER PORT
 *
 */

#include "bb.h"		/* THE BIG BROTHER INCLUDE FILE */
#include <ctype.h>
#include <netdb.h>	/* SMM 1.10 FOR DDNS */

static char *ipaddr;
static int  rc;

#define	BBAGENT	""

#ifdef SIGSETJMP
sigjmp_buf jmpenv; 
#else
jmp_buf jmpenv;
#endif

static void bbsend_timeout()
{
char errormsg[MAXLINE];

	sprintf(errormsg,"CONNECTION TO %s TIMED OUT...", ipaddr);
	bb_errmsg(NULL,errormsg);
	rc = 1;
	return;
}

int bbsend(machine, machineslist, data)
char *machine;				/* IP ADDRESS */
char *machineslist;			/* LIST OF IP ADDRESSES IF machine = 0.0.0.0 */
char *data;				/* DATA TO SEND ACROSS */
{
 	int n, sockfd, port;
        struct sockaddr_in serv_addr;
	char *machlist,*nextmach,*machlistdone;
	int  datalen = 0;
	char errormsg[MAXLINE];
	char *outdata = NULL;

	struct hostent *ho = 0;		/* SMM 1.10 */
	struct in_addr ip;      /* THE IP ADDRESS WE'RE TESTING */

	rc = 0;

	port = PORT;			/* DEFAULT PORT */

	/* RAC
	 * Support for multiple BBDISPLAYS/BBPAGERS
	 */
#if DEBUG
	debug("BOX: %s\n", machine);
	debug("BOXES: %s\n", machineslist);
#endif

	/* If machine == 0.0.0.0 then there are more */
	/* than 1 machine, so use machineslist */
	/* process one at a time */
	if ( ! strcmp(machine,"0.0.0.0") ) {
		machlist = machineslist;
	}
	else {
		machlist = machine;
	}

	machlistdone = (char *) calloc(1,strlen(machlist)+1);

	while ( (machlist != NULL) && *machlist ) {

		/* Position to first non-space character */
		while( isspace(*machlist) )
			machlist++;
		/* Are we at end of machlist ? */
		if( !*machlist )
			break;		/* YES */

		machine = machlist;			/* Position at 1st in list */	
		nextmach= (char *) strchr(machlist,' ');/* More than one left in list ? */
		if (nextmach) {				/* Yup */
			*nextmach = '\0';		/* Terminate first one */
			machlist = nextmach + 1;	/* Reposition to next in list */
		}
		else {
			machlist = NULL;		/* No more */
		}

		ipaddr = machine;		/* GLOBAL IP ADDRESS... */

		/* Don't send the same message twice to the same host */
		if( machlistdone ) {
			if( strlen(machlistdone) > 0 ) {
				if(strstr(machlistdone,machlist)) {
					goto nextmach;
				}
			}
		}

		/*
		 * SMM 1.10
		 * TRY TO SUPPORT bb USING A DNS NAME INSTEAD OF IP ADDRESS
		 * FOR MACHINES USING DYNAMIC DNS
		 */
		if((ip.s_addr = inet_addr(machine)) == -1) { /* IS IT IN DOT FMT */
			if (*machine == '\0') {
#if DEBUG
				debug("BOX IS LOCAL\n");
#endif
				ho = gethostbyname("localhost");
			}
			else ho = gethostbyname(machine);

			if (ho == (struct hostent *)NULL) {
				sprintf(errormsg,"Unknown host: %s", machine);
				bb_errmsg(NULL,errormsg);
				goto nextmach;	/* NEXT HOST IF ANY */
			}
			/*
			 * IF WE MAKE IT HERE, WE HAVE TO COPY THE HOSTNAME 
			 * INTO THE ADDRESS STRUCTURE
			 */
			memcpy(&ip.s_addr, ho->h_addr, ho->h_length);
		}

		datalen = strlen(data) + strlen(BBAGENT) + 1;
		if( (outdata=(char *)malloc(datalen)) == NULL ) {
			sprintf(errormsg,"CAN'T ALLOCATE MEMORY IN bbsend()");
			bb_errmsg(NULL,errormsg);
			return(-1);
		}

		strcpy(outdata,BBAGENT);
		strcat(outdata,data);

		bzero((char *) &serv_addr, sizeof(serv_addr));
        	serv_addr.sin_family = AF_INET;
        	serv_addr.sin_addr.s_addr = ip.s_addr;
        	serv_addr.sin_port = htons(port);

		/*
		 * THIS IS A LITTLE NASTY
		 * IF THE SERVER'S NOT UP, THIS WILL WAIT A LONG TIME BEFORE
		 * IT TIMES OUT.  SO HANDLE THAT HERE... IT GETS 3 SECONDS TO ANSWER
		 */
#ifdef SIGSETJMP
	        if (sigsetjmp(jmpenv,1) != 0) {
#else
		if (setjmp(jmpenv) != 0) {
#endif
#if DEBUG
        	        debug("CALLING SETJMP\n");
#endif
        	}
        	signal(SIGALRM, (void *) bbsend_timeout);
        	alarm(5);

        	/* OPEN SOCKET */
        	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
			sprintf(errormsg," Can't open stream socket");
			bb_errmsg(NULL,errormsg);
			n = -1;
        	}
        	else if (connect(sockfd, (struct sockaddr *) &serv_addr,
                	        sizeof(serv_addr)) < 0) {
                	sprintf(errormsg,"CAN'T CONNECT TO bbd SERVER @ %s", machine);
			bb_errmsg(NULL,errormsg);
			n = -1;
        	}
		else {
        		n = send(sockfd, outdata, datalen + 1, 0);
		}
		alarm(0);	/* Previous alarm not needed anymore */
#if DEBUG
		debug("Send returned: %d\n",n);
#endif
		if( rc == 0 && n < 1 ) {
			rc = 1;
		}
		close(sockfd);

		/* Get next host */
nextmach:

		if ( !machlist ) {
#if DEBUG
			debug("Host list done\n");
#endif
			break;
		}
		while ( *machlist && isspace(*machlist) ) {
			machlist++;
		}
#if DEBUG
		debug("Next hosts: %s\n",machlist);
#endif
	}

	if(machlistdone) {
		free(machlistdone);
	}
#if DEBUG
	debug("bbsend(): rc = %d\n",rc);
#endif

	if( outdata != NULL ) {
		free(outdata);
	}

	return(rc);
}
