/* nctop.c
 * $Id: nctop.c,v 1.8.2.6 2005/08/02 17:35:47 becker Exp $
 * Ralf becker <nctop@web.de>
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sysexits.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <libgen.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include "display.h"
#include "udpclient.h"
#include "utils.h"
#include "slist.h"
#include "globals.h"
#include "readconfig.h"
#include "version.h"

#ifndef SYSCONFDIR
#define SYSCONFDIR "/usr/local/etc"
#endif

#ifndef  DEFAULT_PORT
#define DEFAULT_PORT	5000
#endif 

#define DEFAULT_BATCH	0
#define DEFAULT_WAIT	1
#define DEFAULT_CONF	SYSCONFDIR"/nctop.conf"

static char cvsid[] = "$Id: nctop.c,v 1.8.2.6 2005/08/02 17:35:47 becker Exp $";

char *myname;	/* the name of the game */
/* options */
int opt_port;	/* the port for the connections */
int opt_wait;	/* update ervery opt_wait seconds */ 
int opt_batch;	/* batch mode */
char *opt_conf; /* configuration */

/* the hostlist */
slist *hlist;

/* usage information */
void usage(FILE *fd) {

	fprintf(fd,"%s: [-hbV] [-w sec] [-p port] [-f config_file]\n",myname);
}

/* version information */
void version(void) {

	printf ("%s: "PACKAGE_BUGREPORT" "VERSION"\n",myname);
}

/* need to remove the hostlist entry */
void hlist_remove(void *entry) {

        free(((struct hostlist_t *)entry)->name);
        free(entry);
}

void batch(int sockfd) {

	/* file descriptor set for select */
	fd_set rfds;
	/* timeout for select */
	struct timeval timeout;

	int n;

	/* the main loop */
	n = opt_wait;

	/* we wait for a reasonable number of answers */
	while (n > 0) {

		FD_ZERO(&rfds);
		FD_SET(sockfd, &rfds);

		/* set timeout for select */
		timeout.tv_sec  = 1;
		timeout.tv_usec = 0;

		switch (select(FD_SETSIZE, &rfds, NULL, NULL, &timeout)) {
			case -1: { /* error */
				 break;
			}
			case 0: { /* timeout */
				n--;
				udpsend(sockfd);
				break;
			}
			default: {
				if (FD_ISSET(sockfd,&rfds)) {
					udprecv(sockfd);
				}
			}
		}
	}
	printlist();
}

void loop(int sockfd) {

	int noquit;
	/* file descriptor set for select */
	fd_set rfds;
	/* timeout for select */
	struct timeval timeout;
	/* count select timeouts */
	int n;

	noquit = 1;
	n = opt_wait;

	/* initialize curses display */
	if (display_init() < 0) {
		slist_remove(&hlist);
		exit(EX_UNAVAILABLE);
	}

	/* first update display */
	display();
	display_refresh();

	/* the main loop */
	while (noquit) {

		FD_ZERO(&rfds);
		FD_SET(STDIN_FILENO, &rfds);
		FD_SET(sockfd, &rfds);

		/* set timeout for select */
		timeout.tv_sec  = 1;
		timeout.tv_usec = 0;

		switch (select(FD_SETSIZE, &rfds, NULL, NULL, &timeout)) {
			case -1: { /* error */
				 break;
			}
			case 0: { /* timeout */
				if (--n == 0) {
					display();
					display_msg(0);
					display_refresh();
					n = opt_wait;
				}
				udpsend(sockfd);
				break;
			}
			default: {
				if (FD_ISSET(STDIN_FILENO,&rfds)) {
					noquit = key_handler();
				}
				if (FD_ISSET(sockfd,&rfds)) {
					udprecv(sockfd);
				}
			}
		}
	}

	/* kill curses structures */
	display_kill();
	printf("\n");
}

/* the main program */
int main (int argc, char **argv) {
	
	extern char *optarg;
	extern int optind;
	int ch;

	/* network socket */
	int sockfd;

	/* pointer to hostlist */
	struct hostlist_t *p;

	/* gethostbyname */
	struct hostent *he;

	/* setup */
	myname = basename(argv[0]);	/* save process name */

	/* defaults */
	opt_wait = DEFAULT_WAIT;
	opt_port = DEFAULT_PORT;
	opt_conf = DEFAULT_CONF;
	opt_batch = DEFAULT_BATCH;
	
	/* process commandline */
	while ((ch = getopt(argc, argv, "bf:hp:w:V")) != -1) {
		switch (ch) {
			case 'b': {
				opt_batch = !DEFAULT_BATCH;
				break;
			}
			case 'f': {
				opt_conf = optarg;
				break;
			}
			case 'h': {
				usage(stdout);
				exit(EXIT_SUCCESS);
			}
			case 'p': {
				if (sscanf(optarg,"%d",&opt_port) != 1) {
					fprintf (stderr,"%s: wrong argument\n",myname);
					usage(stderr);
					exit(EX_USAGE);
				}
				break;
			}
			case 'w': {
				if (sscanf(optarg,"%d",&opt_wait) != 1) {
					fprintf (stderr,"%s: wrong argument\n",myname);
					usage(stderr);
					exit(EX_USAGE);
				}
				break;
			}
			case 'V': {
				version();
				exit(EXIT_SUCCESS);
			}
			default: {
				usage(stderr);
				exit(EX_USAGE);
			}
		}
	}	
	argv += optind; argc -= optind; /* advance */

	/* initialize hlist and read data from config */
	if ((hlist = slist_init(hlist_remove)) == NULL) {
		perror(NULL);
		exit(EX_UNAVAILABLE);
	}

	if (readconfig(opt_conf) < 1) {
		slist_remove(&hlist);
		exit(EXIT_FAILURE);
	}

	/* set the hostentries */
	slist_foreach(hlist, p) {
		if ((he = gethostbyname(p->name)) == NULL) {
				p->sin_addr.s_addr = 0;
				p->error = (char *)hstrerror(h_errno);
				continue;
		}
		p->sin_addr = *(struct in_addr *)he->h_addr;
		/* this entry is outdated */
		p->act = 0;
	}

	/* set SIGWINCH handler */
	if (my_signal(SIGWINCH,sig_resize) == SIG_ERR) {
		perror(myname);
		exit(EX_UNAVAILABLE);
	}

	/* open DATAGRAM socket once */
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror(myname);
		exit(EX_UNAVAILABLE);
	} 


	/* call the hosts */
	udpsend(sockfd);

	if (opt_batch == 1) {
		/* batch mode */
		batch(sockfd);
	} else {
		/* normal operation */
		loop(sockfd);
	}

	/* remove list */
	slist_remove(&hlist);

	exit(EXIT_SUCCESS);
}


syntax highlighted by Code2HTML, v. 0.9.1