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 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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <strings.h>
25 #include <gtk/gtk.h>
26 #include <glib/gi18n.h>
27 #include "netstat.h"
28 #include "utils.h"
29 
30 static gint strip_protocol_line (gchar * line, netstat_protocol_data *data);
31 void netstat_create_protocol_model (GtkTreeView *widget);
32 void netstat_protocol_tree_insert (GtkTreeView *widget, gchar *line);
33 
34 static gint strip_route_line (gchar * line, netstat_route_data *data);
35 void netstat_route_tree_insert (GtkTreeView *widget, gchar *line);
36 void netstat_create_route_model (GtkTreeView *widget);
37 
38 void netstat_multicast_tree_insert (GtkTreeView *widget, gchar *line);
39 static gint strip_multicast_line (gchar * line, netstat_multicast_data *data);
40 void netstat_create_multicast_model (GtkTreeView *widget);
41 
42 static NetstatOption netstat_get_active_option2 (Netinfo * netinfo);
43 static gchar * netstat_get_active_option (Netinfo * netinfo);
44 
45 static GtkTreeModel *protocol_model, *route_model, *multicast_model;
46 
47 void clean_gtk_tree_view (GtkTreeView *widget);
48 
49 /* Check the ToggleButton active to show the GtkTreeView with
50  * the right GtkTreeModel
51  */
52 void
on_protocol_button_toggled(GtkToggleButton * togglebutton,gpointer user_data)53 on_protocol_button_toggled (GtkToggleButton *togglebutton, gpointer user_data)
54 {
55 	Netinfo *netinfo = user_data;
56 	/* GtkWidget *parent, *child, *widget; */
57 
58 	g_return_if_fail (GTK_IS_TREE_VIEW (netinfo->output));
59 
60 	/*
61 	widget = GTK_TREE_VIEW (netinfo->output);
62 
63 	parent = gtk_widget_get_parent (GTK_WIDGET (widget));
64 	g_print ("name: %s\n", gtk_widget_get_name (parent));
65 	child = gtk_bin_get_child (GTK_BIN (parent));
66 
67 	g_object_ref (child);
68 
69 	gtk_container_remove (GTK_CONTAINER (parent), child);
70 	*/
71 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->routing))) {
72 		g_print ("routing set\n");
73 		/*gtk_container_add (GTK_CONTAINER (parent), route_tree);
74 		gtk_tree_view_set_model (widget, route_model); */
75 	}
76 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->protocol))) {
77 		g_print ("protocol\n");
78 		/* gtk_container_add (GTK_CONTAINER (parent), protocol_tree);
79 		gtk_tree_view_set_model (widget, protocol_model); */
80 	}
81 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->multicast))) {
82 		g_print ("multicast\n");
83 		/* gtk_container_add (GTK_CONTAINER (parent), multicast_tree);
84 		gtk_tree_view_set_model (widget, multicast_model); */
85 	}
86 
87 	/* g_object_unref (child); */
88 }
89 
90 static NetstatOption
netstat_get_active_option2(Netinfo * netinfo)91 netstat_get_active_option2 (Netinfo * netinfo)
92 {
93 	NetstatOption option = NONE;
94 
95 	g_return_val_if_fail (netinfo != NULL, ROUTE);
96 
97 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->routing))) {
98 		option = ROUTE;
99 	}
100 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->protocol))) {
101 		option = PROTOCOL;
102 	}
103 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->multicast))) {
104 		option = MULTICAST;
105 	}
106 	return option;
107 }
108 
109 static gchar *
netstat_get_active_option(Netinfo * netinfo)110 netstat_get_active_option (Netinfo * netinfo)
111 {
112 	gchar *option = NULL;
113 
114 	g_return_val_if_fail (netinfo != NULL, NULL);
115 
116 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->routing))) {
117 #if defined (__OpenBSD__) || defined (__FreeBSD__)
118 		if (netinfo_is_ipv6_enable ()) {
119 			option = g_strdup ("-rn");
120 		} else {
121 			option = g_strdup ("-rn -f inet");
122 		}
123 #else
124 		/* Works for Solaris and Linux */
125 		if (netinfo_is_ipv6_enable ()) {
126 			option = g_strdup ("-rn -A inet -A inet6");
127 		} else {
128 			option = g_strdup ("-rn -A inet");
129 		}
130 #endif
131 
132 		if (netinfo->stbar_text)
133 			g_free (netinfo->stbar_text);
134 		netinfo->stbar_text = g_strdup (_("Getting routing table"));
135 	}
136 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->protocol))) {
137 		/* Only works for Solaris */
138 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
139 	    	option = g_strdup ("-a -f inet -ln");
140 #else
141 		if (netinfo_is_ipv6_enable ()) {
142 			option = g_strdup ("-A inet -A inet6 -ln");
143 		} else {
144 			option = g_strdup ("-A inet -ln");
145 		}
146 
147 		if (netinfo->stbar_text)
148 			g_free (netinfo->stbar_text);
149 		netinfo->stbar_text = g_strdup (_("Getting active Internet connections"));
150 #endif
151 	}
152 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (netinfo->multicast))) {
153 		/* It works for Solaris and Linux */
154 		option = g_strdup ("-g");
155 
156 		if (netinfo->stbar_text)
157 			g_free (netinfo->stbar_text);
158 		netinfo->stbar_text = g_strdup (_("Getting group memberships"));
159 	}
160 	return option;
161 }
162 
163 void
netstat_stop(Netinfo * netinfo)164 netstat_stop (Netinfo * netinfo)
165 {
166 	g_return_if_fail (netinfo != NULL);
167 
168 	netinfo_stop_process_command (netinfo);
169 }
170 
171 void
netstat_do(Netinfo * netinfo)172 netstat_do (Netinfo * netinfo)
173 {
174 	gboolean toggle;
175 	gchar *command = NULL;
176 	gchar *option = NULL;
177 	gchar *program = NULL;
178 	GtkTreeModel *model;
179 	GtkWidget *parent;
180 	NetstatOption noption;
181 
182 	g_return_if_fail (netinfo != NULL);
183 
184 	toggle = netinfo->toggle;
185 	option = netstat_get_active_option (netinfo);
186 	noption = netstat_get_active_option2 (netinfo);
187 
188 	if (noption == ROUTE || noption == PROTOCOL) {
189 		netinfo->toggle = FALSE;
190 	}
191 
192 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (netinfo->output));
193 	if (GTK_IS_LIST_STORE (model)) {
194 		gtk_list_store_clear (GTK_LIST_STORE (model));
195 	}
196 
197 	parent = gtk_widget_get_toplevel (netinfo->output);
198 
199 	program = util_find_program_dialog ("netstat", parent);
200 
201 	if (program != NULL) {
202 		command =
203 			g_strdup_printf ("%s netstat %s", program, option);
204 
205 		g_strfreev (netinfo->command_line);
206 		netinfo->command_line = g_strsplit (command, " ", -1);
207 
208 		netinfo_process_command (netinfo);
209 	}
210 
211 	/* Restore previous state */
212 	netinfo->toggle = toggle;
213 
214 	g_free (command);
215 	g_free (option);
216 	g_free (program);
217 }
218 
219 /* Process each line from netstat command */
220 void
netstat_foreach(Netinfo * netinfo,gchar * line,gsize len,gpointer user_data)221 netstat_foreach (Netinfo * netinfo, gchar * line, gsize len, gpointer user_data)
222 {
223 	gchar *text_utf8;
224 	gsize bytes_written;
225 	GtkTextBuffer *buffer = NULL;
226 	GtkTextIter iter;
227 
228 	g_return_if_fail (netinfo != NULL);
229 	/*g_return_if_fail (line != NULL);*/
230 
231 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (netinfo->output));
232 	gtk_text_buffer_get_end_iter (buffer, &iter);
233 
234 #ifdef DEBUG
235 	if (netstat_get_active_option2 (netinfo) == PROTOCOL) {
236 		netstat_protocol_data data;
237 		gint count;
238 
239 		count = strip_protocol_line (line, &data);
240 		if (count == 7 || count == 8) {
241 
242 			g_print ("%s\t%s:%s\t%s\n", data.protocol,
243 				data.ip_src, data.port_src, data.state);
244 		}
245 	}
246 #endif /* DEBUG */
247 
248 	if (len > 0) {
249 		text_utf8 = g_locale_to_utf8 (line, len,
250 						  NULL, &bytes_written,
251 						  NULL);
252 
253 		gtk_text_buffer_insert
254 			(GTK_TEXT_BUFFER (buffer), &iter, text_utf8,
255 			 bytes_written);
256 		g_free (text_utf8);
257 	}
258 }
259 
260 /* Collect data from netstat command and insert them in a GtkTreeView.
261 
262    Basically it consist on receive each line, divide it in fields
263    and insert each value in a tree if belong.  The function strip_line
264    divide the lines and return the number of fields.  To distinguish
265    header and data from the output is useful to know then right number
266    of fields.
267 
268    It could be avoid with a helper with two options: with/without
269    headers.  To execute on a shell or just to process its output as
270    this program.
271 */
272 void
netstat_foreach_with_tree(Netinfo * netinfo,gchar * line,gint len,gpointer user_data)273 netstat_foreach_with_tree (Netinfo * netinfo, gchar * line, gint len,
274 			   gpointer user_data)
275 {
276 	GtkTreeView *widget;
277 
278 	g_return_if_fail (netinfo != NULL);
279 
280 	widget = (GTK_TREE_VIEW (netinfo->output));
281 
282 	if (len > 0) {		/* there are data to show */
283 		g_return_if_fail (line != NULL);
284 		switch (netstat_get_active_option2 (netinfo)) {
285 		case PROTOCOL:
286 			netstat_protocol_tree_insert (widget, line);
287 			break;
288 		case ROUTE:
289 			netstat_route_tree_insert (widget, line);
290 			break;
291 		case MULTICAST:
292 			netstat_multicast_tree_insert (widget, line);
293 			break;
294 		case NONE:
295 		default:
296 			break;
297 		}
298 	}
299 }
300 
301 /* PROTOCOL */
302 void
netstat_protocol_tree_insert(GtkTreeView * widget,gchar * line)303 netstat_protocol_tree_insert (GtkTreeView *widget, gchar *line)
304 {
305 	GtkTreeIter iter, sibling;
306 	/*GList *columns;*/
307 	GtkTreePath *path;
308 	GtkTreeModel *model;
309 	gint count;
310 	netstat_protocol_data data;
311 
312 	g_return_if_fail (GTK_IS_TREE_VIEW (widget));
313 	g_return_if_fail (line != NULL);
314 
315 	count = strip_protocol_line (line, &data);
316 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
317 	if (count == 5 || count == 6 || count == 9 || count == 10) {
318 #else
319 	if (count == 5 || count == 6) {
320 #endif
321 #ifdef DEBUG
322 		g_print ("%s\t%s:%s\t%s\n", data.protocol,
323 			data.ip_src, data.port_src, data.state);
324 #endif /* DEBUG */
325 
326 		/* Creation of GtkTreeView */
327 		gtk_tree_view_set_rules_hint (widget, TRUE);
328 /*		columns = gtk_tree_view_get_columns (widget);
329 
330 		if (g_list_length (columns) == 0) {
331 			model = netstat_create_protocol_model (widget);
332 			gtk_tree_view_set_model (widget, model);
333 		}
334 		g_list_free (columns);*/
335 
336 		model = gtk_tree_view_get_model (widget);
337 
338 		if (protocol_model == NULL || protocol_model != model) {
339 			clean_gtk_tree_view (widget);
340 
341 			protocol_model = GTK_TREE_MODEL (gtk_list_store_new
342 						(4,
343 						 G_TYPE_STRING,
344 						 G_TYPE_STRING,
345 						 G_TYPE_STRING,
346 						 G_TYPE_STRING));
347 			netstat_create_protocol_model (widget);
348 
349 			gtk_tree_view_set_model (widget, protocol_model);
350 		}
351 
352 		model = gtk_tree_view_get_model (widget);
353 
354 		gtk_tree_view_get_cursor (widget, &path, NULL);
355 
356 		if (path != NULL) {
357 			gtk_tree_model_get_iter (model, &sibling, path);
358 			gtk_list_store_insert_after (GTK_LIST_STORE
359 							 (model),
360 							 &iter,
361 							 &sibling);
362 		} else {
363 			gtk_list_store_append (GTK_LIST_STORE
364 						   (model), &iter);
365 		}
366 
367 		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
368 					0, data.protocol,
369 					1, data.ip_src,
370 					2, data.port_src,
371 					3, data.state, -1);
372 
373 		gtk_tree_view_set_model (widget, model);
374 		path = gtk_tree_model_get_path (model, &iter);
375 		gtk_tree_view_set_cursor (widget, path, NULL, FALSE);
376 		gtk_tree_path_free (path);
377 	}
378 }
379 
380 static gint
381 strip_protocol_line (gchar * line, netstat_protocol_data *data)
382 {
383 	gint count = 0;
384 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
385 	gint a1, a2, a3, a4;
386 	gchar s9[30];
387 #else
388 	gchar s6[30], laddr[50];
389 	gchar *port;
390 #endif
391 	gint n2, n3;
392 
393 	/*line = g_strdelimit (line, ":", ' ');*/
394 
395 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
396 	line = g_strdelimit (line, ":", ' ');
397 
398 	count = sscanf (line, NETSTAT_PROTOCOL_FORMAT,
399 			data->protocol, &n2, &n3,
400 			&a1, &a2, &a3, &a4, data->port_src,
401 			s9, data->state);
402 	g_snprintf (data->ip_src, 30, "%d.%d.%d.%d", a1, a2, a3, a4);
403 
404 	if (count == 9) {
405 	    bzero (&(data)->state, 30);
406 	}
407 
408 	if (count == 3) {
409 	    /* Handle the *.* entries. */
410 	    gchar s5[30];
411 	    count = sscanf (line, ALT_NETSTAT_PROTOCOL_FORMAT,
412 		    	    data->protocol, &n2, &n3,
413 			    data->port_src, s5,
414 			    data->state);
415 	    g_snprintf (data->ip_src, 30, "*");
416 
417 	    if (count == 5) {
418 		bzero (&(data)->state, 30);
419 	    }
420 	}
421 
422 #else
423 	/*count = sscanf (line, NETSTAT_PROTOCOL_FORMAT,
424 			data->protocol, &n2, &n3,
425 			data->ip_src, data->port_src,
426 			s6, s7, data->state);
427 
428 	if (count == 7) {
429 		bzero (&(data)->state, 30);
430 		}*/
431 	count = sscanf (line, NETSTAT_PROTOCOL_FORMAT,
432 			data->protocol, &n2, &n3,
433 			laddr, s6, data->state);
434 
435 	port = g_strrstr (laddr, ":");
436 
437 	if (port != NULL) {
438 		g_strlcpy (data->ip_src, laddr, 50 * sizeof (gchar));
439 		data->ip_src[strlen (laddr) - strlen (port)] = '\0';
440 		port ++;
441 		g_strlcpy (data->port_src, port, 30 * sizeof (gchar));
442 	}
443 
444 	if (count == 5) {
445 		bzero (&(data)->state, 30);
446 	}
447 #endif
448 
449 	return count;
450 }
451 
452 void
453 netstat_create_protocol_model (GtkTreeView *widget)
454 {
455 	GtkCellRenderer *renderer;
456 	GtkTreeViewColumn *column;
457 
458 	/*clean_gtk_tree_view (widget);*/
459 
460 	renderer = gtk_cell_renderer_text_new ();
461 	/* Transport Protocol that runs over */
462 	column =
463 	    gtk_tree_view_column_new_with_attributes
464 	    (_("Protocol"), renderer, "text", 0, NULL);
465 	gtk_tree_view_append_column (widget, column);
466 
467 	renderer = gtk_cell_renderer_text_new ();
468 	/* IP address where to accept connections */
469 	column =
470 	    gtk_tree_view_column_new_with_attributes
471 	    (_("IP Source"), renderer, "text", 1, NULL);
472 	gtk_tree_view_column_set_alignment (column, 0.5);
473 	gtk_tree_view_append_column (widget, column);
474 
475 	renderer = gtk_cell_renderer_text_new ();
476 	/* Number of port where the service is listening */
477 	column =
478 	    gtk_tree_view_column_new_with_attributes
479 	    (_("Port/Service"), renderer, "text", 2, NULL);
480 	g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL);
481 	gtk_tree_view_append_column (widget, column);
482 
483 	renderer = gtk_cell_renderer_text_new ();
484 	/* State of the service (commonly LISTEN) */
485 	column =
486 	    gtk_tree_view_column_new_with_attributes
487 	    (_("State"), renderer, "text", 3, NULL);
488 	gtk_tree_view_append_column (widget, column);
489 
490 	/* return model;*/
491 }
492 /* END PROTOCOL */
493 
494 /* ROUTE */
495 void
496 netstat_route_tree_insert (GtkTreeView *widget, gchar *line)
497 {
498 	GtkTreeIter iter, sibling;
499 	/*GList *columns;*/
500 	GtkTreePath *path;
501 	GtkTreeModel *model;
502 	gint count;
503 	netstat_route_data data;
504 
505 	g_return_if_fail (GTK_IS_TREE_VIEW (widget));
506 	g_return_if_fail (line != NULL);
507 
508 	count = strip_route_line (line, &data);
509 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
510 	if (count == 6) {
511 #elif defined(__OpenBSD__)
512 	if (count == 8) {
513 #else
514 	if ((count == 8) || (count == 7)) {
515 #endif
516 #ifdef DEBUG
517 		g_print ("%s\t%s:%s\t%d\t%s\n", data.destination,
518 			data.gateway, data.netmask, data.metric,
519 			data.iface);
520 #endif /* DEBUG */
521 
522 		/* Creation of GtkTreeView */
523 		gtk_tree_view_set_rules_hint (widget, TRUE);
524 /*		columns = gtk_tree_view_get_columns (widget);
525 
526 		if (g_list_length (columns) == 0) {
527 			model = netstat_create_route_model (widget);
528 			gtk_tree_view_set_model (widget, model);
529 		}
530 		g_list_free (columns);*/
531 
532 		model = gtk_tree_view_get_model (widget);
533 
534 		if (route_model == NULL || route_model != model) {
535 			clean_gtk_tree_view (widget);
536 
537 			route_model = GTK_TREE_MODEL (gtk_list_store_new
538 				(4,
539 				 G_TYPE_STRING,
540 				 G_TYPE_STRING,
541 				 G_TYPE_STRING,
542 				 G_TYPE_STRING));
543 			netstat_create_route_model (widget);
544 
545 			gtk_tree_view_set_model (widget, route_model);
546 		}
547 
548 		model = gtk_tree_view_get_model (widget);
549 
550 		gtk_tree_view_get_cursor (widget, &path, NULL);
551 
552 		if (path != NULL) {
553 			gtk_tree_model_get_iter (model, &sibling, path);
554 			gtk_list_store_insert_after (GTK_LIST_STORE
555 							 (model),
556 							 &iter,
557 							 &sibling);
558 			gtk_tree_path_free (path);
559 		} else {
560 			gtk_list_store_append (GTK_LIST_STORE
561 						   (model), &iter);
562 		}
563 
564 		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
565 					0, data.destination,
566 					1, data.gateway,
567 					2, data.netmask,
568 					3, data.iface, -1);
569 
570 		gtk_tree_view_set_model (widget, model);
571 		path = gtk_tree_model_get_path (model, &iter);
572 		gtk_tree_view_set_cursor (widget, path, NULL, FALSE);
573 		gtk_tree_path_free (path);
574 	}
575 }
576 
577 static gint
578 strip_route_line (gchar * line, netstat_route_data *data)
579 {
580 	gint count = 0;
581 	gchar flags[30];
582 	gint ref, use;
583 #if !defined (__FreeBSD__) && !defined(__OpenBSD__)
584 	gchar dest[50];
585 	gchar **items;
586 #endif
587 #if defined(__OpenBSD__)
588 	gint mtu, prio;
589 #endif
590 
591 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
592 	count = sscanf (line, NETSTAT_ROUTE_FORMAT,
593 			data->destination,
594 			data->gateway, flags,
595 			&ref, &use, data->iface);
596 #elif defined(__OpenBSD__)
597 	count = sscanf (line, NETSTAT_ROUTE_FORMAT,
598 			data->destination,
599 			data->gateway, flags,
600 			&ref, &use, &mtu, &prio,
601 			data->iface);
602 #else
603 	count = sscanf (line, NETSTAT_ROUTE_FORMAT,
604 			data->destination,
605 			data->gateway, data->netmask,
606 			flags, &(data)->metric, &ref, &use,
607 			data->iface);
608 
609 	if (count == 6) {
610 		count = sscanf (line, NETSTAT_ROUTE6_FORMAT,
611 				dest, data->netmask,
612 				flags, &(data)->metric,
613 				&ref, &use, data->iface);
614 
615 		items = NULL;
616 
617 		items = g_strsplit (dest, "/", 2);
618 		if (items != NULL) {
619 			g_strlcpy (data->destination, items[0], 50 * sizeof (gchar));
620 			g_strlcpy (data->netmask, items[1], 50 * sizeof (gchar));
621 
622 			g_strfreev (items);
623 		}
624 	}
625 
626 #endif
627 	return count;
628 }
629 
630 void
631 netstat_create_route_model (GtkTreeView *widget)
632 {
633 	GtkCellRenderer *renderer;
634 	GtkTreeViewColumn *column;
635 
636 	renderer = gtk_cell_renderer_text_new ();
637 	column =
638 	    gtk_tree_view_column_new_with_attributes
639 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
640 	    (_("Destination/Prefix"), renderer, "text", 0, NULL);
641 #else
642 	    (_("Destination"), renderer, "text", 0, NULL);
643 #endif
644 	gtk_tree_view_append_column (widget, column);
645 
646 	renderer = gtk_cell_renderer_text_new ();
647 	column =
648 	    gtk_tree_view_column_new_with_attributes
649 	    (_("Gateway"), renderer, "text", 1, NULL);
650 	gtk_tree_view_column_set_alignment (column, 0.5);
651 	gtk_tree_view_append_column (widget, column);
652 
653 #if ! (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)) || defined(__NetBSD__) || defined(__DragonFly__)
654 	renderer = gtk_cell_renderer_text_new ();
655 	column =
656 	    gtk_tree_view_column_new_with_attributes
657 	    (_("Netmask"), renderer, "text", 2, NULL);
658 
659 	gtk_tree_view_append_column (widget, column);
660 #endif
661 
662 	renderer = gtk_cell_renderer_text_new ();
663 	column =
664 	    gtk_tree_view_column_new_with_attributes
665 	    (_("Interface"), renderer, "text", 3, NULL);
666 	gtk_tree_view_append_column (widget, column);
667 }
668 /* END ROUTE */
669 
670 /* MULTICAST */
671 void
672 netstat_multicast_tree_insert (GtkTreeView *widget, gchar *line)
673 {
674 	GtkTreeIter iter, sibling;
675 	GtkTreePath *path;
676 	GtkTreeModel *model;
677 	gint count;
678 	netstat_multicast_data data;
679 
680 	g_return_if_fail (GTK_IS_TREE_VIEW (widget));
681 	g_return_if_fail (line != NULL);
682 
683 	count = strip_multicast_line (line, &data);
684 
685 	if (count == 3) {
686 #ifdef DEBUG
687 		g_print ("%s\t%s\t%s\n", data.iface,
688 			data.members, data.group);
689 #endif /* DEBUG */
690 
691 		/* Creation of GtkTreeView */
692 
693 		/*columns = gtk_tree_view_get_columns (widget);
694 
695 		if (g_list_length (columns) == 0) {
696 			model = netstat_create_multicast_model (widget);
697 			gtk_tree_view_set_model (widget, model);
698 		}
699 		g_list_free (columns);*/
700 
701 		model = gtk_tree_view_get_model (widget);
702 
703 		if (multicast_model == NULL || multicast_model != model) {
704 			clean_gtk_tree_view (widget);
705 
706 			multicast_model = GTK_TREE_MODEL (gtk_list_store_new
707 						(3,
708 						 G_TYPE_STRING,
709 						 G_TYPE_STRING,
710 						 G_TYPE_STRING));
711 			netstat_create_multicast_model (widget);
712 
713 			gtk_tree_view_set_model (widget, multicast_model);
714 		}
715 
716 		model = gtk_tree_view_get_model (widget);
717 
718 		gtk_tree_view_set_rules_hint (widget, TRUE);
719 
720 		gtk_tree_view_get_cursor (widget, &path, NULL);
721 
722 		if (path != NULL) {
723 			gtk_tree_model_get_iter (model, &sibling, path);
724 			gtk_list_store_insert_after (GTK_LIST_STORE
725 							 (model),
726 							 &iter,
727 							 &sibling);
728 			gtk_tree_path_free (path);
729 		} else {
730 			gtk_list_store_append (GTK_LIST_STORE
731 						   (model), &iter);
732 		}
733 
734 		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
735 					0, data.iface,
736 					1, data.members,
737 					2, data.group, -1);
738 
739 		gtk_tree_view_set_model (widget, model);
740 		path = gtk_tree_model_get_path (model, &iter);
741 		gtk_tree_view_set_cursor (widget, path, NULL, FALSE);
742 		gtk_tree_path_free (path);
743 	}
744 }
745 
746 static gint
747 strip_multicast_line (gchar * line, netstat_multicast_data *data)
748 {
749 	gint count = 0;
750 	gint members;
751 
752 	count = sscanf (line, NETSTAT_MULTICAST_FORMAT,
753 			data->iface,
754 			&members, data->group);
755 
756 	g_snprintf ((data)->members, 30, "%d", members);
757 
758 	return count;
759 }
760 
761 void
762 netstat_create_multicast_model (GtkTreeView *widget)
763 {
764 	GtkCellRenderer *renderer;
765 	GtkTreeViewColumn *column;
766 
767 	renderer = gtk_cell_renderer_text_new ();
768 	/* Interface of multicast group associated */
769 	column =
770 	    gtk_tree_view_column_new_with_attributes
771 	    (_("Interface"), renderer, "text", 0, NULL);
772 	gtk_tree_view_append_column (widget, column);
773 
774 	renderer = gtk_cell_renderer_text_new ();
775 	/* Members of multicast group */
776 	column =
777 	    gtk_tree_view_column_new_with_attributes
778 	    (_("Member"), renderer, "text", 1, NULL);
779 	g_object_set (G_OBJECT (renderer), "xalign", 0.5, NULL);
780 	gtk_tree_view_append_column (widget, column);
781 
782 	renderer = gtk_cell_renderer_text_new ();
783 	/* Multicast group */
784 	column =
785 	    gtk_tree_view_column_new_with_attributes
786 	    (_("Group"), renderer, "text", 2, NULL);
787 	gtk_tree_view_append_column (widget, column);
788 }
789 /* END MULTICAST */
790 
791 /* Remove all columns from a GtkTreeView */
792 void
793 clean_gtk_tree_view (GtkTreeView *widget)
794 {
795 	GList *columns;
796 	gint n, i;
797 	GtkTreeViewColumn *column;
798 
799 	columns = gtk_tree_view_get_columns (widget);
800 
801 	n = g_list_length (columns);
802 
803 	for (i = n; i > 0; i--) {
804 		column = gtk_tree_view_get_column (widget, i-1);
805 		gtk_tree_view_remove_column (widget, column);
806 	}
807 
808 	g_list_free (columns);
809 }
810 
811 /* Copy on clipboard */
812 void
813 netstat_copy_to_clipboard (Netinfo * netinfo, gpointer user_data)
814 {
815 	GString *result, *content;
816 
817 	g_return_if_fail (netinfo != NULL);
818 
819 	result = g_string_new ("");
820 
821 	switch (netstat_get_active_option2 (netinfo)) {
822 	case PROTOCOL:
823 		/* The netstat "Display active network services" output in
824 	       text format.
825 		   It's a tabular output, and these belongs to the column titles */
826 		result = g_string_new (_("Protocol\tIP Source\tPort/Service\tState\n"));
827 		break;
828 	case ROUTE:
829 		/* The netstat "Display routing" output in text format.
830 		   This seems as a route table.
831 		   It's a tabular output, and these belongs to the column titles */
832 		result = g_string_new (_("Destination\tGateway\tNetmask\tInterface\n"));
833 		break;
834 	case MULTICAST:
835 		/* The netstat "Multicast information" output in text format.
836 		   It's a tabular output, and these belongs to the column titles */
837 		result = g_string_new (_("Interface\tMember\tGroup\n"));
838 		break;
839 	case NONE:
840 	default:
841 		break;
842 	}
843 
844 	content = util_tree_model_to_string (GTK_TREE_VIEW (netinfo->output));
845 
846 	g_string_append_printf (result, "%s", content->str);
847 
848 	gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), result->str,
849 				result->len);
850 
851 	g_string_free (content, TRUE);
852 	g_string_free (result, TRUE);
853 }
854