1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |
8 |  GKrellM is free software: you can redistribute it and/or modify it
9 |  under the terms of the GNU General Public License as published by
10 |  the Free Software Foundation, either version 3 of the License, or
11 |  (at your option) any later version.
12 |
13 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
14 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 |  License for more details.
17 |
18 |  You should have received a copy of the GNU General Public License
19 |  along with this program. If not, see http://www.gnu.org/licenses/
20 |
21 |
22 |  Additional permission under GNU GPL version 3 section 7
23 |
24 |  If you modify this program, or any covered work, by linking or
25 |  combining it with the OpenSSL project's OpenSSL library (or a
26 |  modified version of that library), containing parts covered by
27 |  the terms of the OpenSSL or SSLeay licenses, you are granted
28 |  additional permission to convey the resulting work.
29 |  Corresponding Source for a non-source form of such a combination
30 |  shall include the source code for the parts of OpenSSL used as well
31 |  as that of the covered work.
32 */
33 
34 #include "gkrellm.h"
35 #include "gkrellm-private.h"
36 #include "gkrellm-sysdeps.h"
37 #include "inet.h"
38 
39 typedef struct
40 	{
41 	GtkWidget	*vbox;
42 	gchar		*name;
43 
44 	GkrellmChart		*chart;
45 	GkrellmChart		*chart_minute;
46 	GkrellmChart		*chart_hour;
47 	GkrellmChartconfig	*chart_config_minute;
48 	GkrellmChartconfig	*chart_config_hour;
49 	GkrellmPanel		*panel;
50 	gboolean			hour_mode;
51 	gint				cd_length;
52 
53 	gboolean			extra_info;
54 	GkrellmLauncher		launch;
55 	GtkWidget			*launch_entry,
56 						*tooltip_entry;
57 	GtkWidget			*launch_table;
58 
59 	gshort				*mark_data;		/* Draw marks if hits for any second */
60 	gint				mark_position,
61 						mark_prev_hits;
62 
63 	GkrellmDecal		*list_decal;
64 	GkrellmDecalbutton	*list_button;
65 	GString				*connection_string;
66 	GList				*tcp_save_list;
67 	gboolean			busy;
68 	gboolean			connection_string_event;
69 	gboolean			config_modified;
70 
71 	gchar				*label0;
72 	gint				active0;
73 	gint				prev_active0;
74 	gulong				hits0_minute,
75 						hits0_hour;
76 	gboolean			data0_is_range;
77 	gulong				port0_0,
78 						port0_1;
79 
80 	gchar				*label1;
81 	gint				active1;
82 	gint				prev_active1;
83 	gulong				hits1_minute,
84 						hits1_hour;
85 	gboolean			data1_is_range;
86 	gulong				port1_0,
87 						port1_1;
88 
89 	gulong				krell_hits;
90 	}
91 	InetMon;
92 
93 static GkrellmMonitor *mon_inet;
94 
95 static GList		*inet_mon_list;
96 static GList		*active_tcp_list,
97 					*free_tcp_list;
98 
99 void 				(*read_tcp_data)();
100 
101 static GtkWidget	*inet_vbox;
102 static GdkImage		*grid;
103 
104 static gchar		*inet_data_dir;
105 static gchar		*text_format,
106 					*text_format_locale;
107 
108 static gint			n_inet_monitors,
109 					update_interval  = 1;
110 static gint			style_id;
111 
112 
113 
114 static ActiveTCP *
_tcp_alloc(void)115 _tcp_alloc(void)
116 	{
117 	ActiveTCP	*tcp;
118 
119 	if (free_tcp_list)
120 		{
121 		tcp = free_tcp_list->data;
122 		free_tcp_list = g_list_remove(free_tcp_list, tcp);
123 		}
124 	else
125 		tcp = g_new0(ActiveTCP, 1);
126 	return tcp;
127 	}
128 
129 static ActiveTCP *
_log_active_port(ActiveTCP * tcp)130 _log_active_port(ActiveTCP *tcp)
131 	{
132 	GList		*list;
133 	ActiveTCP	*active_tcp, *new_tcp;
134 	gchar		*ap, *aap;
135 	gint		slen;
136 
137 	for (list = active_tcp_list; list; list = list->next)
138 		{
139 		active_tcp = (ActiveTCP *) (list->data);
140 		if (tcp->family == AF_INET)
141 			{
142 			ap = (char *)&tcp->remote_addr;
143 			aap = (char *)&active_tcp->remote_addr;
144 			slen = sizeof(struct in_addr);
145 			}
146 #if defined(INET6)
147 		else if (tcp->family == AF_INET6)
148 			{
149 			ap = (char *)&tcp->remote_addr6;
150 			aap = (char *)&active_tcp->remote_addr6;
151 			slen = sizeof(struct in6_addr);
152 			}
153 #endif
154 		else
155 			return 0;
156 		if (   memcmp(aap, ap, slen) == 0
157 			&& active_tcp->remote_port == tcp->remote_port
158 			&& active_tcp->local_port == tcp->local_port
159 		   )
160 			{
161 			active_tcp->state = TCP_ALIVE;
162 			return active_tcp;	/* Old hit still alive, not a new hit	*/
163 			}
164 		}
165 	tcp->state = TCP_ALIVE;
166 	tcp->new_hit = 1;
167 	new_tcp = _tcp_alloc();
168 	*new_tcp = *tcp;
169 
170 	if (_GK.debug_level & DEBUG_INET)
171 		{
172 		ap = inet_ntoa(tcp->remote_addr);
173 		g_debug("inet  OO----->  %x %s:%x\n",
174 				tcp->local_port, ap, tcp->remote_port);
175 		}
176 	active_tcp_list = g_list_prepend(active_tcp_list, (gpointer) new_tcp);
177 	return new_tcp;		/* A new hit	*/
178 	}
179 
180 void
gkrellm_inet_log_tcp_port_data(gpointer data)181 gkrellm_inet_log_tcp_port_data(gpointer data)
182 	{
183 	GList		*list;
184 	InetMon		*in;
185 	ActiveTCP	*tcp, *active_tcp = NULL;
186 	gint		krell_hit;
187 
188 	tcp = (ActiveTCP *) data;
189 	for (list = inet_mon_list; list; list = list->next)
190 		{
191 		krell_hit = 0;
192 		in = (InetMon *) list->data;
193 		if (   (!in->data0_is_range
194 				&& (   in->port0_0 == tcp->local_port
195 					|| in->port0_1 == tcp->local_port))
196 			|| (in->data0_is_range
197 				&& tcp->local_port >= in->port0_0
198 				&& tcp->local_port <= in->port0_1)
199 		   )
200 			{
201 			++in->active0;
202 			active_tcp = _log_active_port(tcp);
203 			krell_hit = active_tcp->new_hit;
204 			in->hits0_minute += krell_hit;
205 			in->hits0_hour   += krell_hit;
206 			}
207 		if (   (!in->data1_is_range
208 				&& (   in->port1_0 == tcp->local_port
209 					|| in->port1_1 == tcp->local_port))
210 			|| (in->data1_is_range
211 				&& tcp->local_port >= in->port1_0
212 				&& tcp->local_port <= in->port1_1)
213 		   )
214 			{
215 			++in->active1;
216 			active_tcp = _log_active_port(tcp);
217 			krell_hit = active_tcp->new_hit;
218 			in->hits1_minute += krell_hit;
219 			in->hits1_hour   += krell_hit;
220 			}
221 		in->krell_hits += krell_hit;
222 		}
223 	/* Defer setting new hit to 0 until here so multiple inet charts can
224 	|  monitor the same port number.  The above active_port will be the
225 	|  same if found for both data0 and data1.
226 	*/
227 	if (active_tcp)
228 		active_tcp->new_hit = 0;
229 	}
230 
231 
232 static gboolean
setup_inet_interface(void)233 setup_inet_interface(void)
234     {
235 	if (!read_tcp_data && !_GK.client_mode && gkrellm_sys_inet_init())
236 		{
237 		read_tcp_data = gkrellm_sys_inet_read_tcp_data;
238 		}
239 	return read_tcp_data ? TRUE : FALSE;
240 	}
241 
242 void
gkrellm_inet_client_divert(void (* read_tcp_func)())243 gkrellm_inet_client_divert(void (*read_tcp_func)())
244 	{
245 	read_tcp_data = read_tcp_func;
246 	}
247 
248 
249 /* ======================================================================== */
250 
251 #define DUMP_IN(in,tag)	g_debug("%s: %s %s %ld %ld %ld %ld\n", \
252 						tag, in->label0, in->label1, \
253             			in->port0_0, in->port0_1, in->port1_0, in->port1_1);
254 
255 static void
format_chart_text(InetMon * in,gchar * src_string,gchar * buf,gint size)256 format_chart_text(InetMon *in, gchar *src_string, gchar *buf, gint size)
257 	{
258 	GList			*list;
259 	GkrellmChart	*cp;
260 	GkrellmChartdata *cd;
261 	gchar			c, *s, *s1;
262 	gint			len, value, n, i, w;
263 
264 	if (!buf || size < 1)
265 		return;
266 	--size;
267 	*buf = '\0';
268 	if (!src_string)
269 		return;
270 	cp = in->chart;
271 	w = gkrellm_chart_width();
272 	for (s = text_format_locale; *s != '\0' && size > 0; ++s)
273 		{
274 		len = 1;
275 		if (*s == '$' && *(s + 1) != '\0')
276 			{
277 			value = -1;
278 			s1 = " ";
279 			if ((c = *(s + 1)) == 'M')
280 				value = gkrellm_get_chart_scalemax(cp);
281 			else if (c == 'a' && *in->label0)
282 				value = in->active0;
283 			else if (c == 'l' && *in->label0)
284 				s1 = in->label0;
285 			else if (c == 'c' && *(s + 2))
286 				{
287 				i = 0;
288 				sscanf(s + 2, "%d%n", &n, &i);
289 				s += i;
290 				--n;
291 				if (n > w || n < 0)
292 					n = w;
293 				list = in->hour_mode ?
294 						in->chart_hour->cd_list : in->chart_minute->cd_list;
295 				cd = (GkrellmChartdata *) list->data;
296 				if (*in->label0)
297 					{
298 					value = in->hour_mode ? in->hits0_hour : in->hits0_minute;
299 					for ( ; n > 0; --n)
300 						value += gkrellm_get_chartdata_data(cd, w - n);
301 					}
302 				}
303 			else if (c == 'A' && *in->label1)
304 				value = in->active1;
305 			else if (c == 'L' && *in->label1)
306 				s1 = in->label1;
307 			else if (c == 'C' && *(s + 2))
308 				{
309 				i = 0;
310 				sscanf(s + 2, "%d%n", &n, &i);
311 				s += i;
312 				--n;
313 				if (n > w || n < 0)
314 					n = w;
315 				list = in->hour_mode ?
316 						in->chart_hour->cd_list : in->chart_minute->cd_list;
317 				if (list->next)
318 					list = list->next;
319 				cd = (GkrellmChartdata *) list->data;
320 				if (*in->label1)
321 					{
322 					value = in->hour_mode ? in->hits1_hour : in->hits1_minute;
323 					for ( ; n > 0; --n)
324 						value += gkrellm_get_chartdata_data(cd, w - n);
325 					}
326 				}
327 			else if (c == 'H')
328 				s1 = gkrellm_sys_get_host_name();
329 			if (value >= 0)
330 				len = snprintf(buf, size, "%d", value);
331 			else
332 				len = snprintf(buf, size, "%s", s1);
333 			++s;
334 			}
335 		else
336 			*buf = *s;
337 		size -= len;
338 		buf += len;
339 		}
340 	*buf = '\0';
341 	}
342 
343 static void
draw_inet_extra(InetMon * in)344 draw_inet_extra(InetMon *in)
345 	{
346 	gchar	buf[128];
347 
348 	if (!in->extra_info)
349 		return;
350 	format_chart_text(in, text_format_locale, buf, sizeof(buf));
351 	gkrellm_draw_chart_text(in->chart, style_id, buf);
352 	}
353 
354   /* Use the reserved area below the main chart to draw marks if any
355   |  hits in second intervals.
356   */
357 static void
draw_inet_mark_data(InetMon * in,gint minute_mark)358 draw_inet_mark_data(InetMon *in, gint minute_mark)
359 	{
360 	GkrellmChart	*cp;
361 	GdkGC			*gc1, *gc2, *gc3;
362 	gint			hits, x, y, n;
363 
364 	cp = in->chart;
365 	in->mark_position = (in->mark_position + 1) % cp->w;
366 	if (minute_mark)
367 		{
368 		in->mark_data[in->mark_position] = -1;	/* minute flag in the data */
369 		return;
370 		}
371 	hits = in->hits0_minute + in->hits1_minute;
372 	in->mark_data[in->mark_position] = hits - in->mark_prev_hits;
373 	in->mark_prev_hits = hits;
374 
375 	gc1 = gkrellm_draw_GC(1);
376 	gc2 = gkrellm_draw_GC(2);
377 	gc3 = gkrellm_draw_GC(3);
378 
379 	/* Clear out the area and redraw the marks.
380 	*/
381 	y = cp->h - cp->y;
382 	gdk_draw_drawable(cp->pixmap, gc1, cp->bg_src_pixmap,
383 			0, y,  0, y,  cp->w, cp->y);
384 	gdk_gc_set_foreground(gc1, gkrellm_out_color());
385 	gdk_gc_set_foreground(gc2, gkrellm_in_color());
386 	gdk_gc_set_foreground(gc3, gkrellm_white_color());
387 	for (n = 0; n < cp->w; ++n)
388 		{
389 		x = (in->mark_position + n + 1) % cp->w;
390 		if (in->mark_data[x] > 0)
391 			gdk_draw_line(cp->pixmap, gc1,
392 						cp->x + n, cp->h - 1, cp->x + n, y);
393 		else if (in->mark_data[x] == -1)	/* Minute tick	*/
394 			gdk_draw_line(cp->pixmap, gc3,
395 						cp->x + n, cp->h - 1, cp->x + n, y);
396 		}
397 	gdk_draw_drawable(cp->drawing_area->window, gc1, cp->pixmap,
398 			0, y,  0, y,  cp->w, cp->y);
399 	}
400 
401 static void
draw_inet_chart(InetMon * in)402 draw_inet_chart(InetMon *in)
403 	{
404 	struct tm			tm;
405 	GdkGC				*gc3;
406 	GkrellmChart		*cp;
407 	GkrellmTextstyle	*ts;
408 	GdkColor			tmp_color;
409 	gchar				buf[32];
410 	guint32				pixel0, pixel1;
411 	gint				y0, h4, w, h, n;
412 
413 	cp = in->chart;
414 	gkrellm_draw_chartdata(cp);
415 
416 	y0 = cp->h - cp->y;
417 	h4 = y0 / 4;
418 	gdk_drawable_get_size(in->chart->bg_grid_pixmap, &w, &h);
419 	if (grid == NULL)
420 		grid = gdk_drawable_get_image(in->chart->bg_grid_pixmap, 0, 0, w, h);
421 	ts = gkrellm_chart_alt_textstyle(style_id);
422 
423 	tm = *gkrellm_get_current_time();
424 	gc3 = gkrellm_draw_GC(3);
425 	gdk_gc_set_foreground(gkrellm_draw_GC(3), gkrellm_white_color());
426 	if (in->hour_mode)
427 		{
428 		for (n = cp->w - 1; n >= 0; --n)
429 			{
430 			/* When hour ticked to 0, 23rd hour data was stored and a slot
431 			|  was skipped.
432 			*/
433 			if (tm.tm_hour == 0)	/* Draw day mark at midnight	*/
434 				{
435 				pixel0 = gdk_image_get_pixel(grid, cp->x + n, 0);
436 				tmp_color.pixel = pixel0;
437 				gdk_gc_set_foreground(gc3, &tmp_color);
438 				gdk_draw_line(cp->pixmap, gc3,
439 						cp->x + n - 1, y0 - 3, cp->x + n - 1, 3);
440 				if (h > 1)
441 					{
442 					pixel1 = gdk_image_get_pixel(grid, cp->x + n, 1);
443 					tmp_color.pixel = pixel1;
444 					gdk_gc_set_foreground(gc3, &tmp_color);
445 					gdk_draw_line(cp->pixmap, gc3,
446 							cp->x + n, y0 - 3, cp->x + n, 3);
447 					}
448 				}
449 			if (in->extra_info && tm.tm_hour == 1 && n < cp->w - 5)
450 				{
451 				strftime(buf, sizeof(buf), "%a", &tm);
452 				buf[1] = '\0';
453 				gkrellm_draw_chart_label(in->chart, ts,
454 						cp->x + n, in->chart->h - 4, buf);
455 				}
456 			if (--tm.tm_hour < 0)
457 				{
458 				tm.tm_hour = 24;		/* Extra hour for skipped slot	*/
459 				if (--tm.tm_wday < 0)
460 					tm.tm_wday = 6;
461 				}
462 			}
463 		}
464 	else
465 		{
466 		for (n = cp->w - 1; n >= 0; --n)
467 			{
468 			/* When minute ticked to 0, 59 minute data was stored and a slot
469 			|  was skipped.
470 			*/
471 			if (tm.tm_min == 0)		/* Draw hour mark	*/
472 				{
473 				pixel0 = gdk_image_get_pixel(grid, cp->x + n, 0);
474 				tmp_color.pixel = pixel0;
475 				gdk_gc_set_foreground(gc3, &tmp_color);
476 				gdk_draw_line(cp->pixmap, gc3,
477 						cp->x + n - 1, y0 - 3, cp->x + n - 1, y0 - h4);
478 				if (h > 1)
479 					{
480 					pixel1 = gdk_image_get_pixel(grid, cp->x + n, 1);
481 					tmp_color.pixel = pixel1;
482 					gdk_gc_set_foreground(gc3, &tmp_color);
483 					gdk_draw_line(cp->pixmap, gc3,
484 							cp->x + n, y0 - 3, cp->x + n, y0 - h4);
485 					}
486 				}
487 			if (--tm.tm_min < 0)
488 				tm.tm_min = 60;		/* extra minute for skipped slot */
489 			}
490 		}
491 	if (in->extra_info)
492 		draw_inet_extra(in);
493 	gkrellm_draw_chart_to_screen(cp);
494 	in->prev_active0 = in->active0;
495 	in->prev_active1 = in->active1;
496 	}
497 
498 static void
select_hour_or_minute_chart(InetMon * in)499 select_hour_or_minute_chart(InetMon *in)
500 	{
501 	gkrellm_freeze_side_frame_packing();
502 	if (in->hour_mode && in->chart == in->chart_minute)
503 		{
504 		gkrellm_chart_hide(in->chart_minute, FALSE);
505 		gkrellm_chart_show(in->chart_hour, FALSE);
506 		in->chart = in->chart_hour;
507 		gkrellm_chartconfig_window_destroy(in->chart_minute);
508 		}
509 	else if (!in->hour_mode && in->chart == in->chart_hour)
510 		{
511 		gkrellm_chart_hide(in->chart_hour, FALSE);
512 		gkrellm_chart_show(in->chart_minute, FALSE);
513 		in->chart = in->chart_minute;
514 		gkrellm_chartconfig_window_destroy(in->chart_hour);
515 		}
516 	gkrellm_thaw_side_frame_packing();
517 	}
518 
519 static void
update_inet(void)520 update_inet(void)
521 	{
522 	InetMon			*in;
523 	ActiveTCP		*tcp;
524 	GList			*list;
525 	gchar			buf[32], *ap;
526 	gint			i;
527 	static gint		check_tcp;
528 
529 	if (!inet_mon_list)
530 		return;
531 
532 	if (GK.second_tick && check_tcp == 0)
533 		{
534 		for (list = inet_mon_list; list; list = list->next)
535 			{
536 			in = (InetMon *) list->data;
537 			in->active0 = 0;
538 			in->active1 = 0;
539 			}
540 		/* Assume all connections are dead, then read_tcp_data() will set
541 		|  still alive ones back to alive.  Then I can prune really dead ones.
542 		*/
543 		for (list = active_tcp_list; list; list = list->next)
544 			{
545 			tcp = (ActiveTCP *)(list->data);
546 			tcp->state = TCP_DEAD;
547 			}
548 
549 		(*read_tcp_data)();
550 
551 		for (list = active_tcp_list; list; )
552 			{
553 			tcp = (ActiveTCP *)(list->data);
554 			if (tcp->state == TCP_DEAD)
555 				{
556 				if (list == active_tcp_list)
557 					active_tcp_list = active_tcp_list->next;
558 				list = g_list_remove(list, tcp);
559 				if (_GK.debug_level & DEBUG_INET)
560 					{
561 					ap = inet_ntoa(tcp->remote_addr);
562 					g_debug("inet  XX----->  %x %s:%x\n",
563 							tcp->local_port, ap, tcp->remote_port);
564 					}
565 				free_tcp_list = g_list_prepend(free_tcp_list, tcp);
566 				}
567 			else
568 				list = list->next;
569 			}
570 		}
571 	if (GK.second_tick)
572 		check_tcp = (check_tcp + 1) % update_interval;
573 
574 	for (list = inet_mon_list; list; list = list->next)
575 		{
576 		in = (InetMon *) list->data;
577 		if (GK.hour_tick)
578 			{
579 			if (!*in->label0)
580 				in->hits0_hour = in->hits1_hour;
581 			gkrellm_store_chartdata(in->chart_hour, 0,
582 					in->hits0_hour, in->hits1_hour);
583 			in->hits0_hour = in->hits1_hour = 0;
584 			if (GK.day_tick)	/* Make room for vertical day grid */
585 				{
586 				gkrellm_store_chartdata(in->chart_hour, 0, 0, 0);
587 				gkrellm_store_chartdata(in->chart_hour, 0, 0, 0);
588 				}
589 			}
590 		if (GK.minute_tick)
591 			{
592 			if (!*in->label0)
593 				in->hits0_minute = in->hits1_minute;
594 			gkrellm_store_chartdata(in->chart_minute, 0,
595 					in->hits0_minute, in->hits1_minute);
596 			in->hits0_minute = in->hits1_minute = 0;
597 			if (GK.hour_tick)	/* Make room for vertical hour grid */
598 				{
599 				gkrellm_store_chartdata(in->chart_minute, 0, 0, 0);
600 				gkrellm_store_chartdata(in->chart_minute, 0, 0, 0);
601 				}
602 			gkrellm_refresh_chart(in->chart);
603 			draw_inet_mark_data(in, 1);
604 			}
605 		else if (   GK.second_tick
606 				&& (   in->prev_active0 != in->active0
607 					|| in->prev_active1 != in->active1
608 				   )
609 				)
610 				draw_inet_chart(in);	/* Just to update extra info draw */
611 
612 		if (GK.second_tick)
613 			draw_inet_mark_data(in, 0);
614 
615 		if (in->busy && in->list_button->cur_index == D_MISC_BUTTON_OUT)
616 			i = D_MISC_BUTTON_ON;
617 		else
618 			i = D_MISC_BUTTON_OUT;
619 		gkrellm_set_decal_button_index(in->list_button, i);
620 
621 		gkrellm_update_krell(in->panel, KRELL(in->panel), in->krell_hits);
622 		gkrellm_draw_panel_layers(in->panel);
623 
624 		if (in->connection_string_event)
625 			{
626 			snprintf(buf, sizeof(buf), _("%s Connections"), in->name);
627 			gkrellm_message_dialog(buf, in->connection_string->str);
628 			in->connection_string_event = FALSE;
629 			in->busy = FALSE;
630 			}
631 		}
632 	}
633 
634 static gboolean
tcp_port_is_monitored(ActiveTCP * tcp,gboolean range,gulong p0,gulong p1)635 tcp_port_is_monitored(ActiveTCP *tcp, gboolean range, gulong p0, gulong p1)
636 	{
637 	if (   (!range && (p0 == tcp->local_port || p1 == tcp->local_port))
638 		|| ( range && tcp->local_port >= p0 && tcp->local_port <= p1)
639 	   )
640 		return TRUE;
641 	return FALSE;
642 	}
643 
644 static gpointer
get_connection_string_thread(void * data)645 get_connection_string_thread(void *data)
646 	{
647 	InetMon					*in	= (InetMon *) data;
648 	GList					*list;
649 	ActiveTCP				*tcp;
650 #if defined(INET6)
651 	union {
652 	    struct sockaddr_storage	ss;
653 	    struct sockaddr_in		sin;
654 	    struct sockaddr_in6	sin6;
655 	    struct sockaddr		sa;
656 	} ss;
657 	gint					salen, flag = 0;
658 	gchar					hbuf[NI_MAXHOST];
659 	gchar					buf[NI_MAXHOST + 64];
660 #else
661 	struct hostent			*hostent;
662 	gchar					buf[128];
663 #endif
664 	gchar					*remote_host, *udp_note;
665 
666 	if (in->connection_string)
667 		in->connection_string = g_string_truncate(in->connection_string, 0);
668 	else
669 		in->connection_string = g_string_new("");
670 	for (list = in->tcp_save_list; list; list = list->next)
671 		{
672 		tcp = (ActiveTCP *) list->data;
673 #if defined(INET6)
674 		memset(&ss.ss, 0, sizeof(ss.ss));
675 		switch (tcp->family)
676 			{
677 			case AF_INET:
678 				salen = sizeof(struct sockaddr_in);
679 				memcpy(&ss.sin.sin_addr, &tcp->remote_addr, salen);
680 #if defined(SIN6_LEN)
681 				ss.sin.sin_len = salen;
682 #endif
683 				ss.sin.sin_family = tcp->family;
684 				break;
685 			case AF_INET6:
686 				salen = sizeof(struct sockaddr_in6);
687 				memcpy(&ss.sin6.sin6_addr, &tcp->remote_addr6, salen);
688 #if defined(SIN6_LEN)
689 				ss.sin6.sin6_len = salen;
690 #endif
691 				ss.sin6.sin6_family = tcp->family;
692 				/* XXX: We should mention about
693 				|  scope, too. */
694 				break;
695 			default:
696 				continue;
697 			}
698 		if (getnameinfo(&ss.sa, salen,
699 				hbuf, sizeof(hbuf), NULL, 0, flag))
700 			continue;
701 		remote_host = hbuf;
702 #else
703 		hostent = gethostbyaddr((char *) &tcp->remote_addr,
704 					sizeof(struct in_addr), AF_INET);
705 		if (hostent)
706 			remote_host = hostent->h_name;
707 		else
708 			remote_host = inet_ntoa(tcp->remote_addr);
709 #endif
710 		udp_note = tcp->is_udp ? " (UDP)" : "";
711 		snprintf(buf, sizeof(buf), "%6d:  %s%s\n",
712 				tcp->local_port, remote_host, udp_note);
713 
714 		g_string_append(in->connection_string, buf);
715 		}
716 	if (in->connection_string->len == 0)
717 		g_string_append(in->connection_string, _("No current connections."));
718 	in->connection_string_event = TRUE;
719 	gkrellm_free_glist_and_data(&in->tcp_save_list);
720 	return NULL;
721 	}
722 
723 static void
cb_list_button(GkrellmDecalbutton * button)724 cb_list_button(GkrellmDecalbutton *button)
725     {
726 	InetMon			*in	= (InetMon *) button->data;
727 	GList			*list;
728 	GThread			*gth;
729 	ActiveTCP		*tcp, *tcp_save;
730 
731 	if (in->busy)
732 		return;
733 	in->busy = TRUE;
734 
735 	/* Save a snapshot of active connections so I don't have to worry about
736 	|  the active_tcp_list changing while in the thread.
737 	*/
738 	for (list = active_tcp_list; list; list = list->next)
739 		{
740 		tcp = (ActiveTCP *) list->data;
741 		if (   tcp_port_is_monitored(tcp, in->data0_is_range,
742 						in->port0_0, in->port0_1)
743 			|| tcp_port_is_monitored(tcp, in->data1_is_range,
744 						in->port1_0, in->port1_1)
745 		   )
746 			{
747 			tcp_save = g_new0(ActiveTCP, 1);
748 			*tcp_save = *tcp;
749 			in->tcp_save_list = g_list_append(in->tcp_save_list, tcp_save);
750 			}
751 		}
752 	gth = g_thread_new("get_connection_string",
753 					get_connection_string_thread, in);
754 	g_thread_unref(gth);
755 	}
756 
757 static gint
inet_expose_event(GtkWidget * widget,GdkEventExpose * ev)758 inet_expose_event(GtkWidget *widget, GdkEventExpose *ev)
759 	{
760 	InetMon		*in;
761 	GList		*list;
762 	GdkPixmap	*pixmap = NULL;
763 
764 	for (list = inet_mon_list; list; list = list->next)
765 		{
766 		in = (InetMon *) list->data;
767 		if (widget == in->panel->drawing_area)
768 			pixmap = in->panel->pixmap;
769 		else if (widget == in->chart_minute->drawing_area)
770 			pixmap = in->chart_minute->pixmap;
771 		else if (widget == in->chart_hour->drawing_area)
772 			pixmap = in->chart_hour->pixmap;
773 		if (pixmap)
774 			{
775 			gdk_draw_drawable(widget->window, gkrellm_draw_GC(1), pixmap,
776 					ev->area.x, ev->area.y, ev->area.x, ev->area.y,
777 					ev->area.width, ev->area.height);
778 			break;
779 			}
780 		}
781 	return FALSE;
782 	}
783 
784 static gint
cb_inet_extra(GtkWidget * widget,GdkEventButton * ev)785 cb_inet_extra(GtkWidget *widget, GdkEventButton *ev)
786 	{
787 	InetMon		*in;
788 	GList		*list;
789 
790 	for (list = inet_mon_list; list; list = list->next)
791 		{
792 		in = (InetMon *) list->data;
793 		if (widget != in->chart->drawing_area)
794 			continue;
795 		if (ev->button == 1 && ev->type == GDK_BUTTON_PRESS)
796 			{
797 			in->extra_info = !in->extra_info;
798 			gkrellm_refresh_chart(in->chart);
799 			gkrellm_config_modified();
800 			}
801 		else if (ev->button == 2)
802 			{
803 			in->hour_mode = !in->hour_mode;
804 			select_hour_or_minute_chart(in);
805 			gkrellm_rescale_chart(in->chart);
806 			}
807 		else if (   ev->button == 3
808 				 || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS)
809 				)
810 			gkrellm_chartconfig_window_create(in->chart);
811 		break;
812 		}
813 	return FALSE;
814 	}
815 
816 static gint
cb_panel_press(GtkWidget * widget,GdkEventButton * ev)817 cb_panel_press(GtkWidget *widget, GdkEventButton *ev)
818 	{
819 	if (ev->button == 3)
820 		gkrellm_open_config_window(mon_inet);
821 	return FALSE;
822 	}
823 
824   /* Lock the hour and minute heights together.
825   */
826 static void
cb_inet_height(GkrellmChartconfig * cf,InetMon * in)827 cb_inet_height(GkrellmChartconfig *cf, InetMon *in)
828 	{
829 	gint	h;
830 
831 	h = gkrellm_get_chartconfig_height(cf);
832 	if (in->chart_minute->h != h)
833 		gkrellm_set_chart_height(in->chart_minute, h);
834 	if (in->chart_hour->h != h)
835 		gkrellm_set_chart_height(in->chart_hour, h);
836 	}
837 
838 static void
destroy_inet_monitor(InetMon * in)839 destroy_inet_monitor(InetMon *in)
840 	{
841 	if (in->launch_table)
842 		gtk_widget_destroy(in->launch_table);
843 	g_free(in->name);
844 	g_free(in->label0);
845 	g_free(in->label1);
846 	if (in->launch.command)
847 		g_free(in->launch.command);
848 	if (in->launch.button)
849 		gkrellm_destroy_button(in->launch.button);
850 	g_free(in->mark_data);
851 
852 	/* The panel doesn't live in the chart struct, so destroy it separately
853 	*/
854 	gkrellm_panel_destroy(in->panel);
855 
856 	gkrellm_chartconfig_destroy(&in->chart_config_minute);
857 	gkrellm_chart_destroy(in->chart_minute);
858 
859 	gkrellm_chartconfig_destroy(&in->chart_config_hour);
860 	gkrellm_chart_destroy(in->chart_hour);
861 
862 	gtk_widget_destroy(in->vbox);
863 	g_free(in);
864 	}
865 
866 
867 #define	MIN_GRID_RES		2
868 #define	MAX_GRID_RES		1000000
869 #define DEFAULT_GRID_RES	10
870 
871 static void
chart_create(InetMon * in,GkrellmChart * cp,GkrellmChartconfig ** cfp,gint first_create)872 chart_create(InetMon *in, GkrellmChart *cp, GkrellmChartconfig **cfp,
873 				gint first_create)
874 	{
875 	GkrellmChartconfig	*cf;
876 	GkrellmChartdata	*cd;
877 	GdkPixmap			**src_pixmap, *grid_pixmap;
878 
879 	cp->y = 3;
880 	gkrellm_chart_create(in->vbox, mon_inet, cp, cfp);
881 	cf = *cfp;
882 
883 	/* I accumulate tcp hits myself, so I'm free to make the chartdata
884 	|  accumulate monotonically or not.  I choose not monotonic to make saving
885 	|  and loading data simpler.
886 	*/
887 	src_pixmap = gkrellm_data_out_pixmap();
888 	grid_pixmap = gkrellm_data_out_grid_pixmap();
889 	if (*in->label0)
890 		{
891 		cd = gkrellm_add_chartdata(cp, src_pixmap, grid_pixmap, in->label0);
892 		gkrellm_monotonic_chartdata(cd, FALSE);
893 		}
894 	src_pixmap = gkrellm_data_in_pixmap();
895 	grid_pixmap = gkrellm_data_in_grid_pixmap();
896 	if (*in->label1)
897 		{
898 		cd = gkrellm_add_chartdata(cp, src_pixmap, grid_pixmap, in->label1);
899 		gkrellm_monotonic_chartdata(cd, FALSE);
900 		}
901 	gkrellm_set_draw_chart_function(cp, draw_inet_chart, in);
902 
903 	/* krell is not function of chart grids or resolution, so no interest
904 	|  in connecting to grid or resolution changes.
905 	*/
906 	gkrellm_chartconfig_height_connect(cf, cb_inet_height, in);
907 	gkrellm_chartconfig_grid_resolution_adjustment(cf, TRUE,
908 			0, (gfloat) MIN_GRID_RES, (gfloat) MAX_GRID_RES, 0, 0, 0, 70);
909 	if (gkrellm_get_chartconfig_grid_resolution(cf) < MIN_GRID_RES)
910 		gkrellm_set_chartconfig_grid_resolution(cf, DEFAULT_GRID_RES);
911 
912 	/* Don't want to waste an hour priming the pump, and don't need to
913 	|  because data always starts at zero.
914 	*/
915 	cp->primed = TRUE;		/* XXX */
916 	gkrellm_alloc_chartdata(cp);
917 
918 	if (first_create)
919 		{
920 		g_signal_connect(G_OBJECT (cp->drawing_area), "expose_event",
921 				G_CALLBACK(inet_expose_event), NULL);
922 		g_signal_connect(G_OBJECT(cp->drawing_area),"button_press_event",
923 				G_CALLBACK(cb_inet_extra), NULL);
924 		}
925 	}
926 
927 static void
create_inet_monitor(GtkWidget * vbox1,InetMon * in,gint first_create)928 create_inet_monitor(GtkWidget *vbox1, InetMon *in, gint first_create)
929 	{
930 	GtkWidget		*vbox;
931 	GkrellmChart	*cp;
932 	GkrellmPanel	*p;
933 	GkrellmMargin	*m;
934 	GkrellmStyle	*style;
935 	gint			x;
936 
937 	if (first_create)
938 		{
939 		vbox = gtk_vbox_new(FALSE, 0);
940 		gtk_container_add(GTK_CONTAINER(vbox1), vbox);
941 		in->vbox = vbox;
942 		in->chart_minute = gkrellm_chart_new0();
943 		in->chart_hour = gkrellm_chart_new0();
944 		in->panel = gkrellm_panel_new0();
945 		in->chart = in->chart_minute;
946 		in->name = g_strdup_printf(_("inet%d"), n_inet_monitors++);
947 		}
948 	else
949 		{
950 		vbox = in->vbox;
951 		gkrellm_destroy_decal_list(in->panel);
952 		gkrellm_destroy_krell_list(in->panel);
953 		}
954 	if (in->chart_config_hour && in->chart_config_minute)
955 		in->chart_config_hour->h = in->chart_config_minute->h;
956 	chart_create(in, in->chart_minute, &in->chart_config_minute, first_create);
957 	gkrellm_chartconfig_grid_resolution_label(in->chart_config_minute,
958 			_("TCP hits per minute"));
959 	chart_create(in, in->chart_hour, &in->chart_config_hour, first_create);
960 	gkrellm_chartconfig_grid_resolution_label(in->chart_config_hour,
961 			_("TCP hits per hour"));
962 	cp = in->chart;
963 
964 	p = in->panel;
965 	style = gkrellm_panel_style(style_id);
966 	m = gkrellm_get_style_margins(style);
967 	if (style->label_position == 50 && gkrellm_chart_width() < 80)
968 		style->label_position = 40;		/* Not a kludge, an adjustment! */
969 	in->list_decal = gkrellm_create_decal_pixmap(p,
970 				gkrellm_decal_misc_pixmap(), gkrellm_decal_misc_mask(),
971 				N_MISC_DECALS, style, -1, -1);
972 	if (style->label_position <= 50)
973 		x = gkrellm_chart_width() - in->list_decal->w - m->right;
974 	else
975 		x = m->left;
976 	gkrellm_move_decal(p, in->list_decal, x, in->list_decal->y);
977 
978 	gkrellm_create_krell(p, gkrellm_krell_panel_piximage(style_id), style);
979 
980 	/* Inet krells are not related to chart scale_max.  Just give a constant
981 	|  full scale of 5.
982 	*/
983 	KRELL(p)->full_scale = 5;
984 	gkrellm_panel_configure(p, in->name, style);
985 	gkrellm_panel_create(vbox, mon_inet, p);
986 
987 	/* At first_create both charts will be visible, but this will be
988 	|  undone below
989 	*/
990 	in->list_button = gkrellm_make_decal_button(p, in->list_decal,
991 			cb_list_button, in, D_MISC_BUTTON_OUT, D_MISC_BUTTON_IN);
992 
993 	if (first_create)
994 		{
995 		g_signal_connect(G_OBJECT(p->drawing_area),"expose_event",
996 				G_CALLBACK(inet_expose_event), NULL);
997 		g_signal_connect(G_OBJECT(p->drawing_area), "button_press_event",
998 				G_CALLBACK(cb_panel_press), NULL);
999 
1000 		gtk_widget_show(vbox);
1001 		gkrellm_chart_hide(in->chart_hour, FALSE);
1002 		}
1003 	gkrellm_setup_launcher(p, &in->launch, CHART_PANEL_TYPE, 4);
1004 
1005 	if (in->mark_data)
1006 		g_free(in->mark_data);
1007 	in->mark_data = g_new0(gshort, cp->w);
1008 
1009 	if (! first_create)
1010 		gkrellm_rescale_chart(in->chart);
1011 	}
1012 
1013 static void
create_inet(GtkWidget * vbox,gint first_create)1014 create_inet(GtkWidget *vbox, gint first_create)
1015 	{
1016 	GList		*list;
1017 	gint		new_data	= FALSE;
1018 	gint		i;
1019 	static gint	last_chart_width;
1020 
1021 	inet_vbox = vbox;
1022 	if (grid)
1023 		{
1024 		g_object_unref(G_OBJECT(grid));
1025 		grid = NULL;
1026 		}
1027 	n_inet_monitors = 0;
1028 	if (!first_create && last_chart_width != gkrellm_chart_width())
1029 		{  /* Will be allocating new data arrays */
1030 		gkrellm_inet_save_data();
1031 		new_data = TRUE;
1032 		last_chart_width = gkrellm_chart_width();
1033 		}
1034 	for (i = 0, list = inet_mon_list; list; ++i, list = list->next)
1035 		create_inet_monitor(inet_vbox, (InetMon *)list->data, first_create);
1036 	if (first_create || new_data)
1037 		gkrellm_inet_load_data();
1038 	if (inet_mon_list)
1039 		gkrellm_spacers_show(mon_inet);
1040 	else
1041 		gkrellm_spacers_hide(mon_inet);
1042 	}
1043 
1044 static InetMon   *
lookup_inet(gchar * name)1045 lookup_inet(gchar *name)
1046 	{
1047 	InetMon	*in;
1048 	GList	*list;
1049 
1050 	for (list = inet_mon_list; list; list = list->next)
1051 		{
1052 		in = (InetMon *) list->data;
1053 		if (name && in->name && !strcmp(in->name, name))
1054 			return in;
1055 		}
1056 	return NULL;
1057 	}
1058 
1059 /* --------------------------------------------------------------------- */
1060 #define	INET_CONFIG_KEYWORD		"inet"
1061 
1062 static void
save_inet_config(FILE * f)1063 save_inet_config(FILE *f)
1064 	{
1065 	GList		*list;
1066 	InetMon		*in;
1067 	gchar		buf[128];
1068 	gchar		*l0, *l1;
1069 	gint		i;
1070 
1071 	for (i = 0, list = inet_mon_list; list; list = list->next, ++i)
1072 		{
1073 		in = (InetMon *) list->data;
1074 		l0 = (*in->label0) ? in->label0: "NONE";
1075 		l1 = (*in->label1) ? in->label1: "NONE";
1076 		fprintf(f, "%s monitor %s %s %lu %lu %s %lu %lu %d %d %d\n",
1077 				INET_CONFIG_KEYWORD, in->name,
1078 				l0, in->port0_0, in->port0_1,
1079 				l1, in->port1_0, in->port1_1,
1080 				in->extra_info, in->data0_is_range, in->data1_is_range);
1081 		snprintf(buf, sizeof(buf), "%s:minute", in->name);
1082 		gkrellm_save_chartconfig(f, in->chart_config_minute,
1083 				INET_CONFIG_KEYWORD, buf);
1084 		snprintf(buf, sizeof(buf), "%s:hour", in->name);
1085 		gkrellm_save_chartconfig(f, in->chart_config_hour,
1086 				INET_CONFIG_KEYWORD, buf);
1087 		if (in->launch.command)
1088 			fprintf(f, "%s launch %s %s\n", INET_CONFIG_KEYWORD,
1089 						in->name, in->launch.command);
1090 		if (in->launch.tooltip_comment)
1091 			fprintf(f, "%s tooltip %s %s\n", INET_CONFIG_KEYWORD,
1092 						in->name, in->launch.tooltip_comment);
1093 		}
1094 	fprintf(f, "%s text_format all %s\n", INET_CONFIG_KEYWORD, text_format);
1095 	if (!_GK.client_mode)
1096 		fprintf(f, "%s update_interval all %d\n",
1097 					INET_CONFIG_KEYWORD, update_interval);
1098 	}
1099 
1100 static gint
fix_ports(InetMon * in)1101 fix_ports(InetMon *in)
1102 	{
1103 	gint	cd_length = 2;
1104 	gulong	tmp;
1105 
1106 	if (!*in->label0)
1107 		{
1108 		in->port0_1 = 0;
1109 		in->data0_is_range = 0;
1110 		--cd_length;
1111 		}
1112 	if (!*in->label1)
1113 		{
1114 		in->port1_1 = 0;
1115 		in->data1_is_range = 0;
1116 		--cd_length;
1117 		}
1118 	if (in->data0_is_range && (in->port0_1 < in->port0_0))
1119 		{
1120 		tmp = in->port0_1;
1121 		in->port0_1 = in->port0_0;
1122 		in->port0_0 = tmp;
1123 		}
1124 	if (in->data1_is_range && (in->port1_1 < in->port1_0))
1125 		{
1126 		tmp = in->port1_1;
1127 		in->port1_1 = in->port1_0;
1128 		in->port1_0 = tmp;
1129 		}
1130 	return cd_length;
1131 	}
1132 
1133 static void
load_inet_config(gchar * arg)1134 load_inet_config(gchar *arg)
1135 	{
1136 	InetMon		*in;
1137 	gchar		config[32], name[32];
1138 	gchar		item[CFG_BUFSIZE];
1139 	gchar		label0[16], label1[16];
1140 	gchar		*hr_min;
1141 	gint		n;
1142 
1143 	if ((n = sscanf(arg, "%31s %31s %[^\n]", config, name, item)) != 3)
1144 		return;
1145 	hr_min = strrchr(name, (gint) ':');
1146 	if (hr_min)
1147 		*hr_min++ = '\0';
1148 	if (!strcmp(config, "text_format"))
1149 		{
1150 		gkrellm_locale_dup_string(&text_format, item, &text_format_locale);
1151 		return;
1152 		}
1153 	else if (!strcmp(config, "update_interval"))
1154 		{
1155 		sscanf(item, "%d", &update_interval);
1156 		if (update_interval < 1)
1157 			update_interval = 1;
1158 		}
1159 	else if (!strcmp(config, "monitor"))
1160 		{
1161 		in = g_new0(InetMon, 1);
1162 		label0[0] = '\0';
1163 		label1[0] = '\0';
1164 		sscanf(item, "%15s %lu %lu %15s %lu %lu %d %d %d",
1165 				label0, &in->port0_0, &in->port0_1,
1166 				label1, &in->port1_0, &in->port1_1,
1167 				&in->extra_info, &in->data0_is_range, &in->data1_is_range);
1168 		if (!strcmp(label0, "NONE"))
1169 			label0[0] = '\0';
1170 		if (!strcmp(label1, "NONE"))
1171 			label1[0] = '\0';
1172 		in->label0 = g_strdup(label0);
1173 		in->label1 = g_strdup(label1);
1174 		in->cd_length = fix_ports(in);
1175 		if (in->cd_length > 0)
1176 			{
1177 			in->name = g_strdup(name);
1178 			in->chart_config_minute = gkrellm_chartconfig_new0();
1179 			in->chart_config_hour = gkrellm_chartconfig_new0();
1180 			inet_mon_list = g_list_append(inet_mon_list, in);
1181 			}
1182 		else	/* Bogus config line */
1183 			{
1184 			g_free(in->label0);
1185 			g_free(in->label1);
1186 			g_free(in);
1187 			}
1188 		return;
1189 		}
1190 	if ((in = lookup_inet(name)) == NULL)
1191 		return;
1192 	if (!strcmp(config, GKRELLM_CHARTCONFIG_KEYWORD))
1193 		{
1194 		if (hr_min && !strcmp(hr_min, "hour"))
1195 			gkrellm_load_chartconfig(&in->chart_config_hour, item,
1196 					in->cd_length);
1197 		if (hr_min && !strcmp(hr_min, "minute"))
1198 			gkrellm_load_chartconfig(&in->chart_config_minute, item,
1199 					in->cd_length);
1200 		}
1201 	else if (!strcmp(config, "launch"))
1202 		gkrellm_dup_string(&in->launch.command, item);
1203 	else if (!strcmp(config, "tooltip"))
1204 		gkrellm_dup_string(&in->launch.tooltip_comment, item);
1205 	}
1206 
1207 
1208 /* --------------------------------------------------------------------- */
1209 
1210   /* Read saved inet data (from a previous gkrellm process).  Return the
1211   |  number of missing data slots (skew).
1212   */
1213 static gint
read_inet_data(GkrellmChart * cp,FILE * f,gint minute_chart,gint min,gint hour,gint yday,gint width)1214 read_inet_data(GkrellmChart *cp, FILE *f, gint minute_chart,
1215 			gint min, gint hour, gint yday, gint width)
1216 	{
1217 	struct tm	*tm;
1218 	gchar		data[64];
1219 	gint		n, in, out, cur_slot, skew, day;
1220 
1221 	tm = gkrellm_get_current_time();
1222 	day = tm->tm_yday - yday;
1223 
1224 	/* Check for new years wrap around. I don't handle leap year here, will
1225 	|  get some email, then be safe for four more years...
1226 	*/
1227 	if (day < 0)
1228 		day = tm->tm_yday + ((yday < 365) ? 365 - yday : 0);
1229 
1230 	cur_slot = day * 24 + tm->tm_hour;
1231 	n = hour;
1232 	if (minute_chart)
1233 		{
1234 		cur_slot = cur_slot * 60 + tm->tm_min;
1235 		n = n * 60 + min;
1236 		}
1237 	skew = cur_slot - n;
1238 
1239 	gkrellm_reset_chart(cp);
1240 	for (n = 0; n < width; ++n)
1241 		{
1242 		if (fgets(data, sizeof(data), f) == NULL)
1243 			break;
1244 
1245 		if (skew >= cp->w)	/* All stored data is off the chart	*/
1246 			continue;
1247 
1248 		/* Use chart data storing routines to load in data so I don't care
1249 		|  if current chart width is less or greater than stored data width.
1250 		|  Charts will circular buff fill until data runs out.
1251 		*/
1252 		out = in = 0;
1253 		sscanf(data, "%d %d", &out, &in);
1254 		gkrellm_store_chartdata(cp, 0, out, in);
1255 		}
1256 	/* Need to store zero data for time slots not in read data to bring
1257 	|  the chart up to date wrt current time.  As in update_inet() I need
1258 	|  to skip slots for hour or minute ticks.
1259 	|  Warning: skew can be negative if quit gkrellm, change system clock
1260 	|  to earlier time, then restart gkrellm.
1261 	*/
1262 	if ((n = skew) < cp->w)		/* Do this only if some data was stored  */
1263 		{
1264 		while (n-- > 0)
1265 			{
1266 			gkrellm_store_chartdata(cp, 0, 0, 0);
1267 			if (minute_chart && min++ == 0)
1268 				{
1269 				gkrellm_store_chartdata(cp, 0, 0, 0);
1270 				gkrellm_store_chartdata(cp, 0, 0, 0);
1271 				if (min == 60)
1272 					min = 0;
1273 				}
1274 			else if (!minute_chart && hour++ == 0)
1275 				{
1276 				gkrellm_store_chartdata(cp, 0, 0, 0);
1277 				gkrellm_store_chartdata(cp, 0, 0, 0);
1278 				if (hour == 24)
1279 					hour = 0;
1280 				}
1281 			}
1282 		}
1283 	return skew;
1284 	}
1285 
1286 static void
write_inet_data(GkrellmChart * cp,FILE * f)1287 write_inet_data(GkrellmChart *cp, FILE *f)
1288 	{
1289 	GList	*list;
1290 	gint	n;
1291 
1292 	for (n = 0; n < cp->w; ++n)
1293 		{
1294 		for (list = cp->cd_list; list; list = list->next)
1295 			fprintf(f, "%d ",
1296 			   gkrellm_get_chartdata_data((GkrellmChartdata *) list->data, n));
1297 		fprintf(f, "\n");
1298 		}
1299 	}
1300 
1301 static gchar *
make_inet_data_fname(InetMon * in)1302 make_inet_data_fname(InetMon *in)
1303 	{
1304 	static gchar	idata_fname[256];
1305 	gchar			c_sep0, c_sep1;
1306 
1307 	c_sep0 = in->data0_is_range ? '-': '_';
1308 	c_sep1 = in->data1_is_range ? '-': '_';
1309 	snprintf(idata_fname, sizeof(idata_fname), "%s%cinet_%ld%c%ld_%ld%c%ld",
1310 		inet_data_dir, G_DIR_SEPARATOR,
1311 		in->port0_0, c_sep0, in->port0_1, in->port1_0, c_sep1, in->port1_1);
1312 	return idata_fname;
1313 	}
1314 
1315 void
gkrellm_inet_save_data(void)1316 gkrellm_inet_save_data(void)
1317 	{
1318 	FILE		*f;
1319 	struct tm	*tm;
1320 	GList		*list;
1321 	InetMon		*in;
1322 	gchar		*fname, buf[64];
1323 
1324 	tm = gkrellm_get_current_time();
1325 	for (list = inet_mon_list; list; list = list->next)
1326 		{
1327 		in = (InetMon *) list->data;
1328 		fname = make_inet_data_fname(in);
1329 		if ((f = g_fopen(fname, "w")) == NULL)
1330 			continue;
1331 
1332 		fputs("minute hour yday width\n", f);
1333 		snprintf(buf, sizeof(buf), "%d %d %d %d\n", tm->tm_min,
1334 				tm->tm_hour, tm->tm_yday, in->chart->w);
1335 		fputs(buf, f);
1336 
1337 		/* Save any accumulated hits which have not been stored into the
1338 		|  chart data array, and then save the chart data.
1339 		*/
1340 		fputs("hits0_minute hits1_minute hits0_hour hits1_hour\n", f);
1341 		fprintf(f, "%ld %ld %ld %ld\n",
1342 					in->hits0_minute, in->hits1_minute,
1343 					in->hits0_hour, in->hits1_hour);
1344 		write_inet_data(in->chart_minute, f);
1345 		write_inet_data(in->chart_hour, f);
1346 		fclose(f);
1347 		}
1348 	}
1349 
1350 void
gkrellm_inet_load_data(void)1351 gkrellm_inet_load_data(void)
1352 	{
1353 	FILE		*f;
1354 	GList		*list;
1355 	InetMon		*in;
1356 	gchar		buf[96], *fname;
1357 	gint		min, hour, yday, len, skew;
1358 
1359 	for (list = inet_mon_list; list; list = list->next)
1360 		{
1361 		in = (InetMon *) list->data;
1362 		fname = make_inet_data_fname(in);
1363 		if ((f = g_fopen(fname, "r")) == NULL)
1364 			{
1365 			gkrellm_reset_chart(in->chart);
1366 			draw_inet_chart(in);
1367 			continue;
1368 			}
1369 		fgets(buf, sizeof(buf), f);		/* Comment line */
1370 		fgets(buf, sizeof(buf), f);
1371 		sscanf(buf, "%d %d %d %d", &min, &hour, &yday, &len);
1372 		fgets(buf, sizeof(buf), f);		/* Comment line */
1373 		fgets(buf, sizeof(buf), f);
1374 		sscanf(buf, "%lu %lu %lu %lu",
1375 					&in->hits0_minute, &in->hits1_minute,
1376 					&in->hits0_hour, &in->hits1_hour);
1377 
1378 		skew = read_inet_data(in->chart_minute, f, 1, min, hour, yday, len);
1379 		if (skew > 0)  /* Current minute slot is different from saved */
1380 			in->hits0_minute = in->hits1_minute = 0;
1381 
1382 		skew = read_inet_data(in->chart_hour, f, 0, min, hour, yday, len);
1383 		if (skew > 0)  /* Current hour slot is different from saved */
1384 			in->hits0_hour = in->hits1_hour = 0;
1385 
1386 		fclose(f);
1387 		gkrellm_rescale_chart(in->chart);
1388 		}
1389 	}
1390 
1391 /* --------------------------------------------------------------------- */
1392 #define	DEFAULT_TEXT_FORMAT	"\\t$a\\f $l\\N$A\\f $L"
1393 
1394 enum
1395 	{
1396 	LABEL0_COLUMN,
1397 	PORT00_COLUMN,
1398 	PORT01_COLUMN,
1399 	RANGE0_COLUMN,
1400 	SPACER_COLUMN,
1401 	LABEL1_COLUMN,
1402 	PORT10_COLUMN,
1403 	PORT11_COLUMN,
1404 	RANGE1_COLUMN,
1405 	DUMMY_COLUMN,
1406 	INET_COLUMN,
1407 	N_COLUMNS
1408 	};
1409 
1410 static GtkTreeView	*treeview;
1411 static GtkTreeRowReference *row_reference;
1412 static GtkTreeSelection	*selection;
1413 
1414 
1415 static GtkWidget	*label0_entry,
1416 					*label1_entry;
1417 static GtkWidget	*port0_0_entry,
1418 					*port0_1_entry,
1419 					*port1_0_entry,
1420 					*port1_1_entry;
1421 
1422 static GtkWidget	*launch_vbox;
1423 
1424 static GtkWidget	*data0_range_button,
1425 					*data1_range_button;
1426 
1427 static GtkWidget	*text_format_combo_box;
1428 
1429 
1430 static void
set_list_store_model_data(GtkListStore * store,GtkTreeIter * iter,InetMon * in)1431 set_list_store_model_data(GtkListStore *store, GtkTreeIter *iter, InetMon *in)
1432 	{
1433 	gchar			p00[16], p01[16], p10[16], p11[16];
1434 
1435 	snprintf(p00, sizeof(p00), "%d", (int) in->port0_0);
1436 	snprintf(p01, sizeof(p01), "%d", (int) in->port0_1);
1437 	snprintf(p10, sizeof(p10), "%d", (int) in->port1_0);
1438 	snprintf(p11, sizeof(p11), "%d", (int) in->port1_1);
1439 	gtk_list_store_set(store, iter,
1440 			LABEL0_COLUMN, in->label0,
1441 			PORT00_COLUMN, p00,
1442 			PORT01_COLUMN, p01,
1443 			SPACER_COLUMN, "",
1444 			RANGE0_COLUMN, in->data0_is_range,
1445 			LABEL1_COLUMN, in->label1,
1446 			PORT10_COLUMN, p10,
1447 			PORT11_COLUMN, p11,
1448 			RANGE1_COLUMN, in->data1_is_range,
1449 			DUMMY_COLUMN, "",
1450 			-1);
1451 	}
1452 
1453 static GtkTreeModel *
create_model(void)1454 create_model(void)
1455 	{
1456 	GtkListStore	*store;
1457 	GtkTreeIter		iter;
1458 	GList			*list;
1459 	InetMon			*in;
1460 
1461 	store = gtk_list_store_new(N_COLUMNS,
1462 				G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN,
1463 				G_TYPE_STRING,
1464 				G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN,
1465 				G_TYPE_STRING, G_TYPE_POINTER);
1466 	for (list = inet_mon_list; list; list = list->next)
1467 		{
1468 		in = (InetMon *) list->data;
1469 		in->config_modified = FALSE;
1470 		gtk_list_store_append(store, &iter);
1471 		set_list_store_model_data(store, &iter, in);
1472 		gtk_list_store_set(store, &iter, INET_COLUMN, in, -1);
1473 		}
1474 	return GTK_TREE_MODEL(store);
1475 	}
1476 
1477 static void
change_row_reference(GtkTreeModel * model,GtkTreePath * path)1478 change_row_reference(GtkTreeModel *model, GtkTreePath *path)
1479 	{
1480 	gtk_tree_row_reference_free(row_reference);
1481 	if (model && path)
1482 		row_reference = gtk_tree_row_reference_new(model, path);
1483 	else
1484 		row_reference = NULL;
1485 	}
1486 
1487 static InetMon *
inet_new_from_model(GtkTreeModel * model,GtkTreeIter * iter,gchar * ports[])1488 inet_new_from_model(GtkTreeModel *model, GtkTreeIter *iter, gchar *ports[])
1489 	{
1490 	InetMon		*in;
1491 	gchar		*_ports[4];
1492 	gint		i;
1493 	gboolean	free_ports = FALSE;
1494 
1495 	if (!ports)
1496 		{
1497 		ports = _ports;
1498 		free_ports = TRUE;
1499 		}
1500 	in = g_new0(InetMon, 1);
1501 	gtk_tree_model_get(model, iter,
1502 			LABEL0_COLUMN, &in->label0,
1503 			PORT00_COLUMN, &ports[0],
1504 			PORT01_COLUMN, &ports[1],
1505 			RANGE0_COLUMN, &in->data0_is_range,
1506 			LABEL1_COLUMN, &in->label1,
1507 			PORT10_COLUMN, &ports[2],
1508 			PORT11_COLUMN, &ports[3],
1509 			RANGE1_COLUMN, &in->data1_is_range,
1510 			-1);
1511 	in->port0_0 = atoi(ports[0]);
1512 	in->port0_1 = atoi(ports[1]);
1513 	in->port1_0 = atoi(ports[2]);
1514 	in->port1_1 = atoi(ports[3]);
1515 	for (i = 0; i < 4 && free_ports; ++i)
1516 		g_free(ports[i]);
1517 
1518 	return in;
1519 	}
1520 
1521 static void
reset_entries(void)1522 reset_entries(void)
1523 	{
1524 	gtk_entry_set_text(GTK_ENTRY(label0_entry), "");
1525 	gtk_entry_set_text(GTK_ENTRY(port0_0_entry), "0");
1526 	gtk_entry_set_text(GTK_ENTRY(port0_1_entry), "0");
1527 	gtk_entry_set_text(GTK_ENTRY(label1_entry), "");
1528 	gtk_entry_set_text(GTK_ENTRY(port1_0_entry), "0");
1529 	gtk_entry_set_text(GTK_ENTRY(port1_1_entry), "0");
1530 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data0_range_button), 0);
1531 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data1_range_button), 0);
1532 
1533 	change_row_reference(NULL, NULL);
1534 	gtk_tree_selection_unselect_all(selection);
1535 	}
1536 
1537 
1538 static void
cb_tree_selection_changed(GtkTreeSelection * selection,gpointer data)1539 cb_tree_selection_changed(GtkTreeSelection *selection, gpointer data)
1540 	{
1541 	GtkTreeIter		iter;
1542 	GtkTreeModel	*model;
1543 	GtkTreePath		*path;
1544 	InetMon			*in;
1545 	gchar			*ports[4];
1546 	gint			i;
1547 
1548 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1549 		{
1550 		reset_entries();
1551 		return;
1552 		}
1553 	path = gtk_tree_model_get_path(model, &iter);
1554 	change_row_reference(model, path);
1555 	gtk_tree_path_free(path);
1556 
1557 	in = inet_new_from_model(model, &iter, ports);
1558 
1559 	gtk_entry_set_text(GTK_ENTRY(label0_entry), in->label0);
1560 	gtk_entry_set_text(GTK_ENTRY(port0_0_entry), ports[0]);
1561 	gtk_entry_set_text(GTK_ENTRY(port0_1_entry), ports[1]);
1562 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data0_range_button),
1563 			in->data0_is_range);
1564 
1565 	gtk_entry_set_text(GTK_ENTRY(label1_entry), in->label1);
1566 	gtk_entry_set_text(GTK_ENTRY(port1_0_entry), ports[2]);
1567 	gtk_entry_set_text(GTK_ENTRY(port1_1_entry), ports[3]);
1568 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data1_range_button),
1569 			in->data1_is_range);
1570 	g_free(in->label0);
1571 	g_free(in->label1);
1572 	for (i = 0; i < 4; ++i)
1573 		g_free(ports[i]);
1574 	}
1575 
1576 static void
cb_launch_entry(GtkWidget * widget,InetMon * in)1577 cb_launch_entry(GtkWidget *widget, InetMon *in)
1578 	{
1579 	gkrellm_apply_launcher(&in->launch_entry, &in->tooltip_entry,
1580 				in->panel, &in->launch, gkrellm_launch_button_cb);
1581     }
1582 
1583 static void
add_launch_entry(GtkWidget * vbox,InetMon * in)1584 add_launch_entry(GtkWidget *vbox, InetMon *in)
1585 	{
1586 	in->launch_table = gkrellm_gtk_launcher_table_new(vbox, 1);
1587 	gkrellm_gtk_config_launcher(in->launch_table, 0,  &in->launch_entry,
1588 				&in->tooltip_entry, in->name, &in->launch);
1589 	g_signal_connect(G_OBJECT(in->launch_entry), "changed",
1590 				G_CALLBACK(cb_launch_entry), in);
1591 	g_signal_connect(G_OBJECT(in->tooltip_entry), "changed",
1592 				G_CALLBACK(cb_launch_entry), in);
1593 	gtk_widget_show_all(in->launch_table);
1594 	}
1595 
1596 
1597 static void
sync_inet_list(void)1598 sync_inet_list(void)
1599 	{
1600 	GtkTreeModel	*model;
1601 	GtkTreeIter		iter;
1602 	InetMon			*in, *in_tmp;
1603 	GList			*list, *new_inet_list;
1604 
1605 	/* Just save all data and then later read it back in.  This avoids
1606 	|  complicated detecting of name changes while ports the same, moving
1607 	|  a inet down or up slots, etc.  Data is lost only if a port number
1608 	|  for a monitor is changed.
1609 	*/
1610 	gkrellm_inet_save_data();
1611 	new_inet_list = NULL;
1612 	n_inet_monitors = 0;
1613 
1614 	model = gtk_tree_view_get_model(treeview);
1615 	if (gtk_tree_model_get_iter_first(model, &iter))
1616 		{
1617 		do
1618 			{
1619 			in = inet_new_from_model(model, &iter, NULL);
1620 			new_inet_list = g_list_append(new_inet_list, in);
1621 			gtk_tree_model_get(model, &iter, INET_COLUMN, &in_tmp, -1);
1622 			fix_ports(in);
1623 
1624 			/* If an existing inet still has the same port numbers, preserve
1625 			|  its config.  Otherwise, it is same as making a new entry.
1626 			|  (plus the data layers could go from 2 to 1 and then there would
1627 			|   be an extra data layer in the config - not good).
1628 			*/
1629 			if (   in_tmp
1630 				&& in_tmp->port0_0 == in->port0_0
1631 				&& in_tmp->port0_1 == in->port0_1
1632 				&& in_tmp->port1_0 == in->port1_0
1633 				&& in_tmp->port1_1 == in->port1_1
1634 			   )
1635 				{
1636 				in->chart_config_minute = in_tmp->chart_config_minute;
1637 				in_tmp->chart_config_minute = NULL;
1638 				in->chart_config_hour = in_tmp->chart_config_hour;
1639 				in_tmp->chart_config_hour = NULL;
1640 				in->extra_info = in_tmp->extra_info;
1641 				in->hour_mode = in_tmp->hour_mode;
1642 				}
1643 			else
1644 				{
1645 				in->chart_config_minute = gkrellm_chartconfig_new0();
1646 				in->chart_config_hour = gkrellm_chartconfig_new0();
1647 				gkrellm_set_chartconfig_auto_grid_resolution(
1648 							in->chart_config_minute, TRUE);
1649 				gkrellm_set_chartconfig_auto_grid_resolution(
1650 							in->chart_config_hour, TRUE);
1651 				in->extra_info = TRUE;
1652 				}
1653 			if (in_tmp)
1654 				{
1655 				gkrellm_dup_string(&in->launch.command,
1656 							in_tmp->launch.command);
1657 				gkrellm_dup_string(&in->launch.tooltip_comment,
1658 							in_tmp->launch.tooltip_comment);
1659 				}
1660 			gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1661 						INET_COLUMN, in, -1);
1662 			}
1663 		while (gtk_tree_model_iter_next(model, &iter));
1664 		}
1665 	while (inet_mon_list)
1666 		{
1667 		in = (InetMon *) inet_mon_list->data;
1668 		destroy_inet_monitor(in);
1669 		inet_mon_list = g_list_remove(inet_mon_list, in);
1670 		}
1671 	inet_mon_list = new_inet_list;
1672 	for (list = inet_mon_list; list; list = list->next)
1673 		create_inet_monitor(inet_vbox, (InetMon *)list->data, TRUE);
1674 
1675 	gkrellm_inet_load_data();
1676 
1677 	for (list = inet_mon_list; list; list = list->next)
1678 		{
1679 		in = (InetMon *) list->data;
1680 		draw_inet_chart(in);
1681 		add_launch_entry(launch_vbox, in);
1682 		}
1683 	if (inet_mon_list)
1684 		gkrellm_spacers_show(mon_inet);
1685 	else
1686 		gkrellm_spacers_hide(mon_inet);
1687 	}
1688 
1689 static gboolean
cb_drag_end(GtkWidget * widget,GdkDragContext * context,gpointer data)1690 cb_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
1691 	{
1692 	reset_entries();
1693 	sync_inet_list();
1694 	return FALSE;
1695 	}
1696 
1697 static void
cb_enter(GtkWidget * widget,gpointer data)1698 cb_enter(GtkWidget *widget, gpointer data)
1699 	{
1700 	GtkTreeModel	*model;
1701 	GtkTreePath		*path = NULL;
1702 	GtkTreeIter		iter;
1703 	InetMon			*in;
1704 
1705 	in = g_new0(InetMon, 1);
1706 
1707 	in->data0_is_range = GTK_TOGGLE_BUTTON(data0_range_button)->active;
1708 	in->data1_is_range = GTK_TOGGLE_BUTTON(data1_range_button)->active;
1709 
1710 	in->label0 = gkrellm_gtk_entry_get_text(&label0_entry);
1711 	if (*(in->label0))
1712 		{
1713 		in->port0_0 = atoi(gkrellm_gtk_entry_get_text(&port0_0_entry));
1714 		in->port0_1 = atoi(gkrellm_gtk_entry_get_text(&port0_1_entry));
1715 		}
1716 	in->label1 = gkrellm_gtk_entry_get_text(&label1_entry);
1717 	if (*(in->label1))
1718 		{
1719 		in->port1_0 = atoi(gkrellm_gtk_entry_get_text(&port1_0_entry));
1720 		in->port1_1 = atoi(gkrellm_gtk_entry_get_text(&port1_1_entry));
1721 		}
1722 
1723 	/* Validate the values
1724 	*/
1725 	if (   (!*(in->label0) && !*(in->label1))
1726 		|| (*(in->label0) && in->port0_0 == 0 && in->port0_1 == 0)
1727 		|| (*(in->label1) && in->port1_0 == 0 && in->port1_1 == 0)
1728 	   )
1729 		{
1730 		g_free(in);
1731 		return;
1732 		}
1733 
1734 	model = gtk_tree_view_get_model(treeview);
1735 	if (row_reference)
1736 		{
1737 		path = gtk_tree_row_reference_get_path(row_reference);
1738 		gtk_tree_model_get_iter(model, &iter, path);
1739 		}
1740 	else
1741 		{
1742 		gtk_list_store_append(GTK_LIST_STORE(model), &iter);
1743 		gtk_list_store_set(GTK_LIST_STORE(model), &iter, INET_COLUMN, NULL,-1);
1744 		}
1745 	in->config_modified = TRUE;
1746 	set_list_store_model_data(GTK_LIST_STORE(model), &iter, in);
1747 	g_free(in);
1748 	reset_entries();
1749 	sync_inet_list();
1750 	}
1751 
1752 static void
cb_delete(GtkWidget * widget,gpointer data)1753 cb_delete(GtkWidget *widget, gpointer data)
1754 	{
1755 	GtkTreeModel	*model;
1756 	GtkTreePath		*path;
1757 	GtkTreeIter		iter;
1758 
1759 	if (!row_reference)
1760 		return;
1761 	model = gtk_tree_view_get_model(treeview);
1762 	path = gtk_tree_row_reference_get_path(row_reference);
1763 	gtk_tree_model_get_iter(model, &iter, path);
1764 	gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1765 
1766 	reset_entries();
1767 	sync_inet_list();
1768 	}
1769 
1770 static void
cb_text_format(GtkWidget * widget,gpointer data)1771 cb_text_format(GtkWidget *widget, gpointer data)
1772 	{
1773 	GList   *list;
1774 	gchar   *s;
1775 	GtkWidget *entry;
1776 
1777 	entry = gtk_bin_get_child(GTK_BIN(text_format_combo_box));
1778 	s = gkrellm_gtk_entry_get_text(&entry);
1779 	gkrellm_locale_dup_string(&text_format, s, &text_format_locale);
1780 	for (list = inet_mon_list; list; list = list->next)
1781 		draw_inet_chart((InetMon *) list->data);
1782 	}
1783 
1784 static void
cb_update_interval(GtkWidget * entry,GtkSpinButton * spin)1785 cb_update_interval(GtkWidget *entry, GtkSpinButton *spin)
1786     {
1787     update_interval = gtk_spin_button_get_value_as_int(spin);
1788     }
1789 
1790 static gchar	*inet_info_text[] =
1791 {
1792 N_("Inet charts show historical TCP port hits on a minute or hourly\n"
1793 	"chart. Below the chart there is a strip where marks are drawn for\n"
1794 	"port hits in second intervals.   The inet krell has a full scale\n"
1795 	"value of 5 hits and samples once per second.  The extra info\n"
1796 	"display shows current TCP port connections.\n\n"
1797 	"For each internet monitor, you can specify two labeled data sets with\n"
1798 	"one or two non-zero port numbers entered for each data set.  Two\n"
1799 	"ports are allowed because some internet ports are related and you\n"
1800 	"might want to group them.  Check /etc/services for port numbers.\n\n"
1801 	"For example, if you created an inet monitor:\n"),
1802 
1803 N_("<i>\thttp 80 8080   ftp 21\n"),
1804 
1805 N_("Http hits on the standard http port 80 and www web caching service\n"
1806 	"on port 8080 are combined and plotted in the one color.  Ftp hits\n"
1807 	"on the single ftp port 21 are plotted in another color.\n\n"),
1808 
1809 N_("If the range button is checked, then all port numbers between Port0 and\n"
1810    "Port1 are monitored and included in the plot.\n\n"),
1811 
1812 N_("<h>Chart Labels\n"),
1813 N_("Substitution variables for the format string for chart labels:\n"),
1814 N_("\t$M    maximum chart value\n"),
1815 N_("\t$a    current active connections for Data0\n"),
1816 N_("\t$cN   total connections in last N minutes (or hours) for Data0\n"),
1817 N_("\t$l    label for Data0\n"),
1818 N_("\t$A    current active connections for Data1\n"),
1819 N_("\t$CN   total connections in last N minutes (or hours) for Data1\n"),
1820 N_("\t$L    label for Data1\n"),
1821 
1822 "\n",
1823 N_("<h>Mouse Button Actions:\n"),
1824 N_("<b>\tLeft "),
1825 N_("click on an inet chart to toggle the extra info display of\n"
1826 	"\t\tcurrent TCP port connections.\n"),
1827 N_("<b>\tMiddle "),
1828 N_("click on an inet chart to toggle hour/minute charts.\n")
1829 };
1830 
1831 
1832 static void
create_inet_tab(GtkWidget * tab_vbox)1833 create_inet_tab(GtkWidget *tab_vbox)
1834 	{
1835 	GtkWidget		*tabs;
1836 	GtkWidget		*table;
1837 	GtkWidget		*hbox, *vbox, *vbox1;
1838 	GtkWidget		*separator;
1839 	GtkWidget		*scrolled;
1840 	GtkWidget		*text;
1841 	GtkWidget		*label;
1842 	GtkWidget		*button;
1843 	GtkTreeModel	*model;
1844 	GtkCellRenderer	*renderer;
1845 	GList			*list;
1846 	InetMon			*in;
1847 	gint			i;
1848 
1849 	row_reference = NULL;
1850 
1851 	tabs = gtk_notebook_new();
1852 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
1853 	gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
1854 
1855 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Ports"));
1856 
1857 	table = gtk_table_new(6, 7, FALSE /*homogeneous*/);
1858 	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1859 	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 3);
1860 
1861 	label = gtk_label_new(_("Data0"));
1862 	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 0, 1);
1863 	separator = gtk_hseparator_new();
1864 	gtk_table_attach_defaults(GTK_TABLE(table), separator, 0, 3, 1, 2);
1865 	label = gtk_label_new(_("Data1"));
1866 	gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 7, 0, 1);
1867 	separator = gtk_hseparator_new();
1868 	gtk_table_attach_defaults(GTK_TABLE(table), separator, 4, 7, 1, 2);
1869 
1870 	separator = gtk_vseparator_new();
1871 	gtk_table_attach_defaults(GTK_TABLE(table), separator, 3, 4, 0, 6);
1872 
1873 	label = gtk_label_new(_("Label"));
1874 	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
1875 	label = gtk_label_new(_("Port0"));
1876 	gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
1877 	label = gtk_label_new(_("Port1"));
1878 	gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 2, 3);
1879 	label = gtk_label_new(_("Label"));
1880 	gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 5, 2, 3);
1881 	label = gtk_label_new(_("Port0"));
1882 	gtk_table_attach_defaults(GTK_TABLE(table), label, 5, 6, 2, 3);
1883 	label = gtk_label_new(_("Port1"));
1884 	gtk_table_attach_defaults(GTK_TABLE(table), label, 6, 7, 2, 3);
1885 
1886 	label0_entry = gtk_entry_new();
1887 	gtk_entry_set_max_length(GTK_ENTRY(label0_entry), 8);
1888 	gtk_widget_set_size_request(label0_entry, 32, -1);
1889 	gtk_table_attach_defaults(GTK_TABLE(table), label0_entry, 0, 1, 3, 4);
1890 	port0_0_entry = gtk_entry_new();
1891 	gtk_entry_set_max_length(GTK_ENTRY(port0_0_entry), 8);
1892 	gtk_widget_set_size_request(port0_0_entry, 32, -1);
1893 	gtk_table_attach_defaults(GTK_TABLE(table), port0_0_entry, 1, 2, 3, 4);
1894 	port0_1_entry = gtk_entry_new();
1895 	gtk_entry_set_max_length(GTK_ENTRY(port0_1_entry), 8);
1896 	gtk_widget_set_size_request(port0_1_entry, 32, -1);
1897 	gtk_table_attach_defaults(GTK_TABLE(table), port0_1_entry, 2, 3, 3, 4);
1898 
1899 	label1_entry = gtk_entry_new();
1900 	gtk_entry_set_max_length(GTK_ENTRY(label1_entry), 8);
1901 	gtk_widget_set_size_request(label1_entry, 32, -1);
1902 	gtk_table_attach_defaults(GTK_TABLE(table), label1_entry, 4, 5, 3, 4);
1903 	port1_0_entry = gtk_entry_new();
1904 	gtk_entry_set_max_length(GTK_ENTRY(port1_0_entry), 8);
1905 	gtk_widget_set_size_request(port1_0_entry, 32, -1);
1906 	gtk_table_attach_defaults(GTK_TABLE(table), port1_0_entry, 5, 6, 3, 4);
1907 	port1_1_entry = gtk_entry_new();
1908 	gtk_entry_set_max_length(GTK_ENTRY(port1_1_entry), 8);
1909 	gtk_widget_set_size_request(port1_1_entry, 32, -1);
1910 	gtk_table_attach_defaults(GTK_TABLE(table), port1_1_entry, 6, 7, 3, 4);
1911 
1912 	hbox = gtk_hbox_new(FALSE, 2);
1913 	gtk_table_attach_defaults(GTK_TABLE(table), hbox, 0, 3, 4, 5);
1914 	gkrellm_gtk_check_button(hbox, &data0_range_button, 0, TRUE, 0,
1915 		_("Port0 - Port1 is a range"));
1916 
1917 	hbox = gtk_hbox_new(FALSE, 2);
1918 	gtk_table_attach_defaults(GTK_TABLE(table), hbox, 4, 7, 4, 5);
1919 	gkrellm_gtk_check_button(hbox, &data1_range_button, 0, TRUE, 0,
1920 		_("Port0 - Port1 is a range"));
1921 
1922 	separator = gtk_hseparator_new();
1923 	gtk_table_attach_defaults(GTK_TABLE(table), separator, 0, 7, 5, 6);
1924 
1925 	hbox = gtk_hbutton_box_new();
1926 	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
1927 	gtk_box_set_spacing(GTK_BOX(hbox), 5);
1928 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1929 
1930 	button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1931 	g_signal_connect(G_OBJECT(button), "clicked",
1932 			G_CALLBACK(cb_delete), NULL);
1933 	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1934 
1935 	/* everybody knows about CNTL click, right? */
1936 //	button = gtk_button_new_from_stock(GTK_STOCK_NEW);
1937 //	g_signal_connect(G_OBJECT(button), "clicked",
1938 //			G_CALLBACK(reset_entries), NULL);
1939 //	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1940 
1941 	button = gtk_button_new_from_stock(GTK_STOCK_ADD);
1942 	g_signal_connect(G_OBJECT(button), "clicked",
1943 			G_CALLBACK(cb_enter), NULL);
1944 	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1945 
1946 	separator = gtk_hseparator_new();
1947 	gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 2);
1948 
1949 	scrolled = gtk_scrolled_window_new(NULL, NULL);
1950 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1951 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1952 	gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
1953 
1954 
1955 	model = create_model();
1956 	treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
1957 	g_object_unref(G_OBJECT(model));
1958 	gtk_tree_view_set_rules_hint(treeview, TRUE);
1959 	gtk_tree_view_set_reorderable(treeview, TRUE);
1960 	g_signal_connect(G_OBJECT(treeview), "drag_end",
1961 				G_CALLBACK(cb_drag_end), NULL);
1962 
1963 	renderer = gtk_cell_renderer_text_new();
1964 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Label"),
1965 				renderer,
1966 				"text", LABEL0_COLUMN, NULL);
1967 	renderer = gtk_cell_renderer_text_new();
1968 	g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1969 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Port0"),
1970 				renderer,
1971 				"text", PORT00_COLUMN, NULL);
1972 	renderer = gtk_cell_renderer_text_new();
1973 	g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1974 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Port1"),
1975 				renderer,
1976 				"text", PORT01_COLUMN, NULL);
1977 
1978 	renderer = gtk_cell_renderer_text_new();
1979 	gtk_tree_view_insert_column_with_attributes(treeview, -1, "    ",
1980 				renderer,
1981 				"text", SPACER_COLUMN, NULL);
1982 
1983 	renderer = gtk_cell_renderer_text_new();
1984 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Label"),
1985 				renderer,
1986 				"text", LABEL1_COLUMN, NULL);
1987 	renderer = gtk_cell_renderer_text_new();
1988 	g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1989 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Port0"),
1990 				renderer,
1991 				"text", PORT10_COLUMN, NULL);
1992 	renderer = gtk_cell_renderer_text_new();
1993 	g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1994 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Port1"),
1995 				renderer,
1996 				"text", PORT11_COLUMN, NULL);
1997 
1998 	renderer = gtk_cell_renderer_text_new();
1999 	gtk_tree_view_insert_column_with_attributes(treeview, -1, "    ",
2000 				renderer,
2001 				"text", DUMMY_COLUMN, NULL);
2002 
2003 
2004 	gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
2005 	selection = gtk_tree_view_get_selection(treeview);
2006 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
2007 	g_signal_connect(G_OBJECT(selection), "changed",
2008 				G_CALLBACK(cb_tree_selection_changed), NULL);
2009 
2010 /* --Setup tab */
2011 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Setup"));
2012 
2013 	if (!_GK.client_mode)
2014 		gkrellm_gtk_spin_button(vbox, NULL,
2015 					(gfloat) update_interval, 1, 20, 1, 1, 0, 55,
2016             		cb_update_interval, NULL, FALSE,
2017             		_("Seconds between updates"));
2018 
2019 	label = gtk_label_new("");	/* padding */
2020 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
2021 
2022 	vbox1 = gkrellm_gtk_category_vbox(vbox,
2023 				_("Format String for Chart Labels"),
2024 				4, 0, TRUE);
2025 
2026 	text_format_combo_box = gtk_combo_box_entry_new_text();
2027 	gtk_box_pack_start(GTK_BOX(vbox1), text_format_combo_box, FALSE, FALSE, 2);
2028 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
2029 			text_format);
2030 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
2031 			DEFAULT_TEXT_FORMAT);
2032 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
2033 			"\\r\\f $M\\t$a\\f $l\\N$A\\f $L");
2034 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
2035 			"\\r\\f $M\\D1$a\\f $l\\D2$A\\f $L");
2036 	gtk_combo_box_set_active(GTK_COMBO_BOX(text_format_combo_box), 0);
2037 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(text_format_combo_box)), "changed",
2038 			G_CALLBACK(cb_text_format), NULL);
2039 
2040 	vbox1 = gkrellm_gtk_category_vbox(vbox,
2041 				_("Launch Commands"),
2042 				4, 0, TRUE);
2043 	launch_vbox = gkrellm_gtk_scrolled_vbox(vbox1, NULL,
2044 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2045 	gtk_widget_show(launch_vbox);
2046 	gtk_widget_realize(launch_vbox);
2047 	for (i = 0, list = inet_mon_list; list; list = list->next, ++i)
2048 		{
2049 		in = (InetMon *) list->data;
2050 		add_launch_entry(launch_vbox, in);
2051 		}
2052 
2053 /* --Info tab */
2054 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Info"));
2055 	text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
2056 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2057 	for (i = 0; i < sizeof(inet_info_text)/sizeof(gchar *); ++i)
2058 		gkrellm_gtk_text_view_append(text, _(inet_info_text[i]));
2059 
2060 	reset_entries();
2061 	}
2062 
2063 
2064 
2065 static GkrellmMonitor	monitor_inet =
2066 	{
2067 	N_("Internet"),			/* Name, for config tab.	*/
2068 	MON_INET,			/* Id,  0 if a plugin		*/
2069 	create_inet,		/* The create function		*/
2070 	update_inet,		/* The update function		*/
2071 	create_inet_tab,	/* The config tab create function	*/
2072 	NULL,				/* Instant apply	*/
2073 
2074 	save_inet_config,	/* Save user conifg			*/
2075 	load_inet_config,	/* Load user config			*/
2076 	"inet",				/* config keyword			*/
2077 
2078 	NULL,				/* Undef 2	*/
2079 	NULL,				/* Undef 1	*/
2080 	NULL,				/* Undef 0	*/
2081 
2082 	0,					/* insert_before_id - place plugin before this mon */
2083 
2084 	NULL,				/* Handle if a plugin, filled in by GKrellM		*/
2085 	NULL				/* path if a plugin, filled in by GKrellM		*/
2086 	};
2087 
2088 GkrellmMonitor *
gkrellm_init_inet_monitor(void)2089 gkrellm_init_inet_monitor(void)
2090 	{
2091 	monitor_inet.name = _(monitor_inet.name);
2092 	style_id = gkrellm_add_chart_style(&monitor_inet, INET_STYLE_NAME);
2093 	gkrellm_locale_dup_string(&text_format, DEFAULT_TEXT_FORMAT,
2094 					&text_format_locale);
2095 	mon_inet = &monitor_inet;
2096 	if (setup_inet_interface())
2097 		{	/* Make the "data-suffix/inet" directory */
2098 		inet_data_dir = gkrellm_make_data_file_name("inet", NULL);
2099 		return &monitor_inet;
2100 		}
2101 	return NULL;
2102 	}
2103