1 /* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
2 /* gnome-netinfo - A GUI Interface for network utilities
3  * Copyright (C) 2002, 2003 by German Poo-Caaman~o
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include <gtk/gtk.h>
21 #include <glib/gi18n.h>
22 #include <glib/gprintf.h>
23 #include <sys/types.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27 
28 #ifdef HAVE_CONFIG_H
29 #  include <config.h>
30 #endif
31 
32 #ifdef HAVE_SYS_SOCKIO_H
33 #  include <sys/sockio.h>
34 #endif
35 
36 
37 #include <netinet/in.h>
38 #include <sys/socket.h>	/* basic socket definitions */
39 #include <arpa/inet.h>	/* inet(3) functions */
40 #include <sys/un.h>	/* for Unix domain sockets */
41 #include <sys/ioctl.h>
42 #include <stdlib.h>
43 #include <net/if.h>
44 #ifdef __FreeBSD__
45 #include <net/if_media.h>
46 #endif
47 
48 #include <glibtop.h>
49 #include <glibtop/netlist.h>
50 #include <glibtop/netload.h>
51 
52 #include "info.h"
53 #include "utils.h"
54 #include "util-mii.h"
55 
56 #ifndef IN6_IS_ADDR_GLOBAL
57 #define IN6_IS_ADDR_GLOBAL(a) \
58    (((((__const uint8_t *) (a))[0] & 0xff) == 0x3f   \
59      || (((__const uint8_t *) (a))[0] & 0xff) == 0x20))
60 #endif
61 
62 static gboolean info_nic_update_stats (gpointer data);
63 static GList   *info_get_interfaces   (Netinfo *info);
64 
65 static InfoInterfaceDescription info_iface_desc [] = {
66 	/*  Interface Name                 Interface Type           icon          Device prefix  Pixbuf  */
67 	{ N_("Other type"),              INFO_INTERFACE_OTHER,   "network.png",     "other_type", NULL },
68 	{ N_("Ethernet Interface"),      INFO_INTERFACE_ETH,     "16_ethernet.xpm", "eth",        NULL },
69 	{ N_("Wireless Interface"),      INFO_INTERFACE_WLAN,    "wavelan-16.png",  "wlan",       NULL },
70 	{ N_("Modem Interface"),         INFO_INTERFACE_PPP,     "16_ppp.xpm",      "ppp",        NULL },
71 	{ N_("Modem Interface"),         INFO_INTERFACE_PPP,     "16_ppp.xpm",      "tun",        NULL },
72 	{ N_("Parallel Line Interface"), INFO_INTERFACE_PLIP,    "16_plip.xpm",     "plip",       NULL },
73 	{ N_("Infrared Interface"),      INFO_INTERFACE_IRLAN,   "irda-16.png",     "irlan",      NULL },
74 	{ N_("Loopback Interface"),      INFO_INTERFACE_LO,      "16_loopback.xpm", "lo",         NULL },
75 	{ N_("Unknown Interface"),       INFO_INTERFACE_UNKNOWN, "network.png",     "",         NULL },
76 	{ NULL,                          INFO_INTERFACE_UNKNOWN,  NULL,             NULL,         NULL }
77 };
78 
79 void
info_do(const gchar * nic,Netinfo * info)80 info_do (const gchar * nic, Netinfo * info)
81 {
82 
83 }
84 
85 void
info_set_nic(Netinfo * netinfo,const gchar * nic)86 info_set_nic (Netinfo * netinfo, const gchar *nic)
87 {
88 	GtkTreeModel    *model;
89 	GtkTreeIter      iter;
90 
91 	g_return_if_fail (netinfo != NULL);
92 
93 	if (nic == NULL)
94 		return;
95 
96 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (netinfo->combo));
97 	if (!gtk_tree_model_get_iter_first (model, &iter)) {
98 		g_warning ("No network devices found.");
99 		return;
100 	}
101 
102 	do {
103 		char *text = NULL;
104 
105 		gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 2, &text, -1);
106 		if (!text)
107 			continue;
108 
109 		if (strcmp (text, nic) == 0) {
110 			gtk_combo_box_set_active_iter (GTK_COMBO_BOX (netinfo->combo), &iter);
111 			return;
112 		}
113 	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter));
114 }
115 
116 gchar *
info_get_nic(Netinfo * netinfo)117 info_get_nic (Netinfo * netinfo)
118 {
119 	GtkTreeModel    *model;
120 	GtkTreeIter      iter;
121 	gchar           *nic = NULL;
122 
123 	g_return_val_if_fail (netinfo != NULL, NULL);
124 
125 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (netinfo->combo));
126 
127 	if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (netinfo->combo), &iter))
128 		gtk_tree_model_get (model, &iter, 2, &nic, -1);
129 	else {
130 		g_warning ("No network devices found.");
131 		return NULL;
132 	}
133 
134 	return nic;
135 }
136 
137 static void
info_get_interface_from_dev_name(const gchar * dev_name,gchar ** iface,GdkPixbuf ** pixbuf)138 info_get_interface_from_dev_name (const gchar *dev_name, gchar **iface, GdkPixbuf **pixbuf)
139 {
140 	gint i;
141 	gchar *path;
142 	gchar *dev_type = NULL;
143 #if defined(__FreeBSD__)
144 	int s;
145 	struct ifmediareq ifmr;
146 
147 	if ((s = socket (AF_INET, SOCK_DGRAM, 0)) > -1) {
148 
149 		(void) memset (&ifmr, 0, sizeof (ifmr));
150 		(void) strncpy (ifmr.ifm_name, dev_name, sizeof (ifmr.ifm_name));
151 
152 		if (ioctl (s, SIOCGIFMEDIA, (caddr_t) &ifmr) > -1) {
153 			switch (IFM_TYPE (ifmr.ifm_active)) {
154 				case IFM_ETHER:
155 					dev_type = "eth";
156 					break;
157 				case IFM_IEEE80211:
158 					dev_type = "wlan";
159 					break;
160 			}
161 		}
162 		close (s);
163 	}
164 #endif /* defined(__FreeBSD__) */
165 
166 	if (!dev_type)
167 		dev_type = (gchar *) dev_name;
168 
169 	for (i = 0; info_iface_desc[i].name; i++)
170 		if (strstr (dev_type, info_iface_desc[i].prefix) == dev_type) {
171 			(*iface) = g_strdup_printf ("%s (%s)", _(info_iface_desc[i].name), dev_name);
172 			if (info_iface_desc[i].pixbuf == NULL) {
173 				path = g_build_filename (PIXMAPS_DIR, info_iface_desc[i].icon, NULL);
174 				info_iface_desc[i].pixbuf = gdk_pixbuf_new_from_file (path, NULL);
175 				g_free (path);
176 			}
177 			(*pixbuf) = info_iface_desc[i].pixbuf;
178 			return;
179 		}
180 }
181 
182 void
info_load_iface(Netinfo * info)183 info_load_iface (Netinfo *info)
184 {
185 	GtkTreeModel    *model;
186 	GtkTreeIter      iter;
187 	GtkCellRenderer *renderer;
188 	GList *items = NULL;
189 	GList *p;
190 	GdkPixbuf *pixbuf = NULL;
191 	gchar *iface = NULL;
192 	gchar *text;
193 
194 	items = info_get_interfaces (info);
195 	p = items;
196 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (info->combo));
197 
198 	if (!items) {
199 		iface = g_strdup_printf ("<i>%s</i>", _("Network Devices Not Found"));
200 
201 		gtk_list_store_append (GTK_LIST_STORE (model), &iter);
202 		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
203 				    0, NULL,
204 				    1, iface,
205 				    2, (gpointer) NULL,
206 				    -1);
207 
208 		g_free (iface);
209 	} else {
210 		while (p) {
211 			text = g_strdup (p->data);
212 
213 			info_get_interface_from_dev_name (text, &iface, &pixbuf);
214 
215 			gtk_list_store_append (GTK_LIST_STORE (model), &iter);
216 			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
217 					    0, pixbuf,
218 					    1, iface,
219 					    2, (gpointer) text,
220 					    -1);
221 
222 			g_free (iface);
223 			g_object_unref (pixbuf);
224 
225 			p = g_list_next (p);
226 		}
227 
228 		g_list_free (items);
229 	}
230 
231 	gtk_cell_layout_clear (GTK_CELL_LAYOUT (info->combo));
232 
233 	renderer = gtk_cell_renderer_pixbuf_new ();
234 	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (info->combo), renderer, TRUE);
235 	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (info->combo), renderer,
236 					"pixbuf", 0, NULL);
237 
238 	renderer = gtk_cell_renderer_text_new ();
239 	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (info->combo), renderer, TRUE);
240 	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (info->combo), renderer,
241 					"markup", 1, NULL);
242 
243 	gtk_combo_box_set_active (GTK_COMBO_BOX (info->combo), 0);
244 }
245 
246 static gboolean
info_nic_update_stats(gpointer data)247 info_nic_update_stats (gpointer data)
248 {
249 	Netinfo *info = data;
250 	gchar rx_pkt[10], rx_error[10];
251 	gchar tx_pkt[10], tx_error[10];
252 	gchar collisions[10];
253 	const gchar *nic;
254 	gchar *text_tx_bytes, *text_rx_bytes;
255 
256 	glibtop_netload netload;
257 
258 	g_return_val_if_fail (info != NULL, FALSE);
259 
260 	nic = info_get_nic (info);
261 	if (!nic)
262 		return FALSE;
263 
264 	glibtop_get_netload (&netload, nic);
265 
266 	text_rx_bytes = util_legible_bytes (netload.bytes_in);
267 	text_tx_bytes = util_legible_bytes (netload.bytes_out);
268 
269 	g_sprintf (rx_pkt, "%" G_GUINT64_FORMAT, netload.packets_in);
270 	g_sprintf (tx_pkt, "%" G_GUINT64_FORMAT, netload.packets_out);
271 
272 	g_sprintf (rx_error, "%" G_GUINT64_FORMAT, netload.errors_in);
273 	g_sprintf (tx_error, "%" G_GUINT64_FORMAT, netload.errors_out);
274 
275 	g_sprintf (collisions, "%" G_GUINT64_FORMAT, netload.collisions);
276 
277 	gtk_label_set_text (GTK_LABEL (info->tx_bytes), text_tx_bytes);
278 	gtk_label_set_text (GTK_LABEL (info->tx), tx_pkt);
279 	gtk_label_set_text (GTK_LABEL (info->tx_errors), tx_error);
280 	gtk_label_set_text (GTK_LABEL (info->rx_bytes), text_rx_bytes);
281 	gtk_label_set_text (GTK_LABEL (info->rx), rx_pkt);
282 	gtk_label_set_text (GTK_LABEL (info->rx_errors), rx_error);
283 	gtk_label_set_text (GTK_LABEL (info->collisions), collisions);
284 
285 	g_free (text_tx_bytes);
286 	g_free (text_rx_bytes);
287 
288 	return TRUE;
289 }
290 
291 void
info_nic_changed(GtkWidget * combo,gpointer data)292 info_nic_changed (GtkWidget *combo, gpointer data)
293 {
294 	gchar *text = NULL;
295 	Netinfo *info = data;
296 	GtkTreeModel *model;
297 
298 	static gint timeout_source = 0;
299 
300 	g_return_if_fail (info != NULL);
301 
302 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (info->list_ip_addr));
303 	if (model)
304 		gtk_list_store_clear (GTK_LIST_STORE (model));
305 
306 	text = info_get_nic (info);
307 	if (!text)
308 		return;
309 
310 	/* Fill the NIC configuration data */
311 	info_get_nic_information (text, info);
312 	info_nic_update_stats (info);
313 
314 	if (timeout_source > 0) {
315 		g_source_remove (timeout_source);
316 	}
317 
318 	timeout_source = g_timeout_add (DELAY_STATS, info_nic_update_stats, info);
319 }
320 
321 static gint
info_ip6_masklen(guint8 * netmask)322 info_ip6_masklen (guint8 *netmask)
323 {
324 	gint len = 0;
325 	guchar val;
326 	guchar *pnt;
327 
328 	pnt = (guchar *) netmask;
329 
330 	while ((*pnt == 0xff) && len < 128) {
331 		len += 8;
332 		pnt ++;
333 	}
334 
335 	if (len < 128) {
336 		val = *pnt;
337 		while (val) {
338 			len++;
339 			val <<= 1;
340 		}
341 	}
342 
343 	return len;
344 }
345 
346 typedef struct {
347 	   gchar *ip_addr;
348 	   gchar *ip_prefix;
349 	   gchar *ip_bcast;
350 	   gchar *ip_scope;
351 } InfoIpAddr;
352 
353 static void
info_ip_addr_free(InfoIpAddr * ip)354 info_ip_addr_free (InfoIpAddr *ip)
355 {
356 	g_free (ip->ip_addr);
357 	g_free (ip->ip_prefix);
358 	g_free (ip->ip_bcast);
359 	g_free (ip->ip_scope);
360 	g_free (ip);
361 }
362 
363 static void
info_setup_configure_button(Netinfo * info,gboolean enable)364 info_setup_configure_button (Netinfo *info, gboolean enable)
365 {
366 	gchar *network_tool_path;
367 
368 	network_tool_path = util_find_program_in_path ("nm-connection-editor", NULL);
369 	if (!network_tool_path)
370 		network_tool_path = util_find_program_in_path ("network-admin", NULL);
371 
372 	if (!network_tool_path)
373 		gtk_widget_hide (info->configure_button);
374 	else {
375 		gtk_widget_show (info->configure_button);
376 		gtk_widget_set_sensitive (info->configure_button, enable);
377 
378 		g_free (network_tool_path);
379 	}
380 }
381 
382 void
info_get_nic_information(const gchar * nic,Netinfo * info)383 info_get_nic_information (const gchar *nic, Netinfo *info)
384 {
385 	GtkTreeModel *model;
386 	GtkTreeIter   iter;
387 	gchar *dst;
388 	InfoIpAddr *ip;
389 	gint prefix;
390 	struct in_addr addr, subnet;
391 	gchar *address_string, *subnet_string;
392 	gchar address6_string[INET6_ADDRSTRLEN];
393 	glibtop_netload netload;
394 #ifdef __linux__
395 	mii_data_result data;
396 #endif
397 
398 	gtk_label_set_text (GTK_LABEL (info->hw_address), NOT_AVAILABLE);
399 	gtk_label_set_text (GTK_LABEL (info->mtu), NOT_AVAILABLE);
400 	gtk_label_set_text (GTK_LABEL (info->state), NOT_AVAILABLE);
401 	gtk_label_set_text (GTK_LABEL (info->multicast), NOT_AVAILABLE);
402 	gtk_label_set_text (GTK_LABEL (info->link_speed), NOT_AVAILABLE);
403 
404 	glibtop_get_netload (&netload, nic);
405 
406 	/* IPv6 */
407 	/* FIXME: It shows only one IPv6 address. Bug #563768 */
408 	inet_ntop (AF_INET6, netload.address6, address6_string, INET6_ADDRSTRLEN);
409 	prefix = info_ip6_masklen (netload.prefix6);
410 
411 	ip = g_new0 (InfoIpAddr, 1);
412 	ip->ip_addr = g_strdup (address6_string);
413 	ip->ip_prefix = g_strdup_printf ("%d", prefix);
414 	ip->ip_bcast = g_strdup ("");
415 
416 	switch (netload.scope6) {
417 		case GLIBTOP_IF_IN6_SCOPE_LINK:
418 			ip->ip_scope = g_strdup ("Link");
419 			break;
420 		case GLIBTOP_IF_IN6_SCOPE_SITE:
421 			ip->ip_scope = g_strdup ("Site");
422 			break;
423 		case GLIBTOP_IF_IN6_SCOPE_GLOBAL:
424 			ip->ip_scope = g_strdup ("Global");
425 			break;
426 		case GLIBTOP_IF_IN6_SCOPE_HOST:
427 			ip->ip_scope = g_strdup ("Host");
428 			break;
429 		case GLIBTOP_IF_IN6_SCOPE_UNKNOWN:
430 			ip->ip_scope = g_strdup (_("Unknown"));
431 			break;
432 		default:
433 			ip->ip_scope = g_strdup (_("Unknown"));
434 			break;
435 	}
436 
437 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (info->list_ip_addr));
438 
439 	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
440 	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
441 					    0, "IPv6",
442 					    1, ip->ip_addr,
443 					    2, ip->ip_prefix,
444 					    3, ip->ip_bcast,
445 					    4, ip->ip_scope,
446 					    -1);
447 	info_ip_addr_free (ip);
448 
449 	/* IPv4 */
450 	addr.s_addr = netload.address;
451 	subnet.s_addr = netload.subnet;
452 
453 	address_string = g_strdup (inet_ntoa (addr));
454 	subnet_string  = g_strdup (inet_ntoa (subnet));
455 
456 	ip = g_new0 (InfoIpAddr, 1);
457 	ip->ip_addr = g_strdup (address_string);
458 	ip->ip_prefix = g_strdup (subnet_string);
459 	/* FIXME: Get the broadcast address: Bug #563765 */
460 	ip->ip_bcast = g_strdup ("");
461 
462 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (info->list_ip_addr));
463 
464 	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
465 	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
466 					    0, "IPv4",
467 					    1, ip->ip_addr,
468 					    2, ip->ip_prefix,
469 					    3, ip->ip_bcast,
470 					    4, "",
471 					    -1);
472 
473 	g_free (address_string);
474 	g_free (subnet_string);
475 	info_ip_addr_free (ip);
476 
477 
478 	/* Get general information about the interface */
479 
480 	/* Get the Hardware Address */
481 	if (netload.flags & (1L << GLIBTOP_NETLOAD_HWADDRESS)) {
482 		dst = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x",
483 			   (int) ((guchar *) &netload.hwaddress)[0],
484 			   (int) ((guchar *) &netload.hwaddress)[1],
485 			   (int) ((guchar *) &netload.hwaddress)[2],
486 			   (int) ((guchar *) &netload.hwaddress)[3],
487 			   (int) ((guchar *) &netload.hwaddress)[4],
488 			   (int) ((guchar *) &netload.hwaddress)[5]);
489 	} else {
490 		dst = g_strdup_printf ("%s", NOT_AVAILABLE);
491 	}
492 	gtk_label_set_text (GTK_LABEL (info->hw_address), dst);
493 	g_free (dst);
494 
495 	/* Get the interface's Maximum Transfer Unit */
496 	dst = g_strdup_printf ("%d", netload.mtu);
497 	gtk_label_set_text (GTK_LABEL (info->mtu), dst);
498 	g_free (dst);
499 
500 
501 	/* Get Flags to determine other properties */
502 
503 	/* Is the interface up? */
504 	if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_UP)) {
505 		gtk_label_set_text (GTK_LABEL (info->state), _("Active"));
506 	} else {
507 		gtk_label_set_text (GTK_LABEL (info->state), _("Inactive"));
508 	}
509 
510 	/* Is this a loopback device? */
511 	if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_LOOPBACK)) {
512 		dst = g_strdup_printf ("%s", _("Loopback"));
513 		gtk_label_set_text (GTK_LABEL (info->hw_address), dst);
514 		g_free (dst);
515 		ip->ip_bcast = g_strdup ("");
516 		info_setup_configure_button (info, FALSE);
517 	} else {
518 		info_setup_configure_button (info, TRUE);
519 	}
520 
521 	/* Does this interface supports multicast? */
522 	if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_MULTICAST)) {
523 		gtk_label_set_text (GTK_LABEL (info->multicast), _("Enabled"));
524 	} else {
525 		gtk_label_set_text (GTK_LABEL (info->multicast), _("Disabled"));
526 	}
527 
528 	/* Get the Point-To-Point address if any */
529 	/* FIXME: Bug #563767 */
530 
531 	/* Get the link negotiation speed.  Only available on Linux
532 	 * systems, and lately only for with super user privileges
533 	 * See Bug #387198 */
534 #ifdef __linux__
535 	data = mii_get_basic (nic);
536 	if (data.has_data) {
537 		gtk_label_set_text (GTK_LABEL (info->link_speed), data.media);
538 	}
539 #else
540 	gtk_label_set_text (GTK_LABEL (info->link_speed), NOT_AVAILABLE);
541 #endif
542 }
543 
544 static gint *
compare(gconstpointer a,gconstpointer b)545 compare (gconstpointer a, gconstpointer b)
546 {
547 	return (GINT_TO_POINTER (strcmp (a, b)));
548 }
549 
550 static GList *
info_get_interfaces(Netinfo * info)551 info_get_interfaces (Netinfo *info)
552 {
553 	GList *items = NULL;
554 	glibtop_netlist netlist;
555 	gchar **devices;
556 	gchar *iface;
557 	guint i;
558 
559 	devices = glibtop_get_netlist(&netlist);
560 
561 	for(i = 0; i < netlist.number; ++i) {
562 		iface = g_strdup (devices[i]);
563 		if (g_list_find_custom (items, iface,
564 					           (GCompareFunc) compare) == NULL) {
565 			items = g_list_append (items, iface);
566 		}
567 	}
568 
569 	g_strfreev(devices);
570 
571 	return items;
572 }
573 
574 /* Copy on clipboard */
575 void
info_copy_to_clipboard(Netinfo * netinfo,gpointer user_data)576 info_copy_to_clipboard (Netinfo * netinfo, gpointer user_data)
577 {
578 	GString *result;
579 	const gchar *nic;
580 	const gchar *hw_address;
581 	const gchar *multicast;
582 	const gchar *link_speed;
583 	const gchar *state;
584 	const gchar *mtu;
585 	const gchar *tx;
586 	const gchar *tx_errors;
587 	const gchar *rx;
588 	const gchar *rx_errors;
589 	const gchar *collisions;
590 
591 	g_return_if_fail (netinfo != NULL);
592 
593 	/* The info output in text format:
594 	   Bytes received, Address Source, Number of Sequence,
595 	   Round Trip Time (Time), Units of Time.
596 	   It's a tabular output, and these belongs to the column titles */
597 	result = g_string_new ("");
598 
599 	nic = info_get_nic (netinfo);
600 
601 	hw_address = gtk_label_get_text (GTK_LABEL (netinfo->hw_address));
602 	multicast = gtk_label_get_text (GTK_LABEL (netinfo->multicast));
603 	mtu = gtk_label_get_text (GTK_LABEL (netinfo->mtu));
604 	link_speed = gtk_label_get_text (GTK_LABEL (netinfo->link_speed));
605 	state = gtk_label_get_text (GTK_LABEL (netinfo->state));
606 
607 	tx = gtk_label_get_text (GTK_LABEL (netinfo->tx));
608 	rx = gtk_label_get_text (GTK_LABEL (netinfo->rx));
609 	tx_errors = gtk_label_get_text (GTK_LABEL (netinfo->tx_errors));
610 	rx_errors = gtk_label_get_text (GTK_LABEL (netinfo->rx_errors));
611 	collisions = gtk_label_get_text (GTK_LABEL (netinfo->collisions));
612 
613 	/* The info output in a text format (to copy on clipboard) */
614 	g_string_append_printf (result, _("Network device:\t%s\n"), nic);
615 	g_string_append_printf (result, _("Hardware address:\t%s\n"), hw_address);
616 	g_string_append_printf (result, _("Multicast:\t%s\n"), multicast);
617 	g_string_append_printf (result, _("MTU:\t%s\n"), mtu);
618 	g_string_append_printf (result, _("Link speed:\t%s\n"), link_speed);
619 	g_string_append_printf (result, _("State:\t%s\n"), state);
620 
621 	g_string_append_printf (result, _("Transmitted packets:\t%s\n"), tx);
622 	g_string_append_printf (result, _("Transmission errors:\t%s\n"), tx_errors);
623 	g_string_append_printf (result, _("Received packets:\t%s\n"), rx);
624 	g_string_append_printf (result, _("Reception errors:\t%s\n"), rx_errors);
625 	g_string_append_printf (result, _("Collisions:\t%s\n"), collisions);
626 
627 
628 	gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), result->str,
629 				result->len);
630 
631 	g_string_free (result, TRUE);
632 }
633