/******************************************************************************
 *  bwm-ng                                                                    *
 *                                                                            *
 *  Copyright (C) 2004 Volker Gropp (vgropp@pefra.de)                         *
 *                                                                            *
 *  for more info read README.                                                *
 *                                                                            *
 *  This program is free software; you can redistribute it and/or modify      *
 *  it under the terms of the GNU General Public License as published by      *
 *  the Free Software Foundation; either version 2 of the License, or         *
 *  (at your option) any later version.                                       *
 *                                                                            *
 *  This program is distributed in the hope that it will be useful,           *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *  GNU General Public License for more details.                              *
 *                                                                            *
 *  You should have received a copy of the GNU General Public License         *
 *  along with this program; if not, write to the Free Software               *
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
 *                                                                            *
 *****************************************************************************/

#include "bwm-ng.h"


extern void get_iface_stats (char verbose);
extern void get_cmdln_options(int argc, char *argv[]);

/* global vars and options */

extern int if_count;
extern char PROC_NET_DEV[PATH_MAX];
extern unsigned int delay;
extern char show_kb;
extern char netstat_i;
extern char show_all_if;
extern char show_packets;
extern char output_method;
extern char *iface_list;
extern char csv_char;
extern char csv_count;
extern FILE *csv_file;
extern char daemonize;
extern int html_refresh;

#ifdef __IOCTL
/* fd for check_if_up and ioctl */
extern int skfd;
#endif

/* global buffer to store all data of interfaces in */
extern t_iface_stats *if_stats;
/* total struct */
extern t_iface_stats if_stats_total;


/* clear stuff */
int deinit(char *error_msg) {
	if (output_method==CURSES_OUT) {
		/* first close curses, so we dont leave mess behind */
		endwin();
		curs_set(1);
	}
#ifdef __IOCTL	
	/* close socket if we opened it for ioctl */
	if (skfd >= 0) { 
		close(skfd);
	}
#endif	
	/* we should clean if_state, i think, */
	if (if_stats!=NULL) free(if_stats);
	/* free the opt iface_list */
	if (iface_list!=NULL) free(iface_list);
	/* close the csv_file */
	if (csv_file!=NULL) fclose(csv_file);
	/* output errormsg if given */
	if (error_msg!=NULL) printf(error_msg);
	/* we are done, say goodbye */
    exit(0);
}


/* sigint handler */
void sigint(int sig) {
	/* we got a sigint, call deinit and exit */
	deinit(NULL);
}


/* handle key input by user in gui (curses) mode */
void handle_gui_input(char c) {
    switch (c) {
        /* lets check for known keys */
        case '+': /* increase delay */
            delay+=100;
            timeout(delay);
            break;
        case '-': /* decrease delay */
            if (delay>100) {
                delay+=-100;
                timeout(delay);
            }
            break;
        case 'p':
        case 'P':
            show_packets=!show_packets;
            break;
        case 'a':
        case 'A':
            show_all_if=!show_all_if;
#ifndef __IOCTL	/* we need to reset the stats when no ioctl, cause the output will be fucked else */
			if (netstat_i) {
	            /* switched input, reset iface stats */
	            free(if_stats);
	            if_stats=NULL;
	            if_count=0;
	            memset(&if_stats_total,0,(size_t)sizeof(t_iface_stats));
			}
#endif			
            break;
        case 'n':
        case 'N':
            netstat_i=!netstat_i;
            /* switched input, reset iface stats */
            free(if_stats);
            if_stats=NULL;
            if_count=0;
            memset(&if_stats_total,0,(size_t)sizeof(t_iface_stats));
            break;
        case 'q':
        case 'Q':
            /* we are asked to exit */
            deinit(NULL);
            break;
        case 'd':
        case 'D':
        case 'k':
        case 'K':
            /* switch kilobyte/autoassign */
            show_kb=!show_kb;
            break;
    }
}	



int main (int argc, char *argv[]) {
	char c='\0'; /* used for getch */ 
	unsigned char idle_chars_p=0;
	strcpy(PROC_NET_DEV,"/proc/net/dev");
	get_cmdln_options(argc,argv);
	memset(&if_stats_total,0,(size_t)sizeof(t_iface_stats));
	if (output_method==CURSES_OUT) {
		/* init curses */
		initscr(); 
		cbreak(); 
		noecho();
		nonl();
		curs_set(0);
		timeout(delay); /* set the timeout of getch to delay in ms) */
	}
	/* end of init curses, now set a sigint handler to deinit the screen on ctrl-break */
	signal(SIGINT,sigint);
	signal(SIGTERM,sigint);
	if (output_method==CSV_OUT && csv_count>-1) {
		get_iface_stats(0);
		usleep(delay*1000);
	}
	if (daemonize) {
	  	int nbyt = 0;
	  	/* lets fork into background */
		if ((nbyt = fork()) == -1) {
			deinit("could not fork into background\n");
		}
		if (nbyt != 0) { /* nbyt is the new child pid here */
			deinit("forking into background\n");
		}
		setsid();
	}
    while (1) { /* do the main loop */
		if (output_method==CURSES_OUT) {
			erase();
	        mvwprintw(stdscr,1,8,"bwm-ng v%i.%i (probing every %2.3fs), press 'q' to end this",MAJOR,MINOR,(float)delay/1000);
			if (netstat_i) 
				mvwprintw(stdscr,2,8,"netstat -i %s",show_all_if==1 ? "(all)" : "");
			else 
				mvwprintw(stdscr,2,8,"/proc/net/dev %s",show_all_if==1 ? "(all)" : "");
			mvwprintw(stdscr,3,8,"%c       iface               Tx                Rx             Total",(char)IDLE_CHARS[idle_chars_p]);
			/* go to next char for next run */
			idle_chars_p++;
			if (idle_chars_p>3) idle_chars_p=0;
			mvwprintw(stdscr,4,8,"==================================================================");
		}
		get_iface_stats(!(output_method==PLAIN_OUT || output_method==HTML_OUT)); /* do the actual work, get and print stats */
		if (output_method==CSV_OUT && csv_count>-1) { 
			csv_count--;
			if (csv_count==0) break;
		}
		if (output_method==CURSES_OUT) {
			refresh();
			handle_gui_input(getch());
		} else {
			usleep(delay*1000);
		}
		c='\0'; /* not really needed, but i like it this way */
		if (output_method==PLAIN_OUT || output_method==HTML_OUT) break; /* dont loop when we have plain output */
    }
	/* do we need to output for plain? */
	if (output_method==HTML_OUT) {
        printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n<head>\n");
        printf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n");
		printf("<META HTTP-EQUIV=Refresh CONTENT=\"%i\">\n",html_refresh);
        printf("<link rel=\"stylesheet\" href=\"bwm-ng.css\" type=\"text/css\" media=\"screen,projection,print\">\n");
        printf("</head>\n<body>\n");
		printf("<div class='header'>bwm-ng bwm-ng v%i.%i (refresh %is); input: ",MAJOR,MINOR,html_refresh);
        if (netstat_i)
            printf("netstat -i %s",show_all_if==1 ? "(all)" : "");
        else
            printf("/proc/net/dev %s",show_all_if==1 ? "(all)" : "");
		printf("</div><table class='output'>");
		get_iface_stats(1);
		printf("</table>\n</body>\n</html>\n");
	}
	/* do we need to output for plain? */
	if (output_method==PLAIN_OUT) {
		printf("bwm-ng v%i.%i (delay %2.3fs); input: ",MAJOR,MINOR,(float)delay/1000);
		if (netstat_i) 
			printf("netstat -i %s\n",show_all_if==1 ? "(all)" : "");
		else 
			printf("/proc/net/dev %s\n",show_all_if==1 ? "(all)" : "");
		printf("        iface               Tx                Rx             Total\n");
		printf("==================================================================\n");
		get_iface_stats(1);
	}
	deinit(NULL);
	return 0; /* only to avoid gcc warning */
}
