/*
 * bb.c 
 *
 * BIG BROTHER CLIENT PROGRAM
 * Sean MacGuire - The MacLawran Group Inc.
 * Version 1.4
 * Mar 05th, 2000
 *
 * This program is Copyright (c) 1997-2000
 * The MacLawran Group Inc.
 * All Rights Reserved
 *
 * SENDS THE INPUT LINE TO THE DAEMON ON THE BIG BROTHER PORT
 * Format: bb IP-ADDR [<LINE>|-]
 *
 *	IP-ADDR:	IP-ADDR OF THE SERVER
 *	LINE:		<page|status|summary> <DATA>
 *		DATA:	for page:	<NUMERIC MESSAGE><status-msg>
 *			for status:	<machine><color-code><status-msg>
 *			fro summary:	<summary name><color-code><http link>
 *
 *	-		Will read from standard input a one line status
 *				message.
 */

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

char *ipaddr;

#ifdef SIGSETJMP
sigjmp_buf env; 
#else
jmp_buf env;
#endif
 
main(argc, argv)
int argc;
char *argv[];
{
char data[256];

	if (argc != 3) {
		fprintf(stderr, "bb: incorrect number of arguments\n");
		fprintf(stderr, "Format: <IP-ADDR> <DATA>\n");
		exit(1);
	}

	if( argv[2][0] == '-' ) {
	  debug("bb gets its input from stdin\n");
	  /* It expects one line messages .... */
	  while (fgets(data,sizeof(data)-1,stdin) != NULL) {
	    debug("data came in [%s]\n",data);
	    bbnotify(argv[1],data);
	  }
	  debug("Done\n");
	}
	else {
	  bbnotify(argv[1],argv[2]);
	}

	exit(0);
}

bbnotify(machine,data)
char *machine;				/* IP ADDRESS */
char *data;				/* DATA TO SEND ACROSS */
{
  char *bbpage = NULL;
  char *bbdisplays = NULL;
  char *bbpagers = NULL;
  char *pagelevels = NULL;
  char v1[16],v2[128],v3[16],v4[16];

  bbdisplays = (char *) getenv("BBDISPLAYS");
  debug("Sending: ** %s ** to %s - %s\n",data,machine,bbdisplays);
  bbsend(machine, bbdisplays, data);     /* SEND IT ACROSS */

  /* If BBPAGE is defined then send also a msg if it's a red alert */
  /* What if BBPAGE == BBDISP ? for now send two messages */
  /* keep it simple ... */
  bbpage = (char *) getenv("BBPAGE");
  bbpagers = (char *) getenv("BBPAGERS");
  pagelevels = (char *) getenv("PAGELEVELS");
  if( ! pagelevels || (strlen(pagelevels) == 0) )
	pagelevels = PAGELEVELSDEFAULT;
  if( (bbpage != NULL) && (pagelevels != NULL) ) {
    /* %*s could have been used for v2 but */
    /* Linux thought otherwise i.e. bug or I misunderstood the %*s (skip) */
    sscanf(data,"%15s %127s %16s %*s",v1,v2,v3,v4);
    debug("v1:[%s] v2:[%s] v3:[%s] v4:[%s]\n",v1,v2,v3,v4);
    if( !strcmp(v1,"status") ) {
      if( strstr(pagelevels,v3) ) {
        memcpy(data,"page  ",6); /* Change msg type */
		debug("Sending: ** %s ** to %s - %s\n",data,bbpage,bbpagers);
		bbsend(bbpage,bbpagers,data);      /* SEND IT ACROSS TO BBPAGER */
      }
    }
  }

}

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, timeout();
        struct sockaddr_in serv_addr;
	char *machlist,*nextmach,*machlistdone;
	char *host;

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

	port=PORT;			/* DEFAULT PORT */

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

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

	/* 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 ) {

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

		/* 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') {
				debug("BOX IS LOCAL\n");
				ho = gethostbyname("localhost");
			}
			else ho = gethostbyname(machine);

			if (ho == (struct hostent *)NULL) {
				fprintf(stderr, "bb: Unknown host: %s\n", machine);
				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);
		}

		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(env,1) != 0) {
#else
		if (setjmp(env) != 0) {
#endif
        	        debug("CALLING SETJMP\n");
        	}
        	signal(SIGALRM, (void *)timeout);
        	alarm(5);

        	/* OPEN SOCKET */
        	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                	fprintf(stderr, "bb: Can't open stream socket\n");
			n = -1;
        	}
        	else if (connect(sockfd, (struct sockaddr *) &serv_addr,
                	        sizeof(serv_addr)) < 0) {
                	fprintf(stderr, "bb: CAN'T CONNECT TO bbd SERVER @ %s\n", machine);
			n = -1;
        	}
		else {
        		n = send(sockfd, data, strlen(data) + 1, 0);
		}
		alarm(0);	/* Previous alarm not needed anymore */
		debug("Send returned: %d\n",n);
		close(sockfd);

		/* Get next host */
nextmach:

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

	if(machlistdone) {
		free(machlistdone);
	}

	return(0);
}

timeout()
{
	fprintf(stderr, "bb: CONNECTION TO %s TIMED OUT...\n", ipaddr);
	return;
}
