/* Copyright (C) 1996-2007 Luis Falcon (lfalcon@thymbra.com)  
    
    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., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <math.h>

#define CMD_LINE  fprintf (stderr,"usage : netload device [-t secs] \n\tnetload -setup\n")
#define MAILER "/usr/lib/sendmail -t "
#define PROC_DEV_SIZE 10000

WINDOW *panel;
WINDOW *lever;
WINDOW *credit;
WINDOW *INFO;

int INIT = 0;
long long int old_rec=0;
long long int old_trans=0;
long long temp_load=0;
long long max_sofar=0;

int alarm=0;  /* High-load alarm */
int salarm=0; /* sound alarm */
int ealarm=0; /* email notification */
int aperiod; /* period for re-activating the email alarm */
int aflag=1;
int countdown;

char *netrc;

char *current_time;

int check_netloadrc ();

int mail_notify (int, long long int, long long int, long long int, long long int, long long int, char *device);

int check_arguments (int c, char *v[]);
int setup_netload ();
void show_load (char *line, int scale,int dormant);
void reset (int);
char *update_watch ();


/* Function main () 
******************************************************************************************************************************/


main (int argc, char *argv[])
{

FILE *source;
char *line;
char content [PROC_DEV_SIZE];
double filesize;
int dormant;
int scale;
int argument_length;
char mask [6];

initscr ();
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);


noecho ();
start_color ();


check_arguments (argc, argv);

scale = check_netloadrc (argv[1]); /* check status of .netloadrc, plus getting the alarm and scale factor settings of the device */

signal (SIGINT,reset);

if (argc > 2)
  dormant = atoi (argv [3]);
else
  dormant = 1;

if (strncmp (argv[1],"-setup",6) == 0)
	setup_netload ();



line = malloc (100*sizeof (char));


init_pair (COLOR_CYAN,COLOR_CYAN, COLOR_BLACK);
init_pair (COLOR_RED, COLOR_RED, COLOR_BLACK );
init_pair (COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair (COLOR_BLUE, COLOR_BLUE,COLOR_BLACK);


strcpy (mask,argv[1]);
argument_length = strlen (argv[1]);
mask [argument_length]=':';

panel = newwin (15,60,7,10);

lever = newwin (1,60,18,10);
credit = newwin (1,60,23,10);
INFO = newwin (5,60,1,10);

while (1)
  {
    if ((source=fopen ("/proc/net/dev","r")) == NULL)
	{
	fprintf (stderr, "Couldn't open source file\n");
	endwin ();
	}

    fread (content,1,PROC_DEV_SIZE,source);
    content[PROC_DEV_SIZE-1] = 0; /* Add null terminator */


    if ((line = strstr (content,mask)) == NULL)
      {
	fprintf (stderr,"Device \"%s\" not found\n",argv[1]);
	endwin ();
	exit (1);
      } 
 

  show_load (line,scale,dormant);
  lseek (source,0,SEEK_SET);
  fclose (source);
  sleep (dormant);

  }


}



/*  Function show_load () 
*****************************************************************************************************************/


void show_load (char *line,int scale,int dormant)
{

char device [5];

long long int rbytes, rec_load, trans_load, total_load, sbytes=0; 
long long int rcompressed, colls, compressed, multicast,packets,rpackets;
long long int errors,drop,fifo,frame;
long long int rerrors,rdrop,rfifo,rframe,carrier;
int marks;


int load_level;



    sscanf (line,"%[^:]: %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld %Ld\n",&device,&rbytes,&rpackets,&rerrors,&rdrop,&rfifo,&rframe,&rcompressed,&multicast, &sbytes, &packets,&errors,&drop,&fifo,&colls,&carrier,&compressed);



    wmove (INFO,1,1);
    wprintw (INFO,"\tBYTES");
    wmove (INFO,1,25);
    wprintw (INFO,"ERRORS\t  DROP\tFIFO");    
    wmove (INFO,3,1);

    wprintw (INFO,"RECV\t%Ld",rbytes);
    wmove (INFO,3,27);
    wprintw (INFO,"%Ld\t  %Ld\t  %Ld",rerrors,rdrop,rfifo);
    wmove (INFO,4,1);
    wprintw (INFO,"TRANS\t%Ld",sbytes);
    wmove (INFO,4,27);
    wprintw (INFO,"%Ld\t  %Ld\t  %Ld",errors,drop,fifo);
    

    rec_load = rbytes - old_rec; 
    old_rec = rbytes;

    trans_load = sbytes - old_trans;
    old_trans = sbytes;

    total_load = (rec_load + trans_load)/dormant;   /* Average in Bytes/sec in the last x seconds */

/*
    
    wattrset (credit,COLOR_PAIR(COLOR_BLUE));
    COLOR_PAIR (COLOR_BLUE);
    wprintw (credit,"Comments or bugs to Luis Falcon (lfalcon@thymbra.com)");
    wmove (credit,0,0);
    COLOR_PAIR (COLOR_CYAN);
       
 */
   
    if ( (countdown= countdown - dormant) <=0 )  
    	{aflag = 1; 
    	countdown = aperiod;
        }

if (INIT == 0)
    current_time = update_watch ();
     

if (INIT != 0)
  {
    if (total_load > max_sofar)
	{
        max_sofar = total_load;
	current_time = update_watch ();
	} 
    werase (panel);
    werase (lever);
    wmove (panel,1,5);
    wprintw (panel,"Maximum device load %Ld (%s)",max_sofar,current_time);
    wmove (panel,2,1);
    whline (panel,0,58); 
    wmove (panel,4,14);
    wattrset (panel,A_BOLD);
    wprintw (panel, "Relative Load in %d sec(s) step",dormant);
    wmove (panel,6,15);
    wattrset (panel,COLOR_PAIR (COLOR_CYAN));
    wprintw (panel, "Received  \t %Ld",rec_load); 
 
    wmove (panel,7,15);
    wprintw (panel, "Transmitted\t %Ld",trans_load);

    wmove (panel,8,15);
    wprintw (panel, "Total load\t %Ld",rec_load + trans_load);

    
    wmove (panel,13,22);
    wprintw (panel, "device %s",device);

    wattrset (panel,0);
    wrefresh (panel);
    

    load_level = total_load/scale;
    if (load_level > 60)
	load_level = 60;

    
     if (total_load > 0)      
	{
			
	if (load_level <=20)
		wattrset (lever, A_BOLD);
	if (load_level >20 && load_level < 40)
		{
		wattrset (lever,COLOR_PAIR (COLOR_GREEN));
		COLOR_PAIR (COLOR_GREEN);
		}
	if (load_level > 40)
		{
		if ( alarm==1)
			{
			if (salarm == 1) 
			     beep ();
			if (ealarm == 1 && aflag == 1)
				mail_notify (dormant, rbytes,sbytes,rec_load, trans_load, total_load, device);
			}	
						
		wattrset (lever,COLOR_PAIR (COLOR_RED)); 
		COLOR_PAIR (COLOR_RED);
		}
      	for (marks=0;marks < load_level+1;marks++)	
			wechochar (lever,ACS_BLOCK); 
	}
	  
  }


wattrset (lever,0);


wrefresh (lever);

wrefresh (credit);
wrefresh (INFO);

INIT =1;
}

char *update_watch ()
{
time_t reloj;
char *time_holder;
time (&reloj);
time_holder = ctime (&reloj);
time_holder [24] =0;
return (time_holder);
}

/* Function reset ()
********************************************************************************************************************/

void reset (int signal)
{
endwin ();
printf ("Later...\n");
exit (0);
}

/* Function setup_netload ()
********************************************************************************************************************/

int setup_netload ()
{
printf ("\nNot implemented...yet. \nFor now, edit your $HOME/.netloadrc to fit your requirements.\n\n");
exit (0);
}


/* Function check_arguments 
***********************************************************************************************************************/



int check_arguments (int c,char *v[])
{


if (c < 2 || c > 4 || c == 3)
	{
	endwin ();
	CMD_LINE;
	exit (1);
	}
if (c==4 && strcmp (v[2],"-t") != 0)
        {
	CMD_LINE;
	exit (1);
        }
if (c==4 && strcmp (v[2],"-t") == 0 && atoi (v[3]) == 0)
    {
    fprintf (stderr, " Time must be >= 1 sec\n");
    exit (1);
    }

return (0);
}


/* Function check_netloadrc ()
********************************************************************************************************************/


int check_netloadrc (char *device)
{


FILE *source;

char *line;
char *period;
char content [10000];
char mask [6];
int argument_length;
int filesize=0;
int counter=1;
int sfactor=0;

endwin ();

netrc= malloc ( 100*sizeof (char));
netrc = getenv ("HOME");
netrc = strcat ( netrc,"/.netloadrc");

strcpy (mask,device);
argument_length = strlen (device);
mask [argument_length]=':';



line = malloc (10000*sizeof (char));
period = malloc (10000*sizeof (char));


if ((source=fopen (netrc,"r")) == NULL)
	{
	endwin ();
	fprintf (stderr, "\nCouldn't open %s !\n Setting up defaults ...\n",netrc);
	fprintf (stderr, "\nNow edit %s to your personal settings\n", netrc);
	

	if ((source=fopen (netrc,"w+")) == NULL )
		{
		fprintf (stderr, "\nCouldn't write to %s !\n", netrc);
		exit (1);
		}
	fprintf (source,"## Configuration file for netload\n");
	fprintf (source,"## (c) 1996-2007 Luis Falcon lfalcon@thymbra.com \n\n\n");
	fprintf (source,"## Activate (1) or deactivate (0) the high-load alarm\n");
	fprintf (source,"alarm:1\n");
	fprintf (source,"## Notify (1) or disable (0) high-load sound notification\n");
	fprintf (source,"sound:1\n");
	fprintf (source,"## Notify (1) or disable (0) high-load email/SMS notification\n");
	fprintf (source,"email:0\n");
	fprintf (source,"## Period ( in minutes ) high-load email notification\n");
	fprintf (source,"period:60\n\n");


	fprintf (source,"## Insert and/or your interfaces here, followed by colon and the scale factor.\n");
	fprintf (source,"## one mark is equivalent to x Bytes/sec. There are 60 marks in the meter\n");
	fprintf (source,"ppp0:170\n");
	fprintf (source,"lo:30000\n");
	fprintf (source,"eth0:30000\n\n");
	fprintf (source,"## Email notification stuff...don't get rid or modify  \"From,To and Subject\" headers, or sendmail won't work properly\n\n");
        fprintf (source,"From: your@email.xxx\n");
	fprintf (source,"To: your@recipient.xxx\n");
	fprintf (source,"Subject: High-load\n");
	fprintf (source,"Enter your text here....\n");
	fclose (source);
	exit (1);
	}

/* Check for the device,its scale factor and alarm settings */

    fseek (source,0,SEEK_END);
    filesize = ftell ( source );
    fseek (source,0,SEEK_SET);
    fread (content,filesize,1,source);

    line = strstr (content,mask);

    if ( strstr ( content,"alarm:1" )) 
	alarm=1;
	
   if ( strstr ( content,"sound:1" )) 
	salarm=1;
    if ( strstr ( content,"email:1" )) 
	ealarm=1;

    if ( period = strstr ( content,"period:"))
    	{
    	period = strchr (period,':');
	while (period[counter] != (char) 10)
		counter++;	
	period [counter]= (char) 0;
	period++; /* get rid of ':' */
	aperiod = atoi (period) * 60;
	countdown=aperiod;
	}

      
      
    if (line == NULL)
      {
	fprintf (stderr,"Your device \"%s\" was not found in .netloadrc ... \nSetting default scale 30Kb per unit of time\n",device);
	fprintf (stderr,"Chances are, this is not the scale you want... so add it to .netloadrc\n");
      	sfactor=30000;
 
      	fclose (source);
 	sleep (2);
      	return (sfactor); 
      }

    
line = strchr (line,':');
while (line[counter] != (char) 10)
	counter++;	
line [counter]= (char) 0;
line++; 

sfactor = atoi (line);

fclose (source);


return ( sfactor );




}



int mail_notify (int dormant, long long int rbytes,long long int sbytes,long long int rec_load,long long int trans_load,long long int total_load, char *device)
{

FILE *mail;
FILE *source;
char *message;
char *conf;
long filesize;


message = malloc ( 10000* sizeof ( char));

mail = popen (MAILER, "w");
	if (!mail)
		{
		endwin ();
		perror ("Error :");
		exit (1);
		}
		
source = fopen (netrc,"r");
    fseek (source,0,SEEK_END);
    filesize = ftell ( source );
    fseek (source,0,SEEK_SET);
    fread (message,filesize,1,source);

    message = strstr (message,"From:"); 
    
    fprintf(mail,"%s\n", message);
    fprintf (mail, "\n\nSnapshot of device %s  ( All the values are in Bytes )\n\n", device);
    fprintf (mail, "Time of High-load : %s\n", current_time);
    fprintf (mail, "Time for next email check: %d minutes\n\n", aperiod/60);
    fprintf (mail, "Total Received:\t\t %Ld\n", rbytes);
    fprintf (mail, "Total Sent:\t\t %Ld\n\n", sbytes); 
    fprintf (mail, "Rec. in the last %d seconds:\t\t%Ld\n",dormant, rec_load);  
    fprintf (mail, "Sent in the last %d seconds:\t\t%Ld\n",dormant, trans_load);   
    fprintf (mail, "Total in the last %d seconds:\t\t%Ld\n\n\n",dormant, rec_load+trans_load);
    fprintf (mail, "Average # Bytes per second: %Ld\n", total_load);  
    pclose(mail);

aflag=0;

}

