/******************************************************************************
 *
 * slurm - yet another network load monitor
 *
 * slurm started as a FreeBSD port of the Linux ppp link monitor called
 * pppstatus by Gabriel Montenegro.
 * I ripped of the ppp dependend parts and the email checks to turn in into
 * a generic network load monitor running on all common Unices.
 *
 *  author: Hendrik Scholz
 * website: http://www.wormulon.net/slurm/
 *   email: hendrik@scholz.net
 *
 * As pppstatus is licensed under the GPL, slurm is too. See the following
 * paragraphs for information about pppstatus and the license.
 *
 *****************************************************************************
 * $Id: slurm.c,v 1.86 2004/10/12 19:44:36 hscholz Exp $
 *****************************************************************************
 *
 * 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 "os.h"

#include "config.h"
#include "slurm.h"
#include "src/if_media.h"
#include "src/if_media.c"

#include "error.h"
#include "error.c"
#include "theme.h"
#include "theme.c"

#ifdef __HPUX__
#include "src/hpux.h"
#include "src/hpux.c"
#elif __FreeBSD__
#include "src/freebsd.h"
#include "src/freebsd.c"
#elif __linux__
#include "src/linux.h"
#include "src/linux.c"
#elif __OpenBSD__ || __MicroBSD__
#include "src/openbsd.h"
#include "src/openbsd.c"
#elif __NetBSD__
#include "src/netbsd.h"
#include "src/netbsd.c"
#elif __Solaris__
#include "src/solaris.h"
#include "src/solaris.c"
#elif __APPLE__
#include "src/macos.h"
#include "src/macos.c"
#elif __DragonFly__
#include "src/freebsd.h"
#include "src/freebsd.c"
#else
#warning "Your OS is not supported. Including dummy code!"
#include "src/unsupported.h"
#include "src/unsupported.c"
#endif

/******************************************************************************
 *
 * center()
 *
 * center a given string on a given line
 * this is pppstatus code :)
 *
 *****************************************************************************/

void center(short int line, char *strg, ...)
{
   short int where;
   char *final;
   va_list trans;
   
   final = malloc(80);
   va_start(trans, strg);
   (void)vsnprintf(final, 80, strg, trans);
   va_end(trans);
   where = (int)(40 - (strlen(final) / 2));
   if(line != 0 && line != 24) {
      move(line, 20); 
      hline(32, 50); 
   }
   mvprintw(line, where, "%s",final);
   free(final);
}

/******************************************************************************
 *
 * get_time()
 *
 * uptime stats struct with current time
 *
 *****************************************************************************/

void get_time(void)
{
   long x;
   stats.current_time = time(NULL);
   x = stats.current_time - stats.connect_time;
   stats.online_sec = x % 60;
   stats.online_min = (x / 60) % 60; 
   stats.online_hour = (x / 3600) % 24;
   stats.online_days = (x / (3600 * 24)) % 365;
}

/******************************************************************************
 *
 * update_info()
 *
 * update the statistics and pay attention to buffer overruns while we are
 * here. As we allow decreasing values we have to pay attention to
 * no leave garbage on the screen.
 *
 *****************************************************************************/

void update_info(int displaymode)
{
	char draw[DRAWLEN+1];
	attrset(COLOR_PAIR(PAIR_VAR) | 
		((unsigned long)(t.var_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
    if (displaymode != MODE_LARGE)
    {
		snprintf(draw, DRAWLEN-1, "%lu",
			stats.rx_packets - stats.rx_packets_off);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
		mvprintw(20, 24, "%s", draw);

		snprintf(draw, DRAWLEN-1, "%lu",
			stats.tx_packets - stats.tx_packets_off);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
		mvprintw(20, 65, "%s", draw);

		snprintf(draw, DRAWLEN-1, "%lu",
			stats.rx_errors - stats.rx_errors_off);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
		mvprintw(22, 24, "%s", draw);

		snprintf(draw, DRAWLEN-1, "%lu",
			stats.tx_errors - stats.tx_errors_off);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
		mvprintw(22, 65, "%s", draw);

        switch(data_type)
        {
			case TYPE_MEGA:
    			snprintf(draw, DRAWLEN-1, "%.3f MB", (stats.rx_bytes +
				(stats.rx_over * SNMPMAXBYTES) - stats.rx_bytes_off) / 1048570);
    			strncat(draw, "               ", DRAWLEN-strlen(draw));
				mvprintw(21, 24, "%s", draw);

				snprintf(draw, DRAWLEN-1, "%.3f MB", (stats.tx_bytes +
				(stats.tx_over * SNMPMAXBYTES) - stats.tx_bytes_off) / 1048570);
				strncat(draw, "               ", DRAWLEN-strlen(draw));
				mvprintw(21, 65, "%s", draw);
                break;
			case TYPE_GIGA:
				snprintf(draw, DRAWLEN-1, "%.3f GB", (stats.rx_bytes +
                	(stats.rx_over * SNMPMAXBYTES) - stats.rx_bytes_off)
					/ 1073735680);
                strncat(draw, "               ", DRAWLEN-strlen(draw));
                mvprintw(21, 24, "%s", draw);

                snprintf(draw, DRAWLEN-1, "%.3f GB", (stats.tx_bytes +
                	(stats.tx_over * SNMPMAXBYTES) - stats.tx_bytes_off)
					/ 1073735680);
                strncat(draw, "               ", DRAWLEN-strlen(draw));
                mvprintw(21, 65, "%s", draw);
                break;
        }
    }
}
#ifdef WITH_LED
/******************************************************************************
 *
 * led_on() / led_off()
 *
 * blinkenlights(tm)
 *
 *****************************************************************************/

void led_on(unsigned int who)
{
    int CHAR = 215;

    if(who == LED_RX)
    {
		attrset(COLOR_PAIR(PAIR_RX) | 
			((unsigned long)(t.rx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
        move(14, 37); hline(CHAR, 2);
    }
    else if(who == LED_TX)
    {
		attrset(COLOR_PAIR(PAIR_TX) | 
			((unsigned long) (t.tx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
        move(14, 41); hline(CHAR, 2);
    }
}

void led_off(unsigned int who)
{
    if(who == LED_RX)
    {
		attrset(COLOR_PAIR(PAIR_VAR) | 
			((unsigned long) (t.var_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
        mvprintw(14, 37, "RX");
    }
    else if(who == LED_TX)
    {
		attrset(COLOR_PAIR(PAIR_VAR) | 
			((unsigned long) (t.var_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
        mvprintw(14, 41, "TX");
    }
}
#endif

/******************************************************************************
 *
 * update_stat_large()
 *
 * update the data array holding the needed information and redraw the graph
 * this mode shows two large graphs, one for each direction
 *
 *****************************************************************************/
 
int update_stat_large(void)
{
    float sumspeed;
    float rxspeed;
    float txspeed;
    int i=0,x,y;
    int rx_scalechanged = 0;    /* traffic scale changed? */
    int tx_scalechanged = 0;

    float tmp_maxspeed = 0;     /* needed for max speed calc in graph */
    int tmp_maxspeedpos = 1;    /* same here */

    char draw[DRAWLEN+1];               /* what we draw on the screen */

    /* in case of REINIT we want to keep the rx and tx values as we can
     * recalculate the graph for the new mode based on them.
     * recalculation is done automatically as ??_maxspeed equals 0 after
     * initilization.
     */

    if (db_status == DB_STATUS_REINIT || db_status == DB_STATUS_STARTUP)
    {
        rx_maxspeed = 0; rx_overallmax = 0;
        tx_maxspeed = 0; tx_overallmax = 0;
        /* fill the graph array with zeros */
        for (x = 0; x < GRAPH_WIDTH; x++)
        {
            for (y = 0; y < GRAPH_HEIGHT; y++)
            {   
                rx_graph[x][y] = 0;
                tx_graph[x][y] = 0;
            }
        }

        if (db_status == DB_STATUS_STARTUP)
        {   
            stats.rx_bytes_comp = stats.rx_bytes;
            stats.tx_bytes_comp = stats.tx_bytes;
            for (x = 0; x < GRAPH_WIDTH; x++)
            {   
                rx_speedarray[x] = 0;
                tx_speedarray[x] = 0;
            }
            db_status = DB_STATUS_RUNNING;
    
            return 1;
        }
        db_status = DB_STATUS_RUNNING;
    }

    /*
     * current speed in bits/s
     *
     * in case of the expected u_long overflow in stats.?x_bytes
     * we will calculate a negative number as {sum|tx|rx}speed.
     * to prevent this we have to check if the _comp value is larger
     * than the current value. If true, we set _comp to 0
     */

    if (stats.rx_bytes_comp > stats.rx_bytes)
        stats.rx_bytes_comp = 0;
    if (stats.tx_bytes_comp > stats.tx_bytes)     
        stats.tx_bytes_comp = 0;

    sumspeed = ((stats.rx_bytes - stats.rx_bytes_comp) +
               (stats.tx_bytes - stats.tx_bytes_comp)) / refreshdelay;

    rxspeed = (stats.rx_bytes - stats.rx_bytes_comp) / refreshdelay;
    txspeed = (stats.tx_bytes - stats.tx_bytes_comp) / refreshdelay;

    /* print current speed */
    snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) rxspeed/1024);
	strncat(draw, "               ", DRAWLEN-strlen(draw));
    mvprintw(21, 24, "%s", draw);

    snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) txspeed/1024);
	strncat(draw, "               ", DRAWLEN-strlen(draw));
    mvprintw(21, 65, "%s", draw);

    stats.rx_bytes_comp = stats.rx_bytes;
    stats.tx_bytes_comp = stats.tx_bytes;

    /* set new max speed for graph if reached */
    if (rxspeed > rx_maxspeed)
    {
        rx_maxspeed = rxspeed;
        rx_maxspeedpos = 0;
        rx_scalechanged++;
        if (rxspeed > rx_overallmax)
            rx_overallmax = rxspeed;
    }

    /* set new max speed for graph if reached */
    if (txspeed > tx_maxspeed)
    {
        tx_maxspeed = txspeed;
        tx_maxspeedpos = 0;
        tx_scalechanged++;
        if (txspeed > tx_overallmax)
            tx_overallmax = txspeed;
    }

    /*
     * update the Graph Top Speed field
     * as it might be shorter than before just be sure to not leave
     * trailing garbage by printing spaces
     */

    if (rx_scalechanged)
    {
        snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) rx_maxspeed/1024);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
        mvprintw(22, 24, "%s", draw);
    }
    if (tx_scalechanged)
    {
        snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) tx_maxspeed/1024);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
        mvprintw(22, 65, "%s", draw);
    }


    /* increment position of max speed as we move the graph */
    rx_maxspeedpos++; tx_maxspeedpos++;

    /* check if max speed has to be lowered for the graph as the max speed
     * was reached too long ago
     */

    tmp_maxspeed = 0; tmp_maxspeedpos = 1;
    if (rx_maxspeedpos >= GRAPH_WIDTH)
    {
        /* max speed calculation has to be redone */
        for (i=0; i < GRAPH_WIDTH; i++)
        {
            if  (rx_speedarray[i] > tmp_maxspeed)
            {
                tmp_maxspeed = rx_speedarray[1];
                tmp_maxspeedpos = i;
            }
        }
        /* set new values */
        rx_maxspeed = tmp_maxspeed;
        rx_maxspeedpos = tmp_maxspeedpos;
    }

    tmp_maxspeed = 0; tmp_maxspeedpos = 1;
    if (tx_maxspeedpos >= GRAPH_WIDTH)
    {
        /* max speed calculation has to be redone */
        for (i=0; i < GRAPH_WIDTH; i++)
        {
            if  (tx_speedarray[i] > tmp_maxspeed)
            {
                tmp_maxspeed = tx_speedarray[1];
                tmp_maxspeedpos = i;
            }
        }
        /* set new values */
        tx_maxspeed = tmp_maxspeed;
        tx_maxspeedpos = tmp_maxspeedpos;
    }

    /* prepare the graph array
     *
     * shift the graph to the left and then add the last entry
     * in addition move the traffic stats left
     */

    /* move */
    for (x = GRAPH_WIDTH-1; x >= 0; x--)
    {
        rx_speedarray[x] = rx_speedarray[x-1];
        tx_speedarray[x] = tx_speedarray[x-1];
        for (y = 0; y < GRAPHLARGE_HEIGHT; y++)
        {
            rx_graph[x][y] = rx_graph[x-1][y];
            tx_graph[x][y] = tx_graph[x-1][y];
        }
    }

    /* add the last column */
    if(rx_maxspeed > 0)
        i = (int) ((rxspeed / rx_maxspeed) * GRAPHLARGE_HEIGHT); 
    for (y = 0; y <= GRAPHLARGE_HEIGHT; y++)
    {
        if (i > y)
            rx_graph[0][y] = 1;
        else
            rx_graph[0][y] = 0;
    }
    if (0 != (int) rxspeed)
        rx_graph[0][1] = 1;
    rx_speedarray[0] = rxspeed;

    if(tx_maxspeed > 0)
        i = (int) ((txspeed / tx_maxspeed) * GRAPHLARGE_HEIGHT);
    for (y = 0; y <= GRAPHLARGE_HEIGHT; y++)
    {   
        if (i > y)
            tx_graph[0][y] = 1;
        else
            tx_graph[0][y] = 0;
    }
    if (0 != (int) txspeed)
        tx_graph[0][1] = 1;
    tx_speedarray[0] = txspeed;

    /*
     * rescale graph
     *
     * in case the maxspeed for the shown graph changed we need to
     * recalculate the whole graph
     *
     */ 

    if (rx_scalechanged)
    {
        /* for each line rewrite the graph */
        for (x = GRAPH_WIDTH-1; x >= 0; x--)
        {
            i = (int) ((rx_speedarray[x] / rx_maxspeed) * GRAPHLARGE_HEIGHT);
            for (y = 0; y <= GRAPHLARGE_HEIGHT; y++)
            {   
                if (i > y)
                    rx_graph[x][y] = 1;
                else
                    rx_graph[x][y] = 0;
            }
            if (rx_speedarray[x] != 0)
                rx_graph[x][1] = 1;
        }
    }
    if (tx_scalechanged)
    {
        /* for each line rewrite the graph */
        for (x = GRAPH_WIDTH-1; x >= 0; x--)
        {
            i = (int) ((tx_speedarray[x] / tx_maxspeed) * GRAPHLARGE_HEIGHT);
            for (y = 0; y <= GRAPHLARGE_HEIGHT; y++)
            {
                if (i > y)
                    tx_graph[x][y] = 1;
                else
                    tx_graph[x][y] = 0;
            }
            if (tx_speedarray[x] != 0)
                tx_graph[x][1] = 1;
        }
    }


    /*
     * finally draw the two graphs line by line
     *
     * the rx graphs grows to the bottom
     */

    for (y = GRAPHLARGE_HEIGHT-1; y > 0; y--)
    {
        for (x = 0; x <= GRAPH_WIDTH; x++)
        {
            /* RX graph */
            if (rx_graph[x][y] == 1)
            {
				attrset(COLOR_PAIR(PAIR_RX) | 
					((unsigned long)(t.rx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
                mvprintw(11-y, x+1, SYMBOL_TRAFFIC);
            }
            else
                mvprintw(11-y, x+1, SYMBOL_NOTRAFFIC);
            /* TX graph */
            if (tx_graph[x][y] == 1)
            {
				attrset(COLOR_PAIR(PAIR_TX) | 
					((unsigned long)(t.tx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
                mvprintw(10+y, x+1, SYMBOL_TRAFFIC);
            }
            else
                mvprintw(10+y, x+1, SYMBOL_NOTRAFFIC);
        }
    }
    return 0;
}

/******************************************************************************
 *
 * update_stat_split()
 *
 * updates the array holding information about the graph and redraw
 * the graph.
 *
 *****************************************************************************/

int update_stat_split(void)
{
    float sumspeed;
    float rxspeed;
    float txspeed;
    int i=0,x,y;
    int rx_scalechanged = 0;    /* traffic scale changed? */
    int tx_scalechanged = 0;

    float tmp_maxspeed = 0;     /* needed for max speed calc in graph */
    int tmp_maxspeedpos = 1;    /* same here */

    char draw[DRAWLEN+1];               /* what we draw on the screen */

    /* in case of REINIT we want to keep the rx and tx values as we can
     * recalculate the graph for the new mode based on them.
     * recalculation is done automatically as ??_maxspeed equals 0 after
     * initilization.
     */

    if (db_status != DB_STATUS_RUNNING)
    {
        rx_maxspeed = 0; rx_overallmax = 0;
        tx_maxspeed = 0; tx_overallmax = 0;
        /* fill the graph array with zeros */
        for (x = 0; x < GRAPH_WIDTH; x++)
        {   
            for (y = 0; y < GRAPH_HEIGHT; y++)
            {   
                rx_graph[x][y] = 0;
                tx_graph[x][y] = 0;
            }
        }

        if (db_status == DB_STATUS_STARTUP)
        {
            stats.rx_bytes_comp = stats.rx_bytes;
            stats.tx_bytes_comp = stats.tx_bytes;
            for (x = 0; x < GRAPH_WIDTH; x++)
            {
                rx_speedarray[x] = 0;
                tx_speedarray[x] = 0;
            }
            db_status = DB_STATUS_RUNNING;
    
            return 1;
        }
        db_status = DB_STATUS_RUNNING;
    }
    
    /*
     * current speed in bits/s
     *
     * in case of the expected u_long overflow in stats.?x_bytes
     * we will calculate a negative number as {sum|tx|rx}speed.
     * to prevent this we have to check if the _comp value is larger
     * than the current value. If true, we set _comp to to 2^32 - _comp
     */

    if (stats.rx_bytes_comp > stats.rx_bytes)
        stats.rx_bytes_comp = SNMPMAXBYTES - stats.rx_bytes_comp;
    if (stats.tx_bytes_comp > stats.tx_bytes) 
        stats.tx_bytes_comp = SNMPMAXBYTES - stats.tx_bytes_comp;

    sumspeed = ((stats.rx_bytes - stats.rx_bytes_comp) +
               (stats.tx_bytes - stats.tx_bytes_comp)) / refreshdelay;

    rxspeed = (stats.rx_bytes - stats.rx_bytes_comp) / refreshdelay;
    txspeed = (stats.tx_bytes - stats.tx_bytes_comp) / refreshdelay;

    /* print current speed
     * instead of directly printing the string we first clear the draw string
     * and then fill in the speed. This way we prevent garbage from being
     * left on the screen.
     */

	attrset(COLOR_PAIR(PAIR_VAR) | 
		((unsigned long) (t.var_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
    snprintf(draw, DRAWLEN-1, "%.2f KB/s    ", rxspeed / 1024);
	strncat(draw, "               ", DRAWLEN-strlen(draw));
    mvprintw(17, 24, "%s", draw);
    snprintf(draw, DRAWLEN-1, "%.2f KB/s    ", txspeed / 1024);
	strncat(draw, "               ", DRAWLEN-strlen(draw));
    mvprintw(17, 65, "%s", draw);

    stats.rx_bytes_comp = stats.rx_bytes;
    stats.tx_bytes_comp = stats.tx_bytes;

    /* set new max speed for graph if reached */
    if (rxspeed > rx_maxspeed)
    {
        rx_maxspeed = rxspeed;
        rx_maxspeedpos = 0;
        rx_scalechanged++;
        if (rxspeed > rx_overallmax)
        {
            rx_overallmax = rxspeed;
            snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) rxspeed/1024);
			strncat(draw, "               ", DRAWLEN-strlen(draw));
            mvprintw(19, 24, "%s", draw);
        }
    }

    /* set new max speed for graph if reached */
    if (txspeed > tx_maxspeed)
    {
        tx_maxspeed = txspeed;
        tx_maxspeedpos = 0;
        tx_scalechanged++;
        if (txspeed > tx_overallmax)
        {
            tx_overallmax = txspeed;
            snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) txspeed/1024);
			strncat(draw, "               ", DRAWLEN-strlen(draw));
            mvprintw(19, 65, "%s", draw);
        }
    }

    /*
     * update the Graph Top Speed field
     * as it might be shorter than before just be sure to not leave
     * trailing garbage by printing spaces
     */

    if (rx_scalechanged)
    {
        snprintf(draw, DRAWLEN-1, "%.2f KB/s", rx_maxspeed/1024);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
        mvprintw(18, 24, "%s", draw);
    }
    if (tx_scalechanged)
    {
        snprintf(draw, DRAWLEN-1, "%.2f KB/s", tx_maxspeed/1024);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
        mvprintw(18, 65, "%s", draw);
    }


    /* increment position of max speed as we move the graph */
    rx_maxspeedpos++; tx_maxspeedpos++;

    /* check if max speed has to be lowered for the graph as the max speed
     * was reached too long ago
     */

    tmp_maxspeed = 0; tmp_maxspeedpos = 1;
    if (rx_maxspeedpos >= GRAPHSPLIT_WIDTH)
    {
        /* max speed calculation has to be redone */
        for (i=0; i < GRAPHSPLIT_WIDTH; i++)
        {
            if  (rx_speedarray[i] > tmp_maxspeed)
            {
                tmp_maxspeed = rx_speedarray[1];
                tmp_maxspeedpos = i;
            }
        }
        /* set new values */
        rx_maxspeed = tmp_maxspeed;
        rx_maxspeedpos = tmp_maxspeedpos;
    }

    tmp_maxspeed = 0; tmp_maxspeedpos = 1;
    if (tx_maxspeedpos >= GRAPHSPLIT_WIDTH)
    {
        /* max speed calculation has to be redone */
        for (i=0; i < GRAPHSPLIT_WIDTH; i++)
        {
            if  (tx_speedarray[i] > tmp_maxspeed)
            {
                tmp_maxspeed = tx_speedarray[1];
                tmp_maxspeedpos = i;
            }
        }
        /* set new values */
        tx_maxspeed = tmp_maxspeed;
        tx_maxspeedpos = tmp_maxspeedpos;
    }

    /* prepare the graph array
     *
     * shift the graph to the left and then add the last entry
     * in addition move the traffic stats left
     */

    /* move */
    for (x = GRAPHSPLIT_WIDTH-1; x >= 0; x--)
    {
        rx_speedarray[x] = rx_speedarray[x-1];
        tx_speedarray[x] = tx_speedarray[x-1];
        for (y = 0; y < GRAPHSPLIT_HEIGHT; y++)
        {
            rx_graph[x][y] = rx_graph[x-1][y];
            tx_graph[x][y] = tx_graph[x-1][y];
        }
    }

    /* add the last column */
    if(rx_maxspeed > 0)
        i = (int) ((rxspeed / rx_maxspeed) * GRAPHSPLIT_HEIGHT); 
    for (y = 0; y <= GRAPHSPLIT_HEIGHT; y++)
    {
        if (i > y)
            rx_graph[0][y] = 1;
        else
            rx_graph[0][y] = 0;
    }
    if (0 != (int) rxspeed)
        rx_graph[0][1] = 1;
    rx_speedarray[0] = rxspeed;

    if(tx_maxspeed > 0)
        i = (int) ((txspeed / tx_maxspeed) * GRAPHSPLIT_HEIGHT);
    for (y = 0; y <= GRAPHSPLIT_HEIGHT; y++)
    {   
        if (i > y)
            tx_graph[0][y] = 1;
        else
            tx_graph[0][y] = 0;
    }
    if (0 != (int) txspeed)
        tx_graph[0][1] = 1;
    tx_speedarray[0] = txspeed;

    /*
     * rescale graph
     *
     * in case the maxspeed for the shown graph changed we need to
     * recalculate the whole graph
     *
     */ 

    if (rx_scalechanged)
    {
        /* for each line rewrite the graph */
        for (x = GRAPHSPLIT_WIDTH-1; x >= 0; x--)
        {
            i = (int) ((rx_speedarray[x] / rx_maxspeed) * GRAPHSPLIT_HEIGHT);
            for (y = 0; y <= GRAPHSPLIT_HEIGHT; y++)
            {   
                if (i > y)
                    rx_graph[x][y] = 1;
                else
                    rx_graph[x][y] = 0;
            }
            if (rx_speedarray[x] != 0)
                rx_graph[x][1] = 1;
        }
    }
    if (tx_scalechanged)
    {
        /* for each line rewrite the graph */
        for (x = GRAPHSPLIT_WIDTH-1; x >= 0; x--)
        {
            i = (int) ((tx_speedarray[x] / tx_maxspeed) * GRAPHSPLIT_HEIGHT);
            for (y = 0; y <= GRAPHSPLIT_HEIGHT; y++)
            {
                if (i > y)
                    tx_graph[x][y] = 1;
                else
                    tx_graph[x][y] = 0;
            }
            if (tx_speedarray[x] != 0)
                tx_graph[x][1] = 1;
        }
    }


    /*
     * finally draw the two graphs line by line
     *
     * the rx graphs grows to the bottom
     */

    for (y = GRAPHSPLIT_HEIGHT-1; y > 0; y--)
    {
        for (x = 0; x <= GRAPHSPLIT_WIDTH; x++)
        {
            /* RX graph */
            if (rx_graph[x][y] == 1)
            {
				attrset(COLOR_PAIR(PAIR_RX) | 
					((unsigned long)(t.rx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
                mvprintw(7-y, x+1, SYMBOL_TRAFFIC);
            }
            else
                mvprintw(7-y, x+1, SYMBOL_NOTRAFFIC);
            /* TX graph */
            if (tx_graph[x][y] == 1)
            {
				attrset(COLOR_PAIR(PAIR_TX) | 
					((unsigned long)(t.tx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
                mvprintw(6+y, x+1, SYMBOL_TRAFFIC);
            }
            else
                mvprintw(6+y, x+1, SYMBOL_NOTRAFFIC);
        }
    }
    return 0;
}

/******************************************************************************
 *
 * update_stat_combined()
 *
 * this is the classic view for the graph known from 0.0.3
 *
 *****************************************************************************/
int update_stat_combined(void)
{
    float sumspeed;
    float rxspeed;
    float txspeed;
    int i=0,x,y;
    int rx_scalechanged = 0;       /* traffic scale changed? */

    float tmp_maxspeed = 0;     /* needed for max speed calc in graph */
    int tmp_maxspeedpos = 1;    /* same here */

    char draw[DRAWLEN+1];               /* what we draw on the screen */

    /* in case of REINIT we want to keep the rx and tx values as we can
     * recalculate the graph for the new mode based on them.
     */

    if (db_status == DB_STATUS_REINIT || db_status == DB_STATUS_STARTUP)
    {

        tx_maxspeed = 0; tx_overallmax = 0;
        rx_maxspeed = 0; rx_overallmax = 0;
        comb_maxspeed = 0; comb_overallmax = 0;
        /* fill the graph array with zeros */
        for (x = 0; x < GRAPH_WIDTH; x++)
        {
            for (y = 0; y < GRAPH_HEIGHT; y++)
            {
                rx_graph[x][y] = 0;
                tx_graph[x][y] = 0;
            }
        }

        /* force graph recalculation */
        rx_scalechanged++;

        if (db_status == DB_STATUS_STARTUP)
        {   
            stats.rx_bytes_comp = stats.rx_bytes;
            stats.tx_bytes_comp = stats.tx_bytes;
            for (x = 0; x < GRAPH_WIDTH; x++)
            {   
                rx_speedarray[x] = 0;
                tx_speedarray[x] = 0;
            }
            db_status = DB_STATUS_RUNNING;
            return 1;
        }
        db_status = DB_STATUS_RUNNING;
    }

    /*
     * current speed in bits/s
     *
     * in case of the expected u_long overflow in stats.?x_bytes
     * we will calculate a negative number as {sum|tx|rx}speed.
     * to prevent this we have to check if the _comp value is larger
     * than the current value. If true, we set _comp to 0
     */

    if (stats.rx_bytes_comp > stats.rx_bytes)
        stats.rx_bytes_comp = 0;
    if (stats.tx_bytes_comp > stats.tx_bytes)     
        stats.tx_bytes_comp = 0;

    sumspeed = ((stats.rx_bytes - stats.rx_bytes_comp) +
               (stats.tx_bytes - stats.tx_bytes_comp)) / refreshdelay;

    rxspeed = (stats.rx_bytes - stats.rx_bytes_comp) / refreshdelay;
    txspeed = (stats.tx_bytes - stats.tx_bytes_comp) / refreshdelay;

    /* print current speed */
    snprintf(draw, DRAWLEN-1, "%.2f KB/s", sumspeed / 1024);
	strncat(draw, "               ", DRAWLEN-strlen(draw));
    mvprintw(18, 24, "%s", draw);

    stats.rx_bytes_comp = stats.rx_bytes;
    stats.tx_bytes_comp = stats.tx_bytes;

    /* set new max speed for graph if reached */
    if (sumspeed > comb_maxspeed)
    {
        comb_maxspeed = sumspeed;
        rx_maxspeedpos = 0;
        rx_scalechanged++;
        if (sumspeed > comb_overallmax)
        {
            comb_overallmax = sumspeed;
            snprintf(draw, DRAWLEN-1, "%.2f KB/s", (float) sumspeed / 1024);
			strncat(draw, "               ", DRAWLEN-strlen(draw));
            mvprintw(19, 65, "%s", draw);
        }
    }

    /*
     * update the Graph Top Speed field
     * as it might be shorter than before just be sure to not leave
     * trailing garbage by printing spaces
     */

    if (rx_scalechanged)
    {
        snprintf(draw, DRAWLEN-1, "%.2f KB/s", comb_maxspeed / 1024);
		strncat(draw, "               ", DRAWLEN-strlen(draw));
        mvprintw(19, 24, "%s", draw);
    }

    /* increment position of max speed as we move the graph */
    rx_maxspeedpos++;

    /* check if max speed has to be lowered for the graph as the max speed
     * was reached too long ago
     */

    tmp_maxspeed = 0; tmp_maxspeedpos = 1;
    if (rx_maxspeedpos >= GRAPHCOMBINED_WIDTH)
    {
        /* max speed calculation has to be redone */
        for (i=0; i < GRAPHCOMBINED_WIDTH; i++)
        {
            if  (rx_speedarray[i] > tmp_maxspeed)
            {
                tmp_maxspeed = rx_speedarray[1];
                tmp_maxspeedpos = i;
            }
        }
        /* set new values */
        comb_maxspeed = tmp_maxspeed;
        rx_maxspeedpos = tmp_maxspeedpos;
    }

    /* prepare the graph array
     *
     * shift the graph to the left and then add the last entry
     * in addition move the traffic stats left
     *
     * there seems to be some redundancy in here regarding the rx/tx values
     * but we need it for seamless mode switching
     *
     */

    /* move */
    for (x = GRAPHCOMBINED_WIDTH-1; x >= 0; x--)
    {
        rx_speedarray[x] = rx_speedarray[x-1];
        tx_speedarray[x] = tx_speedarray[x-1];
        for (y = 0; y < GRAPHCOMBINED_HEIGHT; y++)
        {
            rx_graph[x][y] = rx_graph[x-1][y];
            tx_graph[x][y] = tx_graph[x-1][y];
        }
    }

    /* add the last column */
    if(comb_maxspeed > 0)
        i = (int) ((sumspeed / comb_maxspeed) * GRAPHCOMBINED_HEIGHT);
    for (y = 0; y <= GRAPHCOMBINED_HEIGHT; y++)
    {
        if (i > y)
            rx_graph[0][y] = 1;
        else
            rx_graph[0][y] = 0;
    }
    if (0 != (int) sumspeed)
        rx_graph[0][1] = 1;

    rx_speedarray[0] = rxspeed;
    tx_speedarray[0] = txspeed;

    /*
     * rescale graph
     *
     * in case the maxspeed for the shown graph changed we need to
     * recalculate the whole graph
     *
     */

    if (rx_scalechanged)
    {
        /* for each line rewrite the graph */
        for (x = GRAPHCOMBINED_WIDTH-1; x >= 0; x--)
        {
            i = (int) ((rx_speedarray[x] / comb_maxspeed) * GRAPHSPLIT_HEIGHT);
            for (y = 0; y <= GRAPHCOMBINED_HEIGHT; y++)
            {
                if (i > y)
                    rx_graph[x][y] = 1;
                else
                    rx_graph[x][y] = 0;
            }
            if (rx_speedarray[x] != 0)
                rx_graph[x][1] = 1;
        }
    }

    /*
     * finally draw the two graphs line by line
     *
     * the rx graphs grows to the bottom
     */

    for (y = GRAPHCOMBINED_HEIGHT-1; y > 0; y--)
    {
        for (x = 0; x <= GRAPHCOMBINED_WIDTH; x++)
        {
            /* RX graph */
            if (rx_graph[x][y] == 1)
            {
				attrset(COLOR_PAIR(PAIR_RX) | 
					((unsigned long)(t.rx_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
                mvprintw(13-y, x+1, SYMBOL_TRAFFIC);
            }
            else
                mvprintw(13-y, x+1, SYMBOL_NOTRAFFIC);
        }
    }
    return 0;
}

/******************************************************************************
 *
 * usage()
 *
 * print usage and die
 *
 *****************************************************************************/

void usage (int code, char **argv)
{
    fprintf(stderr, "slurm %s - Hendrik Scholz <hendrik@scholz.net>\n\n"
    "usage: %s [-hHz] [-csl] [-d delay] [-t theme] -i interface\n\n",
		PACKAGE_VERSION, argv[0]);
    fprintf(stderr, "    -h            print help\n"
					"    -z            zero counters at startup\n"
					"    -d delay      delay between refreshs in seconds"
					" (%d < delay < %d)\n"
                    "    -c            old classic/combined view\n"
                    "    -s            split window mode with stats\n"
                    "    -l            large split window mode\n"
					"    -L            enable TX/RX 'leds'\n"
                    "    -i interface  select network interface\n"
					"    -t theme      select a theme\n\n",
					REFRESH_MIN, REFRESH_MAX);
    _exit(code);
}

/******************************************************************************
 *
 * draw_face()
 *
 * draw the static parts of the screen
 *
 *****************************************************************************/

void draw_face(int displaymode, char *hostname)
{
    int x, y;

	attrset(COLOR_PAIR(PAIR_TEXT) | 
		((unsigned long)(t.text_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
    for(x = 0; x <= 24; x++)
	{
        for(y = 0; y <= 80; y++)
        {
            mvprintw(x, y, " "); 
        }
	}
    refresh();
    if (displaymode != MODE_LARGE)
    {
        mvprintw(20, 6, "Received Packets:");
        mvprintw(22, 3, "Errors on Receiving:");
        mvprintw(20, 44,"Transmitted Packets:");
        switch(data_type)
        {
			case TYPE_MEGA:
                mvprintw(21,  7, "MBytes Received:");
                mvprintw(21, 45, "MBytes Transmitted:");
                break;
			case TYPE_GIGA:
				mvprintw(21,  7, "GBytes Received:");
                mvprintw(21, 45, "GBytes Transmitted:");
                break;
        }
    }

    if (displaymode == MODE_SPLIT)
    {
        mvprintw(22, 41, "Errors on Transmission:");
#ifdef WITH_LED
		if (ledenabled)
		{
			mvprintw(14, 37, "RX");
			mvprintw(14, 41, "TX");
		}
#endif
        mvprintw(17,  6, "Current RX Speed:");
        mvprintw(19,  2, "Overall Top RX Speed:"); 
        mvprintw(18,  4, "Graph Top RX Speed:");
        mvprintw(17, 47, "Current TX Speed:");
        mvprintw(19, 43, "Overall Top TX Speed:");
        mvprintw(18, 45, "Graph Top TX Speed:");
        mvprintw(15,  6, "Active Interface:");
        mvprintw(15, 48, "Interface Speed:");
    }
    else if (displaymode == MODE_COMBINED)
    {
        mvprintw(22, 41, "Errors on Transmission:");
#ifdef WITH_LED
		if (ledenabled)
		{
			mvprintw(14, 37, "RX");
			mvprintw(14, 41, "TX");
		}
#endif

        mvprintw(18,  9, "Current Speed:");
        mvprintw(19, 46, "Overall Top Speed:");
        mvprintw(19,  7, "Graph Top Speed:");
        mvprintw(16,  6, "Active Interface:");
        mvprintw(16, 48, "Interface Speed:");
    }
    else
    {
        /* large split mode */
        mvprintw(21,  6, "Current RX Speed:");
        mvprintw(21, 47, "Current TX Speed:");
        mvprintw(22,  4, "Graph Top RX Speed:");
        mvprintw(22, 45, "Graph Top TX Speed:");

    }
	attrset(COLOR_PAIR(PAIR_TITLE) | 
		((unsigned long)(t.title_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
	if (hostname[0] != '\0')
    	center(00, "-= slurm %s on %s =-", VERSION, hostname);
	else
		center(00, "-= slurm %s =-", VERSION);
	attrset(COLOR_PAIR(PAIR_VAR) | 
		((unsigned long)(t.var_attrib==COL_BOLD)?A_BOLD:A_NORMAL));
    if (displaymode == MODE_SPLIT)
    {
        mvprintw(15, 24, "%s", ifdata.if_name);
        mvprintw(15, 65, "%s", (char *) ifdata.if_speedstring);
    }
    else if (displaymode == MODE_COMBINED)
    {
        mvprintw(16, 24, "%s", ifdata.if_name);
        mvprintw(16, 65, "%s", (char *) ifdata.if_speedstring);
    }
    refresh();
}

/*****************************************************************************
 *
 * main()
 *
 * this is where the nightmare starts
 *
 ****************************************************************************/

int main(int argc, char *argv[]) 
{  
    short int key_pressed;
    long now, old[2];
    int sec_value = 0;
    int min_value = 0;
    int reload = FALSE;
    int validinterface = 0;
    int displaymode = MODE_SPLIT;
    int modechange = 0;
    unsigned short int first = 1;
    unsigned short int disconnected = 0;
	char hostname[MAXHOSTNAMELEN+1];
	extern long refreshdelay;
	extern int ledenabled;
	float tmpdelay;
    int op;
	int z_option = FALSE;
	char *themep = NULL;
	hostname[0] = '\0';

    /* HP-UX related as of now but could become standard */
    ifdata.if_valid = 0;
    ifdata.if_id = 0;
    ifdata.if_amount = 0;

	ledenabled = 0;

	/* determine hostname */
	if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
		hostname[0] = '\0';

    /* handle command line options */
    while ((op = getopt(argc, argv, "Lhzd:clsi:t:")) != EOF)
    {
        switch (op)
        {
            case 'i':
                /* interface */
                snprintf((char *)ifdata.if_name,
                    (size_t) sizeof(ifdata.if_name), "%s", optarg);
                /* check if interface really exists */
#ifdef _HAVE_CHECKINTERFACE
                validinterface = checkinterface(); 
#else
                /* just trust the user for now */
                validinterface++;
#endif
                break;
            case 'h':
                /* print help and exit peacefully */
                usage(0, argv);
                break;
			case 'z':
				/* virtually reset all counters by adding an offset */
				z_option = TRUE;
				break;
			case 'd':
				/* delay between updates */
				tmpdelay = atof(optarg);
				if ((tmpdelay < REFRESH_MIN) || (tmpdelay > REFRESH_MAX))
				{
					fprintf(stderr,
							"delay has to be between %d and %d seconds!\n",
							 REFRESH_MIN, REFRESH_MAX);
					return 1;
				}
				else
					refreshdelay = tmpdelay;
				break;
            case 'c':
                /* use old classic/combined view */
                displaymode = MODE_COMBINED;
                break;
            case 'l':
                /* use large split window mode */
                displaymode = MODE_LARGE;
                break;
			case 'L':
				/* enable TX/RX led */
				ledenabled = 1;
				break;
            case 's':
                /* use default split window mode */
                displaymode = MODE_SPLIT;
                break;
			case 't':
				/* theme */
				themep = optarg;
				break;
            default:
                usage(1, argv);
                break;
        }
    }

	if (strlen(ifdata.if_name) == 0)
		usage(1, argv);

    if (!validinterface)
    {
        fprintf(stderr, "specified device does not exist or cannot "
                "be monitored!\n\nIf you think this is an error please report "
                "it to <hendrik@scholz.net>. Thanks!\n");
		exit(1);
    }

    /* Initialize some info variables */
    stats.tx_packets = 0; stats.tx_bytes = 0; stats.tx_errors = 0;
    stats.rx_packets = 0; stats.rx_bytes = 0; stats.rx_errors = 0;
    stats.tx_bytes_comp = 0; stats.tx_bytes_comp = 0;
    /* overruns */
    stats.rx_over = 0; stats.tx_over = 0;

    /*
     * run get_stat() once so watchif gets set and we get offsets in case
	 * -z cli option was given.
     */
    get_stat();
	if (z_option == TRUE)
		zero_stats();
	else
	{
		/* set all counters to zero */
	    stats.rx_packets_off = stats.rx_errors_off = 0;
	    stats.rx_over_off = stats.tx_packets_off = 0;
    	stats.tx_errors_off = stats.tx_over_off = 0;
	    stats.rx_bytes_off = stats.tx_bytes_off = 0;
	    stats.rx_bytes_comp_off = stats.tx_bytes_comp_off = 0;
	}

    /* determine interface speed
     * not all systems have this nice feature we display "unknown"
     * if the speed could not determined due to errors or lack of
     * this feature on the host operating system
     */
#if defined(_HAVE_BSD) || defined(__HPUX__) || defined(__Solaris__) || defined(__APPLE__)
    ifdata.if_speed = get_if_speed(ifdata.if_name);
    
    /* if ERR_IFACE_NO_SPEED we could not determine the interface speed
     * if ERR_IFACE_DOWN the interface was down
     * as we cannot monitor an interface which is down we exit quit
     */
    if (ifdata.if_speed == ERR_IFACE_DOWN)
    {
        fprintf(stderr, "interface '%s' is down\n", (char *) ifdata.if_name);
        return 1;
    }

    /* ifdata.if_speed is in kbit/s */
    if (ifdata.if_speed >= 1000)
        snprintf((char *) ifdata.if_speedstring, sizeof(ifdata.if_speedstring), "%d Mbit/s",
            (int) ifdata.if_speed/1000);
    else if ((ifdata.if_speed == 0) || (ifdata.if_speed ==  ERR_IFACE_NO_SPEED))
        snprintf((char *) ifdata.if_speedstring,
			sizeof(ifdata.if_speedstring), "unknown");
    else
        snprintf((char *) ifdata.if_speedstring,
			sizeof(ifdata.if_speedstring), "%d kbit/s",
            		(int) ifdata.if_speed/100);
#else
     snprintf((char *) ifdata.if_speedstring,
		sizeof(ifdata.if_speedstring), "unknown");
#endif

#if MEDIADEBUG
   return 0;
#endif

#ifndef NO_CURSES_E
    printf("\e(U"); 
#endif


	if (themep == NULL)
		theme_setdefault(&t);
	else
		theme_readfile(&t, themep);

	if (t.complete != E_ALL)
		error(ERR_FATAL, "broken theme");

    initscr();
    intrflush(stdscr, FALSE);
    start_color();
    curs_set(0); /* Toggle the cursor off */ 
    nonl(); 
    noecho(); 
    cbreak(); 
    nodelay(stdscr, TRUE);

#ifdef _HAVE_NCURSES
    if (use_default_colors() == OK) /* need ncurses for transparency */
        t.background = -1;
#endif

	init_pair(PAIR_TEXT, t.text, t.background);
	init_pair(PAIR_RX, t.rx, t.background);
	init_pair(PAIR_TX, t.tx, t.background);
	init_pair(PAIR_VAR, t.var, t.background);
	init_pair(PAIR_TITLE, t.title, t.background);
	attrset(COLOR_PAIR(PAIR_TEXT) |	
		((unsigned long)(t.text_attrib==COL_BOLD)?A_BOLD:A_NORMAL));

	/* curses is set up so make sure to shut it down correctly when
	 * receiving termination signals by calling slurm_shutdown()	
	 */

	signal(SIGHUP,  slurm_shutdown); signal(SIGINT,  slurm_shutdown);
	signal(SIGQUIT, slurm_shutdown); signal(SIGKILL, slurm_shutdown);
	signal(SIGTERM, slurm_shutdown);

    draw_face(displaymode, hostname); 
    update_info(displaymode);
    now = time(NULL);
    old[0] = old[1] = time(NULL) - 3;

	for (;;)
    { 
		get_stat();
#ifdef WITH_LED
		if (ledenabled)
		{
			if (displaymode != MODE_LARGE)
			{
				/* In case of a new RX Packet... the RX Led Turn on 
				 * Else... Turn off */
				if (stats.rx_packets != stats.rx_packets_led)
					led_on(LED_RX);
				else
					led_off(LED_RX);
				/* In case of a new TX Packet... the TX Led Turn on
				 * Else... Turn off */
				if (stats.tx_packets != stats.tx_packets_led)
					led_on(LED_TX);
				else
					led_off(LED_TX);
			}
		} /* end ledenabled */
#endif

        stats.rx_packets_led = stats.rx_packets;
        stats.tx_packets_led = stats.tx_packets;

        get_time();
		/* check if we have to switch to Gbytes mode */
		if (data_type != TYPE_GIGA &&
			((stats.tx_bytes > 1073735680) ||
			(stats.rx_bytes > 1073735680)))
		{
			data_type = TYPE_GIGA;
			draw_face(displaymode, hostname);	
		}

        update_info(displaymode);

        if((!sec_value && first) || disconnected)
        {
            sec_value = stats.online_sec;
            min_value = stats.online_min;
            update_stat(displaymode);
            first = 0; disconnected = 0;
        }
	 
        now = time(NULL);
	 
        if(stats.online_sec != sec_value)
        {
            update_stat(displaymode);
            sec_value = stats.online_sec;
        }

		/* move cursor to upper left corner */
		move (0, 0);

		tmpdelay = refreshdelay * 10;
		do
		{
			usleep(100*1000); /* 10th of a second */
			tmpdelay--;
			key_pressed = getch();
			if (key_pressed != ERR)
				break;
		} while (tmpdelay > 0);

        if (key_pressed != ERR && tolower(key_pressed) == 'q')
            break;
        else if (key_pressed != ERR && tolower(key_pressed) == 'c')
        {
            displaymode = MODE_COMBINED;
            modechange++;
        }
        else if (key_pressed != ERR && tolower(key_pressed) == 'l')
        {
            displaymode = MODE_LARGE;
            modechange++;
        }
        else if (key_pressed != ERR && tolower(key_pressed) == 's')
        {
            displaymode = MODE_SPLIT;
            modechange++;
        }
        else if (key_pressed != ERR && tolower(key_pressed) == 'm')
        {
            if (displaymode == MODE_COMBINED)
                displaymode = MODE_SPLIT;
            else if (displaymode == MODE_SPLIT)
                displaymode = MODE_LARGE;
            else
                displaymode = MODE_COMBINED;

            modechange++;
        }
        else if (key_pressed != ERR && tolower(key_pressed) == 'r')
        {
            draw_face(displaymode, hostname);
            update_stat(displaymode);
            reload = TRUE;
        }
		else if (key_pressed != ERR && tolower(key_pressed) == 'z')
		{
			zero_stats();
			update_stat(displaymode);
			reload = TRUE;
		}

        /* if the display mode change we need to redraw the face and
         * reinitialize the graph arrays
         * draw_face() clears the screen
         */

        if (modechange)
        {
            db_status = DB_STATUS_REINIT;
            modechange = 0;
            draw_face(displaymode, hostname);
        }
    }
	slurm_shutdown(1); /* needs a bogus parameter :) */
   return 0; 
}
/******************************************************************************
 *
 * update_stat()
 *
 * graph update dispatcher, just calls the right function
 *
 *****************************************************************************/
int update_stat(int displaymode)
{
    switch (displaymode)
    {
        case MODE_COMBINED:
            return update_stat_combined();
            break;
        case MODE_SPLIT:
            return update_stat_split();
            break;
        case MODE_LARGE:
            return update_stat_large();
            break;
        default:
            return 1;
    }
}
/******************************************************************************
 *
 * zero_stats()
 *
 * redefine the offsets for all counters so we can virtually reset
 * the counters on the display
 *
 *****************************************************************************/

void zero_stats(void)
{
	stats.rx_packets_off = stats.rx_packets;
    stats.rx_errors_off = stats.rx_errors;
    stats.rx_over_off = stats.rx_over;
    stats.tx_packets_off = stats.tx_packets;
    stats.tx_errors_off = stats.tx_errors;
    stats.tx_over_off = stats.tx_over;
    stats.rx_bytes_off = stats.rx_bytes;
    stats.tx_bytes_off = stats.tx_bytes;
    stats.rx_bytes_comp_off = stats.rx_bytes_comp;
    stats.tx_bytes_comp_off = stats.tx_bytes_comp;
}

/******************************************************************************
 *
 * slurm_shutdown()
 *
 * shutdown curses so we get a clean terminal.
 *
 *****************************************************************************/

void slurm_shutdown (int sig)
{
	endwin();
	system("clear");
	curs_set(1);
	fprintf(stdout, "slurm %s by Hendrik Scholz - "
		"http://www.wormulon.net/slurm/\n", VERSION);

	/* close dev if running Linux */
#ifdef __linux__
	fclose(proc_net_dev);
#endif
	exit (0);
}


syntax highlighted by Code2HTML, v. 0.9.1