/******************************************************************************
 *  bwm-ng parsing stuff                                                      *
 *                                                                            *
 *  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"


#ifdef __IOCTL
/* following only for check_if_up and ioctl */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#endif

extern void print_values(int y,int x,char *if_name,t_iface_stats new_stats,t_iface_stats stats,float multiplier);
extern int deinit(char *error_msg);

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;

#ifdef __IOCTL
/* fd for check_if_up and ioctl */
int skfd = -1;
#endif

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


#ifdef __IOCTL
/* test whether the iface is up or not */
char check_if_up(char *ifname) {
    struct ifreq ifr;
    if (skfd < 0) {
        /* maybe check some /proc file first like net-tools do */
        if ((skfd =  socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
            deinit("socket error");
        }
    }
    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
        return 0; /* return if as down if there was some error */
    }
    if (ifr.ifr_flags & IFF_UP) return 1; /* check against IFF_UP and return */
        else return 0;
}
#endif


/* returns the position of the match, first=1, no match=0 */
short strcomp(char *instr, char *searchstr) {
	int pos = 0,
	k,number=1;
	k = strlen( searchstr );
	do {
		switch ( *instr ) {
			case 0:
			case ',':
				if ( k == pos && ! strncasecmp( instr - pos, searchstr, pos ) ) {
					return number;
                } else number++;
				pos = 0;
				break;
			default:
				pos++;
				break;
			}
		} while ( *instr++ );
	return 0;
}



/* do the actual work, get and print stats if verbose */
void get_iface_stats (char verbose) {
    FILE *f;
    char buffer[1024],name[1024];
    char *ptr;
    unsigned long long buf;
    int local_if_count=0,hidden_if=0;
    float multiplier=(float)1000/delay;
    t_iface_stats stats,tmp_if_stats; /* local struct, used to calc total values */
    memset(&stats,0,(size_t)sizeof(t_iface_stats)); /* init it */
    /* dont open proc_net_dev if netstat_i is requested, else try to open and if it fails fallback */
    if (netstat_i || !(f=fopen(PROC_NET_DEV,"r"))) {
        if (show_all_if) {
            if (!(f=popen("netstat -ia","r"))) {
                deinit("no input stream found");
            }
        } else {
            if (!(f=popen("netstat -i","r"))) {
                deinit("no input stream found");
            }
        }
        netstat_i=1;
    }
    if ((fgets(buffer,1023,f) != NULL ) && (fgets(buffer,1023,f) != NULL )) {
        while (fgets(buffer,1023,f) != NULL ) {
            memset(&tmp_if_stats,0,(size_t)sizeof(t_iface_stats)); /* reinit it to zero */
            if (!netstat_i) {
                /* get the name */
                ptr=strchr(buffer,':');
                /* wrong format */
                if (ptr==NULL) { deinit("wrong format of input stream"); }
                /* set : to end_of_string and move to first char of "next" string (to first data) */
                *ptr++ = 0;
                sscanf(ptr,"%llu%llu%llu%llu%llu%llu%llu%llu%llu%llu",&tmp_if_stats.rec,&tmp_if_stats.p_rec,&buf,&buf,&buf,&buf,&buf,&buf,&tmp_if_stats.send,&tmp_if_stats.p_send);
                sscanf(buffer,"%s",name);
            } else {
                sscanf(buffer,"%s%llu%llu%llu%llu%llu%llu%llu%llu",name,&buf,&buf,&tmp_if_stats.p_rec,&buf,&buf,&buf,&tmp_if_stats.p_send,&buf);
            }
            for (local_if_count=0;local_if_count<if_count;local_if_count++) {
                /*check if its the correct if */
                if (!strcmp(name,if_stats[local_if_count].if_name)) break;
            }
            if (local_if_count==if_count) {
                /* iface not found, seems like there is a new one! */
                if_count++;
                if_stats=(t_iface_stats*)realloc(if_stats,sizeof(t_iface_stats)*if_count);
                /* copy the iface name or add a dummy one */
                if (name[0]!='\0')
                    if_stats[if_count-1].if_name=(char*)strdup(name);
                else
                    if_stats[if_count-1].if_name=(char*)strdup("unknown");
                /* set it to current value, so there is no peak at first announce,
                 * we cannot copy the struct cause we wanna safe the name */
                if_stats_total.send+=if_stats[local_if_count].send=tmp_if_stats.send;
                if_stats_total.rec+=if_stats[local_if_count].rec=tmp_if_stats.rec;
                if_stats_total.p_send+=if_stats[local_if_count].p_send=tmp_if_stats.p_send;
                if_stats_total.p_rec+=if_stats[local_if_count].p_rec=tmp_if_stats.p_rec;
            }
            if (verbose) { /* any output at all? */
				if (
#ifdef __IOCTL				
					(show_all_if || check_if_up(name)) && /* is it up or do we show all ifaces? */ 
#endif
					(iface_list==NULL || strcomp(iface_list,name))) {
	                    print_values(5+local_if_count-hidden_if,8,name,tmp_if_stats,if_stats[local_if_count],multiplier);
#ifdef __IOCTL					
				} else
                    hidden_if++; /* increase the opt cause we dont show this if */
#endif				
            }
            /* save current stats for the next run add current iface stats to total */
            stats.send+=if_stats[local_if_count].send=tmp_if_stats.send;
            stats.rec+=if_stats[local_if_count].rec=tmp_if_stats.rec;
            stats.p_send+=if_stats[local_if_count].p_send=tmp_if_stats.p_send;
            stats.p_rec+=if_stats[local_if_count].p_rec=tmp_if_stats.p_rec;
        }
    } /* fgets done */
    if (verbose) {
        /* output total ifaces stats */
        if (output_method==CURSES_OUT)
            mvwprintw(stdscr,6+local_if_count-hidden_if,8,"------------------------------------------------------------------");
        else if (output_method==PLAIN_OUT)
            printf("------------------------------------------------------------------\n");
        print_values(7+local_if_count-hidden_if,8,"total",stats,if_stats_total,multiplier); 
    }
    /* save the data in total-struct */
    if_stats_total.send=stats.send;
    if_stats_total.rec=stats.rec;
    if_stats_total.p_send=stats.p_send;
    if_stats_total.p_rec=stats.p_rec;
    /* close input stream */
    if (netstat_i)
        pclose(f);
    else
        fclose(f);
    return;
}

