/*Network monitor for system tray*/
/*(c) Copyright Barry Kauler 2010, bkhome.org*/
/*GPL license: /usr/share/doc/legal/gpl-2.0.txt*/
/*first release, version 2.0, may 18, 2010*/
/*version 2.1: new icons*/
/*version 2.3: icons now external, now displays dead icon correctly*/
/*version 2.3.2: still trying to get icon to update correctly*/
/*version 2.4: display tx/rx in KB if <1024, improved mouse-click operations*/
/*version 2.4.1: fix icon update when disconnect/reconnect*/
/*version 2.4.2: display acc monthly tx/rx*/
/*version 2.4.3: change 'long int' to 'long long int' -- 32-bit to 64-bit*/
/*2.5 (20120519): rodin.s: added gettext*/

#include <string.h>
#include <libintl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gstdio.h>
#include <dirent.h>
#include <errno.h>
#define _(STRING)    gettext(STRING)

/*#include "networkblank.xpm"
#include "networkboth.xpm"
#include "networkdead.xpm"
#include "networkin.xpm"
#include "networkout.xpm"*/

GdkPixbuf *networkblank_pixbuf;
GdkPixbuf *networkboth_pixbuf;
GdkPixbuf *networkdead_pixbuf;
GdkPixbuf *networkin_pixbuf;
GdkPixbuf *networkout_pixbuf;

GtkStatusIcon *tray_icon;
unsigned int interval = 500; /*update interval in milliseconds*/

char *netdir="/sys/class/net";
DIR *dip;
struct dirent *dit;
//int  i = 0;
char buf1[1024];
FILE *fp;
char char1;
int flagactive=0;
int flagactiveprev=0;
char infomsg[256];
char rxstr[52];
long long int rxacc=0;
char rxaccstr[64];
char txstr[52];
long long int txacc=0;
char txaccstr[64];
long long int rxaccprev=0;
long long int txaccprev=0;
int flagtransfer=0;
int flagtransferprev=0;
int loopcnt=0;
int breakcnt=0;
int flagdisconnect=0;

//100814
char *rxmonthfile="/var/local/sns/rx_bytes_month";
char *txmonthfile="/var/local/sns/tx_bytes_month";
char rxstrmonth[52];
long long int rxaccmonth=0;
char txstrmonth[52];
long long int txaccmonth=0;
long long int rxaccmonth_updated=0;
long long int txaccmonth_updated=0;

GError *gerror;


gboolean Update(gpointer ptr);
int find_active();

int find_active() {

    flagactive=0;
    infomsg[0]=0;
    strcat(infomsg,_("Active interfaces: "));
    
    dip=opendir(netdir);
    if (dip==NULL) return 1;
    
    while ((dit = readdir(dip)) != NULL)
    {
        //i++;
        if (strcmp(dit->d_name,".")!=0 && strcmp(dit->d_name,"..")!=0 && strcmp(dit->d_name,"lo")!=0 ) {
            buf1[0]=0;
            strcat(buf1,netdir);
            strcat(buf1,"/");
            strcat(buf1,dit->d_name);
            strcat(buf1,"/dormant");
            fp=fopen(buf1,"r");
            if (fp!=NULL) {
                char1=fgetc(fp);
                fclose(fp);
                //if interface active, char1==0...
                if (char1=='0') {
                    flagactive=flagactive+1;
                    strcat(infomsg,dit->d_name);
                    strcat(infomsg," ");
                    //accumulate bytes received...
                    buf1[0]=0;
                    strcat(buf1,netdir);
                    strcat(buf1,"/");
                    strcat(buf1,dit->d_name);
                    strcat(buf1,"/statistics/rx_bytes");
                    fp=fopen(buf1,"r");
                    if (fp!=NULL) {
                        fgets(rxstr,12,fp);
                        rxacc=atol(rxstr)/1024;
                        fclose(fp);
                    }
                    rxaccmonth_updated=(rxaccmonth+rxacc)/1024; //100814 in MB
                    //accumulate bytes transmitted...
                    buf1[0]=0;
                    strcat(buf1,netdir);
                    strcat(buf1,"/");
                    strcat(buf1,dit->d_name);
                    strcat(buf1,"/statistics/tx_bytes");
                    fp=fopen(buf1,"r");
                    if (fp!=NULL) {
                        fgets(txstr,12,fp);
                        txacc=atol(txstr)/1024;
                        fclose(fp);
                    }
                    txaccmonth_updated=(txaccmonth+txacc)/1024; //100814 in MB
                    
                }
            }
        }
    }

    closedir(dip);
    if (flagactive==0) {
        strcat(infomsg,_("none "));
        strcat(infomsg,_(" Click this icon for network setup"));
    }
    else {
        if (rxacc < 1024) {
            sprintf(rxaccstr,"%.1f",((float)rxacc));
            strcat(infomsg," Rx:");
            strcat(infomsg,rxaccstr);
            strcat(infomsg,_("KB "));
        }
        else {
            sprintf(rxaccstr,"%.1f",((float)rxacc/1024.0));
            strcat(infomsg," Rx:");
            strcat(infomsg,rxaccstr);
            strcat(infomsg,_("MB "));
        }
        //100814 monthly acc...
        sprintf(rxaccstr,_("(Month:%dMB) "),rxaccmonth_updated);
        strcat(infomsg,rxaccstr);
        if (txacc < 1024) {
            sprintf(txaccstr,"%.1f",((float)txacc));
            strcat(infomsg," Tx:");
            strcat(infomsg,txaccstr);
            strcat(infomsg,"KB ");
        }
        else {
            sprintf(txaccstr,"%.1f",((float)txacc/1024.0));
            strcat(infomsg," Tx:");
            strcat(infomsg,txaccstr);
            strcat(infomsg,_("MB "));
        }
        //100814 monthly acc...
        sprintf(txaccstr,_("(Month:%dMB) "),txaccmonth_updated);
        strcat(infomsg,txaccstr);
    }
}

gboolean Update(gpointer ptr) {

    find_active();
    loopcnt=loopcnt+1;
    
    if (flagactive==0) flagtransfer=0;
    else {
        flagtransfer=1;
        if (rxacc!=rxaccprev) flagtransfer=2;
        if (txacc!=txaccprev) flagtransfer=3;
        if (txacc!=txaccprev && rxacc!=rxaccprev) flagtransfer=4;
    }
    //printf("loopcnt=%i flagtransfer=%i flagactive=%i\n",loopcnt,flagtransfer,flagactive); fflush(stdout); //TEST
    //lot of trouble with this logic, so introduce breakcnt to force icon update if stuck...
    if (flagtransferprev == flagtransfer) {
    if (loopcnt != 1) { //want to update icon on first loop.
        if (flagactive == flagactiveprev && flagtransfer == flagtransferprev && flagtransfer == 1) breakcnt=breakcnt+1; //no change.
        if (flagactive == flagactiveprev && flagtransfer == flagtransferprev && flagactive == 0) breakcnt=breakcnt+1; //no change.
    }
    else breakcnt=0;
    if (breakcnt != 0 && breakcnt < 8) return; //force update after 4 seconds.
    }
    breakcnt=0;
    flagactiveprev=flagactive;
    txaccprev=txacc;
    rxaccprev=rxacc;
    flagtransferprev=flagtransfer;
    
    if (flagtransfer==0) gtk_status_icon_set_from_pixbuf(tray_icon,networkdead_pixbuf);
    else if (flagtransfer==1) gtk_status_icon_set_from_pixbuf(tray_icon,networkblank_pixbuf);
    else if (flagtransfer==2) gtk_status_icon_set_from_pixbuf(tray_icon,networkin_pixbuf);
    else if (flagtransfer==3) gtk_status_icon_set_from_pixbuf(tray_icon,networkout_pixbuf);
    else if (flagtransfer==4) gtk_status_icon_set_from_pixbuf(tray_icon,networkboth_pixbuf);
    
    //update tooltip...
    gtk_status_icon_set_tooltip(tray_icon, infomsg);
}

void  view_popup_menu_onSetupNetworking (GtkWidget *menuitem, gpointer userdata);
void  view_popup_menu_onSetupNetworking (GtkWidget *menuitem, gpointer userdata)
  {
    /* we passed the view as userdata when we connected the signal */
    /*GtkTreeView *treeview = GTK_TREE_VIEW(userdata);*/
    system("defaultconnect & ");
  }

void  view_popup_menu_onNetworkStatus (GtkWidget *menuitem, gpointer userdata);
void  view_popup_menu_onNetworkStatus (GtkWidget *menuitem, gpointer userdata)
  {
    system("ipinfo & ");
  }

void  view_popup_menu_onDisconnect (GtkWidget *menuitem, gpointer userdata);
void  view_popup_menu_onDisconnect (GtkWidget *menuitem, gpointer userdata)
  {
    flagdisconnect=1;
    system("/usr/local/apps/Connect/AppRun --disconnect & ");
  }

void  view_popup_menu_onReconnect (GtkWidget *menuitem, gpointer userdata);
void  view_popup_menu_onReconnect (GtkWidget *menuitem, gpointer userdata)
{
    system("/usr/local/apps/Connect/AppRun --connect & ");
    flagactiveprev=0; /*100703*/
}

void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data)
{
        GtkWidget *menu, *menuitem;
        menu = gtk_menu_new();
        menuitem = gtk_menu_item_new_with_label(_("Setup networking"));
        g_signal_connect(menuitem, "activate", (GCallback) view_popup_menu_onSetupNetworking, status_icon);
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
        menuitem = gtk_menu_item_new_with_label(_("Network status information"));
        g_signal_connect(menuitem, "activate", (GCallback) view_popup_menu_onNetworkStatus, status_icon);
        gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
        if (flagactive != 0) {
            flagdisconnect=0;
            menuitem = gtk_menu_item_new_with_label(_("Disconnect from network"));
            g_signal_connect(menuitem, "activate", (GCallback) view_popup_menu_onDisconnect, status_icon);
            gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
        }
        if (flagdisconnect == 1) {
            menuitem = gtk_menu_item_new_with_label(_("Reconnect to network"));
            g_signal_connect(menuitem, "activate", (GCallback) view_popup_menu_onReconnect, status_icon);
            gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
        }
        gtk_widget_show_all(menu);
        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, gdk_event_get_time(NULL));
}

void tray_icon_on_click(GtkStatusIcon *status_icon, gpointer user_data)
{
    if (flagactive == 0)system("defaultconnect & ");
    else {
        system(_("yaf-splash -placement bottom -bg purple -timeout 10 -text 'Note: right-click icon for network menu' & "));
        system("ipinfo & ");
    }
}

static GtkStatusIcon *create_tray_icon() {

    tray_icon = gtk_status_icon_new();
    g_signal_connect(G_OBJECT(tray_icon), "activate", G_CALLBACK(tray_icon_on_click), NULL);
    g_signal_connect(G_OBJECT(tray_icon), "popup-menu", G_CALLBACK(tray_icon_on_menu), NULL);

    /*networkblank_pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)networkblank_xpm);
    networkboth_pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)networkboth_xpm);
    networkdead_pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)networkdead_xpm);
    networkin_pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)networkin_xpm);
    networkout_pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)networkout_xpm);*/
    
    networkblank_pixbuf=gdk_pixbuf_new_from_file("/usr/local/lib/X11/mini-icons/networkblank.xpm",&gerror);
    networkboth_pixbuf=gdk_pixbuf_new_from_file("/usr/local/lib/X11/mini-icons/networkboth.xpm",&gerror);
    networkdead_pixbuf=gdk_pixbuf_new_from_file("/usr/local/lib/X11/mini-icons/networkdead.xpm",&gerror);
    networkin_pixbuf=gdk_pixbuf_new_from_file("/usr/local/lib/X11/mini-icons/networkin.xpm",&gerror);
    networkout_pixbuf=gdk_pixbuf_new_from_file("/usr/local/lib/X11/mini-icons/networkout.xpm",&gerror);

    gtk_status_icon_set_from_pixbuf(tray_icon,networkblank_pixbuf);

    gtk_status_icon_set_tooltip(tray_icon,_("No active network interfaces"));
    gtk_status_icon_set_visible(tray_icon, TRUE);
    return tray_icon;
}

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

    gtk_init(&argc, &argv);
    
    setlocale( LC_ALL, "" );
    bindtextdomain( "network_tray", "/usr/share/locale" );
    textdomain( "network_tray" );

    //100814 monthly acc (see also /usr/local/simple_network_setup/rc.network and rc.shutdown)...
    fp=fopen(rxmonthfile,"r");
    if (fp!=NULL) {
       fgets(rxstrmonth,12,fp);
       rxaccmonth=atol(rxstrmonth)/1024; //in KB.
       fclose(fp);
    }
    fp=fopen(txmonthfile,"r");
    if (fp!=NULL) {
       fgets(txstrmonth,12,fp);
       txaccmonth=atol(txstrmonth)/1024;
       fclose(fp);
    }

    tray_icon = create_tray_icon();
        
    gtk_timeout_add(interval, Update, NULL);

    gtk_main();
    return 0;
}
