/***************************************************************************
 *            dlgdetails.c
 *
 *  Mon May 10 20:28:29 2004
 *  Copyright  2004  Vladimir Đokić
 *  vladeck@gnome-ppp.org
 ****************************************************************************/

/*
 *  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 Library 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.
 */

/* Parts of this code
 * Copyright (C) 2003 Sun Microsystems, Inc.
 *
 * Authors:
 *    Erwann Chenede  <erwann.chenede@sun.com>
 *    Mark McLoughlin  <mark@skynet.ie>  
 *    Joe Marcus Clarke  <marcus@freebsd.org>
 */

#include <unistd.h>
#include "gnome-ppp.h"


static inline gint parse_stats( gchar *buf, gint prx_idx, gint ptx_idx,
				glong *in_packets, glong *out_packets,
				gint brx_idx, gint btx_idx,
				glong *in_bytes, glong *out_bytes )
{
	gchar *p;
	gint i;
	
	p = strtok (buf, " \t\n");
	
	for (i = 0; p; i++, p = strtok (NULL, " \t\n")) {
		
		if (i == prx_idx)
			*in_packets = g_ascii_strtoull (p, NULL, 10);
		
		if (i == ptx_idx)
			*out_packets = g_ascii_strtoull (p, NULL, 10);
		
		if (i == brx_idx)
			*in_bytes = g_ascii_strtoull (p, NULL, 10);
		
		if (i == btx_idx)
			*out_bytes = g_ascii_strtoull (p, NULL, 10);
	}
	
	if (i <= prx_idx || i <= ptx_idx || i <= brx_idx || i <=btx_idx)
		return FALSE;
	
	return TRUE;
}

static inline gchar *parse_iface_name (const gchar *buf)
{
	gchar *p1;
	
	if ((p1 = strchr (buf, ':'))) {		
		gchar *p2;
		
		p2 = strchr (p1, ':');
		
		if (p2)
			*p2++ = '\0';
		else
			*p1++ = '\0';
		
		return p2 ? p2 : p1;
	} else if ((p1 = strchr (buf, ' '))) {
		*p1++ = '\0';
		return p1;
	}
	
	return NULL;
}

static inline void parse_header (gchar *buf, gint *prx_idx, gint *ptx_idx,
				gint *brx_idx, gint *btx_idx)
{
	gchar *p;
	gint i;
	
	*prx_idx = *ptx_idx = -1;
	*brx_idx = *btx_idx = -1;
	
	p = strtok (buf, "| \t\n");
	p = strtok (NULL, "| \t\n"); /* skip the first one */
	
	for (i = 0; p; i++, p = strtok (NULL, "| \t\n")) {
		
		if (!strcmp (p, "packets")) {
			
			if (*prx_idx == -1)
				*prx_idx = i;
			else
				*ptx_idx = i;
		} else if (!strcmp (p, "bytes")) {
			
			if (*brx_idx == -1)
				*brx_idx = i;
			else
				*btx_idx = i;
		}
	}
}

static inline FILE *get_proc_net_dev_fh (void)
{
	static FILE *retval = NULL;
	
	if (retval != NULL)
		return retval;
	
	return retval = fopen ("/proc/net/dev", "r");
}

gchar *get_transfer_details (const gchar *iface, glong *packets_in, glong *packets_out,
			glong *bytes_in, glong *bytes_out)
{
	FILE *fh;
	gchar buf[512];
	gint prx_idx, ptx_idx;
	gint brx_idx, btx_idx;
	gchar *error_message = NULL;
	
	*packets_in = -1;
	*packets_out = -1;
	*bytes_in = -1;
	*bytes_out = -1;
	
	fh = get_proc_net_dev_fh ();
	
	if (!fh)
		/*return g_strdup_printf (_("Cannot open /proc/net/dev: %s"), g_strerror (errno));*/
		return g_strdup (_("Cannot open /proc/net/dev: %s"));
	
	fgets (buf, sizeof (buf), fh);
	fgets (buf, sizeof (buf), fh);
	
	parse_header (buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx);
	
	if (prx_idx == -1 || ptx_idx == -1 ||
		brx_idx == -1 || btx_idx == -1) {		
		return g_strdup (_("Could not parse /proc/net/dev. Unknown format."));
	}
	
	while (fgets (buf, sizeof (buf), fh)) {		
		gchar *stats;
		gchar *name;
		
		name = buf;
		
		while (g_ascii_isspace (name[0]))
			name++;
		
		stats = parse_iface_name (name);
		
		if (!stats) {
			
			if (!error_message)
				error_message = g_strdup_printf (_("Could not parse interface name from '%s'"), buf);
			continue;
		}
		
		if (strcmp (name, iface) != 0)
			continue;
		
		if (!parse_stats (stats, prx_idx, ptx_idx, packets_in, packets_out,
					brx_idx, btx_idx, bytes_in, bytes_out)) {
			
			if (error_message)
				g_free (error_message);
			
			error_message = g_strdup_printf (_("Could not parse interface statistics from '%s'. "
							"prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;"),
							buf, prx_idx, ptx_idx, brx_idx, btx_idx);
			
			continue;
		}
	}
	
	if ((*packets_in == -1 || *packets_out == -1 || *bytes_in == -1 || *bytes_out == -1) && !error_message)
		error_message = g_strdup_printf (_("Could not find information on interface '%s' in /proc/net/dev"), iface);
		
	rewind (fh);
		
	return error_message;	
}

gboolean get_addr_details (const gchar *iface, char **addr, char **dest)
{
	struct ifreq if_req;
	gint fd;
	gint flags;
	
	if (addr)
		*addr = NULL;
	
	if (dest)
		*dest = NULL;
	
	if (!iface)
		return FALSE;
	
	if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
		/*g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n", g_strerror (errno));*/
		return FALSE;
	}
	
	if_req.ifr_addr.sa_family = AF_INET;
	
	strncpy (if_req.ifr_name, iface, IF_NAMESIZE - 1);
	if_req.ifr_name[IF_NAMESIZE - 1] = '\0';
	
	if (addr && ioctl (fd, SIOCGIFADDR, &if_req) == 0)
		*addr = g_strdup (inet_ntoa (((struct sockaddr_in *)&if_req.ifr_addr)->sin_addr));
	
	if (addr && !*addr) {
		close( fd );
		return FALSE;
	}
	strncpy (if_req.ifr_name, iface, IF_NAMESIZE - 1);
	if_req.ifr_name[IF_NAMESIZE - 1] = '\0';
	
	if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0) {
		close (fd);
		return TRUE;
	}
	flags = if_req.ifr_flags;
	
	strncpy (if_req.ifr_name, iface, IF_NAMESIZE - 1);
	if_req.ifr_name[IF_NAMESIZE - 1] = '\0';
	
	if (dest && flags & IFF_POINTOPOINT && ioctl (fd, SIOCGIFDSTADDR, &if_req) == 0)
		*dest = g_strdup (inet_ntoa (((struct sockaddr_in *)&if_req.ifr_dstaddr)->sin_addr));
	
	close (fd);
	
	return TRUE;
}

void on_details_close (GtkWidget *widget, gpointer data)
{
	gtk_widget_hide (gnome_ppp.details.window);
}
