HACK: 1. try to match RowsetProperties
[wireshark-wip.git] / ui / gtk / hostlist_table.c
blobcdd939d1a45a9a52956d8ddc91b2af72782d22b4
1 /* hostlist_table.c 2004 Ian Schorr
2 * modified from endpoint_talkers_table.c 2003 Ronnie Sahlberg
3 * Helper routines common to all host list taps.
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <locale.h>
34 #include <gtk/gtk.h>
36 #include <epan/packet_info.h>
37 #include <epan/to_str.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/tap.h>
40 #include <epan/strutil.h>
41 #ifdef HAVE_GEOIP
42 #include <GeoIP.h>
43 #include <epan/geoip_db.h>
44 #include <wsutil/pint.h>
45 #include <epan/filesystem.h>
46 #endif
48 #include <wsutil/file_util.h>
50 #include "ui/simple_dialog.h"
51 #include "ui/alert_box.h"
52 #include "ui/utf8_entities.h"
53 #include "wsutil/tempfile.h"
55 #include "ui/gtk/hostlist_table.h"
56 #include "ui/gtk/filter_utils.h"
57 #include "ui/gtk/gtkglobals.h"
59 #include "ui/gtk/gui_utils.h"
60 #include "ui/gtk/dlg_utils.h"
61 #include "ui/gtk/help_dlg.h"
62 #include "ui/gtk/main.h"
63 #ifdef HAVE_GEOIP
64 #include "ui/gtk/webbrowser.h"
65 #include "ui/gtk/stock_icons.h"
66 #endif
68 #include "ui/gtk/old-gtk-compat.h"
70 #define HOST_PTR_KEY "hostlist-pointer"
71 #define NB_PAGES_KEY "notebook-pages"
72 #define HL_DLG_HEIGHT 550
74 #define CMP_INT(i1, i2) \
75 if ((i1) > (i2)) \
76 return 1; \
77 else if ((i1) < (i2)) \
78 return -1; \
79 else \
80 return 0;
82 #define COL_STR_LEN 32
84 /* convert a port number into a string */
85 static char *
86 hostlist_port_to_str(int port_type_val, guint32 port)
88 static int i=0;
89 static gchar *strp, str[4][12];
90 gchar *bp;
92 switch(port_type_val){
93 case PT_TCP:
94 case PT_UDP:
95 case PT_SCTP:
96 i = (i+1)%4;
97 strp=str[i];
98 bp = &strp[11];
100 *bp = 0;
101 do {
102 *--bp = (port % 10) +'0';
103 } while ((port /= 10) != 0 && bp > strp);
104 return bp;
106 return NULL;
110 #define FN_ANY_ADDRESS 0
111 #define FN_ANY_PORT 1
113 /* Given an address (to distinguish between ipv4 and ipv6 for tcp/udp,
114 a port_type and a name_type (FN_...)
115 return a string for the filter name.
117 Some addresses, like AT_ETHER may actually be any of multiple types
118 of protocols, either ethernet, tokenring, fddi etc so we must be more
119 specific there; that's why we need specific_addr_type.
121 static const char *
122 hostlist_get_filter_name(address *addr, int specific_addr_type_val, int port_type_val, int name_type_val)
124 switch(name_type_val){
125 case FN_ANY_ADDRESS:
126 switch(addr->type){
127 case AT_ETHER:
128 switch(specific_addr_type_val){
129 case SAT_ETHER:
130 return "eth.addr";
131 case SAT_WLAN:
132 return "wlan.addr";
133 case SAT_FDDI:
134 return "fddi.addr";
135 case SAT_TOKENRING:
136 return "tr.addr";
137 default:
138 break;
140 break;
141 case AT_IPv4:
142 return "ip.addr";
143 case AT_IPv6:
144 return "ipv6.addr";
145 case AT_IPX:
146 return "ipx.addr";
147 case AT_FC:
148 return "fc.id";
149 case AT_URI:
150 switch(specific_addr_type_val){
151 case SAT_JXTA:
152 return "jxta.message.address";
153 default:
154 break;
156 break;
157 case AT_USB:
158 return "usb.addr";
159 default:
160 break;
162 break;
163 case FN_ANY_PORT:
164 switch(port_type_val){
165 case PT_TCP:
166 return "tcp.port";
167 case PT_UDP:
168 return "udp.port";
169 case PT_SCTP:
170 return "sctp.port";
172 break;
175 g_assert_not_reached();
176 return NULL;
179 static void
180 reset_hostlist_table_data(hostlist_table *hosts)
182 guint32 i;
183 char *display_name;
184 char title[256];
185 GString *error_string;
186 const char *filter;
187 GtkListStore *store;
189 if (hosts->use_dfilter) {
190 filter = gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
191 } else {
192 filter = hosts->filter;
194 error_string = set_tap_dfilter (hosts, filter);
195 if (error_string) {
196 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
197 g_string_free(error_string, TRUE);
198 return;
202 if(hosts->page_lb) {
203 display_name = cf_get_display_name(&cfile);
204 g_snprintf(title, sizeof(title), "Endpoints: %s", display_name);
205 g_free(display_name);
206 gtk_window_set_title(GTK_WINDOW(hosts->win), title);
207 g_snprintf(title, sizeof(title), "%s", hosts->name);
208 gtk_label_set_text(GTK_LABEL(hosts->page_lb), title);
209 gtk_widget_set_sensitive(hosts->page_lb, FALSE);
211 if (hosts->use_dfilter) {
212 if (filter && strlen(filter)) {
213 g_snprintf(title, sizeof(title), "%s Endpoints - Filter: %s", hosts->name, filter);
214 } else {
215 g_snprintf(title, sizeof(title), "%s Endpoints - No Filter", hosts->name);
217 } else {
218 g_snprintf(title, sizeof(title), "%s Endpoints", hosts->name);
220 gtk_label_set_text(GTK_LABEL(hosts->name_lb), title);
221 } else {
222 display_name = cf_get_display_name(&cfile);
223 g_snprintf(title, sizeof(title), "%s Endpoints: %s", hosts->name, display_name);
224 g_free(display_name);
225 gtk_window_set_title(GTK_WINDOW(hosts->win), title);
228 /* remove all entries from the list */
229 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(hosts->table)));
230 gtk_list_store_clear(store);
232 /* delete all hosts */
233 for(i=0;i<hosts->num_hosts;i++){
234 hostlist_talker_t *host = &g_array_index(hosts->hosts, hostlist_talker_t, i);
235 g_free((gpointer)host->myaddress.data);
238 if (hosts->hosts)
239 g_array_free(hosts->hosts, TRUE);
241 if (hosts->hashtable != NULL)
242 g_hash_table_destroy(hosts->hashtable);
244 hosts->hosts=NULL;
245 hosts->hashtable=NULL;
246 hosts->num_hosts=0;
249 static void
250 reset_hostlist_table_data_cb(void *arg)
252 reset_hostlist_table_data((hostlist_table *)arg);
255 static void
256 hostlist_win_destroy_cb(GtkWindow *win _U_, gpointer data)
258 hostlist_table *hosts=(hostlist_table *)data;
260 remove_tap_listener(hosts);
262 reset_hostlist_table_data(hosts);
263 g_free(hosts);
266 enum
268 ADR_COLUMN,
269 PORT_COLUMN,
270 PACKETS_COLUMN,
271 BYTES_COLUMN,
272 PKT_AB_COLUMN,
273 BYTES_AB_COLUMN,
274 PKT_BA_COLUMN,
275 BYTES_BA_COLUMN,
276 #ifdef HAVE_GEOIP
277 GEOIP1_COLUMN,
278 GEOIP2_COLUMN,
279 GEOIP3_COLUMN,
280 GEOIP4_COLUMN,
281 GEOIP5_COLUMN,
282 GEOIP6_COLUMN,
283 GEOIP7_COLUMN,
284 GEOIP8_COLUMN,
285 GEOIP9_COLUMN,
286 GEOIP10_COLUMN,
287 GEOIP11_COLUMN,
288 GEOIP12_COLUMN,
289 GEOIP13_COLUMN,
290 #endif
291 INDEX_COLUMN,
292 N_COLUMNS
295 static gint
296 hostlist_sort_column(GtkTreeModel *model,
297 GtkTreeIter *a,
298 GtkTreeIter *b,
299 gpointer user_data)
302 guint32 idx1, idx2;
303 gint data_column = GPOINTER_TO_INT(user_data);
304 hostlist_table *hl = (hostlist_table *)g_object_get_data(G_OBJECT(model), HOST_PTR_KEY);
305 hostlist_talker_t *host1 = NULL;
306 hostlist_talker_t *host2 = NULL;
308 gtk_tree_model_get(model, a, INDEX_COLUMN, &idx1, -1);
309 gtk_tree_model_get(model, b, INDEX_COLUMN, &idx2, -1);
311 if (!hl || idx1 >= hl->num_hosts || idx2 >= hl->num_hosts)
312 return 0;
314 host1 = &g_array_index(hl->hosts, hostlist_talker_t, idx1);
315 host2 = &g_array_index(hl->hosts, hostlist_talker_t, idx2);
317 switch(data_column){
318 case 0: /* Address */
319 return(CMP_ADDRESS(&host1->myaddress, &host2->myaddress));
320 case 1: /* (Port) */
321 CMP_INT(host1->port, host2->port);
322 #ifdef HAVE_GEOIP
323 default:
325 gchar *text1, *text2;
326 double loc1 = 0, loc2 = 0;
328 gtk_tree_model_get(model, a, data_column, &text1, -1);
329 gtk_tree_model_get(model, b, data_column, &text2, -1);
331 if (text1) {
332 loc1 = atof(text1);
333 g_free(text1);
336 if (text2) {
337 loc2 = atof(text2);
338 g_free(text2);
340 CMP_INT(loc1, loc2);
342 break;
343 #endif
345 g_assert_not_reached();
346 return 0;
349 static void
350 hostlist_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data, guint callback_action)
352 guint idx;
353 hostlist_table *hl=(hostlist_table *)callback_data;
354 char *str = NULL;
355 char *sport;
356 GtkTreeIter iter;
357 GtkTreeModel *model;
358 GtkTreeSelection *sel;
359 hostlist_talker_t *host = NULL;
361 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(hl->table));
362 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
363 return;
365 gtk_tree_model_get (model, &iter,
366 INDEX_COLUMN, &idx,
367 -1);
369 if(idx>= hl->num_hosts){
370 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No hostlist selected");
371 return;
373 host = &g_array_index(hl->hosts, hostlist_talker_t, idx);
375 sport=hostlist_port_to_str(host->port_type, host->port);
377 str = g_strdup_printf("%s==%s%s%s%s%s",
378 hostlist_get_filter_name(&host->myaddress, host->sat, host->port_type, FN_ANY_ADDRESS),
379 ep_address_to_str(&host->myaddress),
380 sport?" && ":"",
381 sport?hostlist_get_filter_name(&host->myaddress, host->sat, host->port_type, FN_ANY_PORT):"",
382 sport?"==":"",
383 sport?sport:"");
385 apply_selected_filter (callback_action, str);
387 g_free (str);
389 static gboolean
390 hostlist_show_popup_menu_cb(void *widg _U_, GdkEvent *event, hostlist_table *et)
392 GdkEventButton *bevent = (GdkEventButton *)event;
394 if(event->type==GDK_BUTTON_PRESS && bevent->button==3){
395 gtk_menu_popup(GTK_MENU(et->menu), NULL, NULL, NULL, NULL,
396 bevent->button, bevent->time);
399 return FALSE;
402 /* Action callbacks */
403 static void
404 apply_as_selected_cb(GtkWidget *widget, gpointer user_data)
406 hostlist_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_SELECTED, 0));
408 static void
409 apply_as_not_selected_cb(GtkWidget *widget, gpointer user_data)
411 hostlist_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_NOT_SELECTED, 0));
413 static void
414 apply_as_and_selected_cb(GtkWidget *widget, gpointer user_data)
416 hostlist_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_AND_SELECTED, 0));
418 static void
419 apply_as_or_selected_cb(GtkWidget *widget, gpointer user_data)
421 hostlist_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_OR_SELECTED, 0));
423 static void
424 apply_as_and_not_selected_cb(GtkWidget *widget, gpointer user_data)
426 hostlist_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_AND_NOT_SELECTED, 0));
428 static void
429 apply_as_or_not_selected_cb(GtkWidget *widget, gpointer user_data)
431 hostlist_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_OR_NOT_SELECTED, 0));
434 static void
435 prep_as_selected_cb(GtkWidget *widget, gpointer user_data)
437 hostlist_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_SELECTED, 0));
439 static void
440 prep_as_not_selected_cb(GtkWidget *widget, gpointer user_data)
442 hostlist_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_NOT_SELECTED, 0));
444 static void
445 prep_as_and_selected_cb(GtkWidget *widget, gpointer user_data)
447 hostlist_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_AND_SELECTED, 0));
449 static void
450 prep_as_or_selected_cb(GtkWidget *widget, gpointer user_data)
452 hostlist_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_OR_SELECTED, 0));
454 static void
455 prep_as_and_not_selected_cb(GtkWidget *widget, gpointer user_data)
457 hostlist_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_AND_NOT_SELECTED, 0));
459 static void
460 prep_as_or_not_selected_cb(GtkWidget *widget, gpointer user_data)
462 hostlist_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_OR_NOT_SELECTED, 0));
465 static void
466 find_selected_cb(GtkWidget *widget, gpointer user_data)
468 hostlist_select_filter_cb( widget , user_data, CALLBACK_FIND_FRAME(ACTYPE_SELECTED, 0));
470 static void
471 find_not_selected_cb(GtkWidget *widget, gpointer user_data)
473 hostlist_select_filter_cb( widget , user_data, CALLBACK_FIND_FRAME(ACTYPE_NOT_SELECTED, 0));
475 static void
476 find_prev_selected_cb(GtkWidget *widget, gpointer user_data)
478 hostlist_select_filter_cb( widget , user_data, CALLBACK_FIND_PREVIOUS(ACTYPE_SELECTED, 0));
480 static void
481 find_prev_not_selected_cb(GtkWidget *widget, gpointer user_data)
483 hostlist_select_filter_cb( widget , user_data, CALLBACK_FIND_PREVIOUS(ACTYPE_NOT_SELECTED, 0));
485 static void
486 find_next_selected_cb(GtkWidget *widget, gpointer user_data)
488 hostlist_select_filter_cb( widget , user_data, CALLBACK_FIND_NEXT(ACTYPE_SELECTED, 0));
490 static void
491 find_next_not_selected_cb(GtkWidget *widget, gpointer user_data)
493 hostlist_select_filter_cb( widget , user_data, CALLBACK_FIND_NEXT(ACTYPE_NOT_SELECTED, 0));
495 static void
496 color_selected_cb(GtkWidget *widget, gpointer user_data)
498 hostlist_select_filter_cb( widget , user_data, CALLBACK_COLORIZE(ACTYPE_SELECTED, 0));
501 static const char *ui_desc_hostlist_table_popup =
502 "<ui>\n"
503 " <popup name='HostlistTableFilterPopup'>\n"
504 " <menu action='/Apply as Filter'>\n"
505 " <menuitem action='/Apply as Filter/Selected'/>\n"
506 " <menuitem action='/Apply as Filter/Not Selected'/>\n"
507 " <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected'/>\n"
508 " <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected'/>\n"
509 " <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected'/>\n"
510 " <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected'/>\n"
511 " </menu>\n"
512 " <menu action='/Prepare a Filter'>\n"
513 " <menuitem action='/Prepare a Filter/Selected'/>\n"
514 " <menuitem action='/Prepare a Filter/Not Selected'/>\n"
515 " <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected'/>\n"
516 " <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected'/>\n"
517 " <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected'/>\n"
518 " <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected'/>\n"
519 " </menu>\n"
520 " <menu action='/Find Frame'>\n"
521 " <menu action='/Find Frame/Find Frame'>\n"
522 " <menuitem action='/Find Frame/Selected'/>\n"
523 " <menuitem action='/Find Frame/Not Selected'/>\n"
524 " </menu>\n"
525 " <menu action='/Find Frame/Find Next'>\n"
526 " <menuitem action='/Find Next/Selected'/>\n"
527 " <menuitem action='/Find Next/Not Selected'/>\n"
528 " </menu>\n"
529 " <menu action='/Find Frame/Find Previous'>\n"
530 " <menuitem action='/Find Previous/Selected'/>\n"
531 " <menuitem action='/Find Previous/Not Selected'/>\n"
532 " </menu>\n"
533 " </menu>\n"
534 " <menu action='/Colorize Procedure'>\n"
535 " <menuitem action='/Colorize Procedure/Colorize Host Traffic'/>\n"
536 " </menu>\n"
537 " </popup>\n"
538 "</ui>\n";
541 * GtkActionEntry
542 * typedef struct {
543 * const gchar *name;
544 * const gchar *stock_id;
545 * const gchar *label;
546 * const gchar *accelerator;
547 * const gchar *tooltip;
548 * GCallback callback;
549 * } GtkActionEntry;
550 * const gchar *name; The name of the action.
551 * const gchar *stock_id; The stock id for the action, or the name of an icon from the icon theme.
552 * const gchar *label; The label for the action. This field should typically be marked for translation,
553 * see gtk_action_group_set_translation_domain().
554 * If label is NULL, the label of the stock item with id stock_id is used.
555 * const gchar *accelerator; The accelerator for the action, in the format understood by gtk_accelerator_parse().
556 * const gchar *tooltip; The tooltip for the action. This field should typically be marked for translation,
557 * see gtk_action_group_set_translation_domain().
558 * GCallback callback; The function to call when the action is activated.
561 static const GtkActionEntry service_resp_t_popup_entries[] = {
562 { "/Apply as Filter", NULL, "Apply as Filter", NULL, NULL, NULL },
563 { "/Prepare a Filter", NULL, "Prepare a Filter", NULL, NULL, NULL },
564 { "/Find Frame", NULL, "Find Frame", NULL, NULL, NULL },
565 { "/Find Frame/Find Frame", NULL, "Find Frame", NULL, NULL, NULL },
566 { "/Find Frame/Find Next", NULL, "Find Next" , NULL, NULL, NULL },
567 { "/Find Frame/Find Previous", NULL, "Find Previous", NULL, NULL, NULL },
568 { "/Colorize Procedure", NULL, "Colorize Procedure", NULL, NULL, NULL },
569 { "/Apply as Filter/Selected", NULL, "Selected", NULL, "Selected", G_CALLBACK(apply_as_selected_cb) },
570 { "/Apply as Filter/Not Selected", NULL, "Not Selected", NULL, "Not Selected", G_CALLBACK(apply_as_not_selected_cb) },
571 { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected", G_CALLBACK(apply_as_and_selected_cb) },
572 { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected", G_CALLBACK(apply_as_or_selected_cb) },
573 { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected", G_CALLBACK(apply_as_and_not_selected_cb) },
574 { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected", G_CALLBACK(apply_as_or_not_selected_cb) },
575 { "/Prepare a Filter/Selected", NULL, "Selected", NULL, "selcted", G_CALLBACK(prep_as_selected_cb) },
576 { "/Prepare a Filter/Not Selected", NULL, "Not Selected", NULL, "Not Selected", G_CALLBACK(prep_as_not_selected_cb) },
577 { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected", G_CALLBACK(prep_as_and_selected_cb) },
578 { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected", G_CALLBACK(prep_as_or_selected_cb) },
579 { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected", G_CALLBACK(prep_as_and_not_selected_cb) },
580 { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected", NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected", G_CALLBACK(prep_as_or_not_selected_cb) },
581 { "/Find Frame/Selected", NULL, "Selected", NULL, "Selected", G_CALLBACK(find_selected_cb) },
582 { "/Find Frame/Not Selected", NULL, "Not Selected", NULL, "Not Selected", G_CALLBACK(find_not_selected_cb) },
583 { "/Find Previous/Selected", NULL, "Selected", NULL, "Selected", G_CALLBACK(find_prev_selected_cb) },
584 { "/Find Previous/Not Selected", NULL, "Not Selected", NULL, "Not Selected", G_CALLBACK(find_prev_not_selected_cb) },
585 { "/Find Next/Selected", NULL, "Selected", NULL, "Selected", G_CALLBACK(find_next_selected_cb) },
586 { "/Find Next/Not Selected", NULL, "Not Selected", NULL, "Not Selected", G_CALLBACK(find_next_not_selected_cb) },
587 { "/Colorize Procedure/Colorize Host Traffic",NULL, "Colorize Host Traffic", NULL, "Colorize Host Traffic", G_CALLBACK(color_selected_cb) },
590 static void
591 hostlist_create_popup_menu(hostlist_table *hl)
593 GtkUIManager *ui_manager;
594 GtkActionGroup *action_group;
595 GError *error = NULL;
597 action_group = gtk_action_group_new ("HostlistTablePopupActionGroup");
598 gtk_action_group_add_actions (action_group, /* the action group */
599 service_resp_t_popup_entries, /* an array of action descriptions */
600 G_N_ELEMENTS(service_resp_t_popup_entries),/* the number of entries */
601 hl); /* data to pass to the action callbacks */
603 ui_manager = gtk_ui_manager_new ();
604 gtk_ui_manager_insert_action_group (ui_manager,
605 action_group,
606 0); /* the position at which the group will be inserted */
607 gtk_ui_manager_add_ui_from_string (ui_manager,ui_desc_hostlist_table_popup, -1, &error);
608 if (error != NULL)
610 fprintf (stderr, "Warning: building hostlist table filter popup failed: %s\n",
611 error->message);
612 g_error_free (error);
613 error = NULL;
615 hl->menu = gtk_ui_manager_get_widget(ui_manager, "/HostlistTableFilterPopup");
616 g_signal_connect(hl->table, "button_press_event", G_CALLBACK(hostlist_show_popup_menu_cb), hl);
620 /* Draw/refresh the address field of a single entry at the specified index */
621 static void
622 get_hostlist_table_address(hostlist_table *hl, hostlist_talker_t *host, const char **entries)
624 char *port;
625 guint32 pt;
627 if (!hl->resolve_names)
628 entries[0] = ep_address_to_str(&host->myaddress);
629 else
630 entries[0] = (char *)get_addr_name(&host->myaddress);
632 pt = host->port_type;
633 if(!hl->resolve_names) pt = PT_NONE;
634 switch(pt) {
635 case(PT_TCP):
636 entries[1] = get_tcp_port(host->port);
637 break;
638 case(PT_UDP):
639 entries[1] = get_udp_port(host->port);
640 break;
641 case(PT_SCTP):
642 entries[1] = get_sctp_port(host->port);
643 break;
644 default:
645 port=hostlist_port_to_str(host->port_type, host->port);
646 entries[1] = port?port:"";
650 /* Refresh the address fields of all entries in the list */
651 static void
652 draw_hostlist_table_addresses(hostlist_table *hl)
654 guint32 i;
655 const char *entries[2];
656 GtkListStore *store;
658 store = GTK_LIST_STORE(gtk_tree_view_get_model(hl->table));
659 g_object_ref(store);
660 gtk_tree_view_set_model(GTK_TREE_VIEW(hl->table), NULL);
662 for(i=0;i<hl->num_hosts;i++){
663 hostlist_talker_t *host = &g_array_index(hl->hosts, hostlist_talker_t, i);
664 get_hostlist_table_address(hl, host, entries);
665 gtk_list_store_set (store, &host->iter,
666 ADR_COLUMN, entries[0],
667 PORT_COLUMN, entries[1],
668 -1);
670 gtk_tree_view_set_model(GTK_TREE_VIEW(hl->table), GTK_TREE_MODEL(store));
671 g_object_unref(store);
675 static void
676 draw_hostlist_table_data(hostlist_table *hl)
678 guint32 i;
679 char title[256];
680 GtkListStore *store;
681 gboolean first = TRUE;
683 if (hl->page_lb) {
684 if(hl->num_hosts) {
685 g_snprintf(title, sizeof(title), "%s: %u", hl->name, hl->num_hosts);
686 } else {
687 g_snprintf(title, sizeof(title), "%s", hl->name);
689 gtk_label_set_text(GTK_LABEL(hl->page_lb), title);
690 gtk_widget_set_sensitive(hl->page_lb, hl->num_hosts);
691 } else {
692 if(hl->num_hosts) {
693 g_snprintf(title, sizeof(title), "%s Endpoints: %u", hl->name, hl->num_hosts);
694 } else {
695 g_snprintf(title, sizeof(title), "%s Endpoints", hl->name);
697 gtk_label_set_text(GTK_LABEL(hl->name_lb), title);
700 store = GTK_LIST_STORE(gtk_tree_view_get_model(hl->table));
701 for(i=0;i<hl->num_hosts;i++){
702 hostlist_talker_t *host = &g_array_index(hl->hosts, hostlist_talker_t, i);
704 if (!host->modified)
705 continue;
707 if (first) {
708 g_object_ref(store);
709 gtk_tree_view_set_model(GTK_TREE_VIEW(hl->table), NULL);
711 first = FALSE;
713 host->modified = FALSE;
714 if (!host->iter_valid) {
715 const char *entries[2];
716 #ifdef HAVE_GEOIP
717 char *geoip[NUM_GEOIP_COLS];
718 guint j;
720 if ((host->myaddress.type == AT_IPv4 || host->myaddress.type == AT_IPv6) && !hl->geoip_visible) {
721 GList *columns, *list;
722 GtkTreeViewColumn *column;
723 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(hl->table));
724 list = columns;
725 while(columns) {
726 const gchar *title_p;
727 gint id;
729 column = (GtkTreeViewColumn *)columns->data;
730 title_p = gtk_tree_view_column_get_title(column);
731 id = gtk_tree_view_column_get_sort_column_id(column);
732 if (title_p[0] != 0 && id >= GEOIP1_COLUMN) {
733 gtk_tree_view_column_set_visible(column, TRUE);
735 columns = g_list_next(columns);
737 g_list_free(list);
738 hl->geoip_visible = TRUE;
741 /* Filled in from the GeoIP config, if any */
742 for (j = 0; j < NUM_GEOIP_COLS; j++) {
743 if (host->myaddress.type == AT_IPv4 && j < geoip_db_num_dbs()) {
744 const guchar *name = geoip_db_lookup_ipv4(j, pntohl(host->myaddress.data), "-");
745 geoip[j] = g_strdup(name);
746 } else if (host->myaddress.type == AT_IPv6 && j < geoip_db_num_dbs()) {
747 const guchar *name;
748 const struct e_in6_addr *addr = (const struct e_in6_addr *) host->myaddress.data;
750 name = geoip_db_lookup_ipv6(j, *addr, "-");
751 geoip[j] = g_strdup(name);
752 } else {
753 geoip[j] = NULL;
756 #endif /* HAVE_GEOIP */
758 get_hostlist_table_address(hl, host, entries);
759 host->iter_valid = TRUE;
760 gtk_list_store_insert_with_values( store , &host->iter, G_MAXINT,
761 ADR_COLUMN, entries[0],
762 PORT_COLUMN, entries[1],
763 PACKETS_COLUMN, host->tx_frames+host->rx_frames,
764 BYTES_COLUMN, host->tx_bytes+host->rx_bytes,
765 PKT_AB_COLUMN, host->tx_frames,
766 BYTES_AB_COLUMN, host->tx_bytes,
767 PKT_BA_COLUMN, host->rx_frames,
768 BYTES_BA_COLUMN, host->rx_bytes,
769 #ifdef HAVE_GEOIP
770 GEOIP1_COLUMN, geoip[0],
771 GEOIP2_COLUMN, geoip[1],
772 GEOIP3_COLUMN, geoip[2],
773 GEOIP4_COLUMN, geoip[3],
774 GEOIP5_COLUMN, geoip[4],
775 GEOIP6_COLUMN, geoip[5],
776 GEOIP7_COLUMN, geoip[6],
777 GEOIP8_COLUMN, geoip[7],
778 GEOIP9_COLUMN, geoip[8],
779 GEOIP10_COLUMN, geoip[9],
780 GEOIP11_COLUMN, geoip[10],
781 GEOIP12_COLUMN, geoip[11],
782 GEOIP13_COLUMN, geoip[12],
783 #endif
784 INDEX_COLUMN, i,
785 -1);
787 #ifdef HAVE_GEOIP
788 for (j = 0; j < NUM_GEOIP_COLS; j++)
789 g_free(geoip[j]);
790 #endif /* HAVE_GEOIP */
792 else {
793 gtk_list_store_set (store, &host->iter,
794 PACKETS_COLUMN, host->tx_frames+host->rx_frames,
795 BYTES_COLUMN, host->tx_bytes+host->rx_bytes,
796 PKT_AB_COLUMN, host->tx_frames,
797 BYTES_AB_COLUMN, host->tx_bytes,
798 PKT_BA_COLUMN, host->rx_frames,
799 BYTES_BA_COLUMN, host->rx_bytes,
800 -1);
803 if (!first) {
804 if (!hl->fixed_col && hl->num_hosts >= 1000) {
805 /* finding the right size for a column isn't easy
806 * let it run in autosize a little (1000 is arbitrary)
807 * and then switch to fixed width.
809 hl->fixed_col = TRUE;
810 switch_to_fixed_col(hl->table);
813 gtk_tree_view_set_model(GTK_TREE_VIEW(hl->table), GTK_TREE_MODEL(store));
814 g_object_unref(store);
818 static void
819 draw_hostlist_table_data_cb(void *arg)
821 draw_hostlist_table_data((hostlist_table *)arg);
824 typedef struct {
825 int nb_cols;
826 gint columns_order[N_COLUMNS];
827 GString *CSV_str;
828 hostlist_table *talkers;
829 } csv_t;
831 /* output in C locale */
832 static gboolean
833 csv_handle(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
834 gpointer data)
836 csv_t *csv = (csv_t *)data;
837 gchar *table_text;
838 int i;
839 guint idx;
840 guint64 value;
842 gtk_tree_model_get(model, iter, INDEX_COLUMN, &idx, -1);
844 for (i=0; i< csv->nb_cols; i++) {
845 if (i)
846 g_string_append(csv->CSV_str, ",");
848 switch(csv->columns_order[i]) {
849 case ADR_COLUMN:
850 case PORT_COLUMN:
851 gtk_tree_model_get(model, iter, csv->columns_order[i], &table_text, -1);
852 if (table_text) {
853 g_string_append_printf(csv->CSV_str, "\"%s\"", table_text);
854 g_free(table_text);
856 break;
857 case PACKETS_COLUMN:
858 case BYTES_COLUMN:
859 case PKT_AB_COLUMN:
860 case BYTES_AB_COLUMN:
861 case PKT_BA_COLUMN:
862 case BYTES_BA_COLUMN:
863 gtk_tree_model_get(model, iter, csv->columns_order[i], &value, -1);
864 g_string_append_printf(csv->CSV_str, "\"%" G_GINT64_MODIFIER "u\"", value);
865 break;
866 default:
867 gtk_tree_model_get(model, iter, csv->columns_order[i], &table_text, -1);
868 if (table_text) {
869 g_string_append_printf(csv->CSV_str, "\"%s\"", table_text);
870 g_free(table_text);
872 break;
875 g_string_append(csv->CSV_str,"\n");
877 return FALSE;
880 static void
881 copy_as_csv_cb(GtkWindow *copy_bt, gpointer data _U_)
883 GtkClipboard *cb;
884 char *savelocale;
885 GList *columns, *list;
886 GtkTreeViewColumn *column;
887 GtkListStore *store;
888 csv_t csv;
890 csv.talkers=(hostlist_table *)g_object_get_data(G_OBJECT(copy_bt), HOST_PTR_KEY);
891 if (!csv.talkers)
892 return;
894 savelocale = setlocale(LC_NUMERIC, NULL);
895 setlocale(LC_NUMERIC, "C");
896 csv.CSV_str = g_string_new("");
898 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(csv.talkers->table));
899 list = columns;
900 csv.nb_cols = 0;
901 while(columns) {
902 column = (GtkTreeViewColumn *)columns->data;
903 if (gtk_tree_view_column_get_visible(column)) {
904 csv.columns_order[csv.nb_cols] = gtk_tree_view_column_get_sort_column_id(column);
905 if (csv.nb_cols)
906 g_string_append(csv.CSV_str, ",");
907 g_string_append_printf(csv.CSV_str, "\"%s\"", gtk_tree_view_column_get_title(column));
908 csv.nb_cols++;
910 columns = g_list_next(columns);
912 g_list_free(list);
914 g_string_append(csv.CSV_str,"\n");
915 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(csv.talkers->table)));
916 gtk_tree_model_foreach(GTK_TREE_MODEL(store), csv_handle, &csv);
918 /* Now that we have the CSV data, copy it into the default clipboard */
919 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
920 gtk_clipboard_set_text(cb, csv.CSV_str->str, -1); /* Copy the CSV data into the clipboard */
921 setlocale(LC_NUMERIC, savelocale);
922 g_string_free(csv.CSV_str, TRUE); /* Free the memory */
925 #ifdef HAVE_GEOIP
926 typedef struct {
927 int nb_cols;
928 gint32 col_lat, col_lon, col_country, col_city, col_as_num, col_ip, col_packets, col_bytes;
929 FILE *out_file;
930 gboolean hosts_written;
931 hostlist_table *talkers;
932 } map_t;
934 static const char *map_endpoint_opener;
936 static void
937 map_init(void)
939 map_endpoint_opener = "{\n";
942 /* XXX output in C locale */
943 static gboolean
944 map_handle(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
945 gpointer data)
947 map_t *map = (map_t *)data;
948 gchar *table_entry, *esc_entry;
949 guint64 value;
950 /* Add the column values to the TSV data */
952 /* check, if we have a geolocation available for this host */
953 gtk_tree_model_get(model, iter, map->col_lat, &table_entry, -1);
954 if (strcmp(table_entry, "-") == 0) {
955 g_free(table_entry);
956 return FALSE;
959 gtk_tree_model_get(model, iter, map->col_lon, &table_entry, -1);
960 if (strcmp(table_entry, "-") == 0) {
961 g_free(table_entry);
962 return FALSE;
967 'type': 'Feature', 'geometry': { 'type': 'Point', 'coordinates': [-122.583889, 37.898889] },
968 'properties': { 'title': 'host.example.com', 'description': 'AS: AS12345 Ewok Holdings, Inc.<br/>Country: US<br/>City: Muir Woods, CA<br/>Packets: 6<br/>Bytes: 980' }
972 fputs(map_endpoint_opener, map->out_file);
973 fputs(" 'type': 'Feature', 'geometry': { 'type': 'Point', 'coordinates': [", map->out_file);
975 /* Longitude */
976 gtk_tree_model_get(model, iter, map->col_lon, &table_entry, -1);
977 fputs(table_entry, map->out_file);
978 g_free(table_entry);
979 fputs(", ", map->out_file);
981 /* Latitude */
982 gtk_tree_model_get(model, iter, map->col_lat, &table_entry, -1);
983 fputs(table_entry, map->out_file);
984 g_free(table_entry);
985 fputs("] },\n", map->out_file);
987 fputs(" 'properties': { 'title': '", map->out_file);
989 /* Title */
990 gtk_tree_model_get(model, iter, map->col_ip, &table_entry, -1);
991 esc_entry = string_replace(table_entry, "'", "&#39;");
992 fputs(esc_entry, map->out_file);
993 g_free(table_entry);
994 g_free(esc_entry);
995 fputs("', 'description': '", map->out_file);
997 /* Description */
998 if (map->col_as_num >= 0) {
999 gtk_tree_model_get(model, iter, map->col_as_num, &table_entry, -1);
1000 fputs("AS: ", map->out_file);
1001 esc_entry = string_replace(table_entry, "'", "&#39;");
1002 fputs(esc_entry, map->out_file);
1003 g_free(table_entry);
1004 g_free(esc_entry);
1005 fputs("<br/>", map->out_file);
1008 if (map->col_country >= 0) {
1009 gtk_tree_model_get(model, iter, map->col_country, &table_entry, -1);
1010 fputs("Country: ", map->out_file);
1011 esc_entry = string_replace(table_entry, "'", "&#39;");
1012 fputs(esc_entry, map->out_file);
1013 g_free(table_entry);
1014 g_free(esc_entry);
1015 fputs("<br/>", map->out_file);
1018 if (map->col_country >= 0) {
1019 gtk_tree_model_get(model, iter, map->col_city, &table_entry, -1);
1020 fputs("City: ", map->out_file);
1021 esc_entry = string_replace(table_entry, "'", "&#39;");
1022 fputs(esc_entry, map->out_file);
1023 g_free(table_entry);
1024 g_free(esc_entry);
1025 fputs("<br/>", map->out_file);
1028 gtk_tree_model_get(model, iter, map->col_packets, &value, -1);
1029 fprintf(map->out_file, "Packets: %" G_GINT64_MODIFIER "u<br/>", value);
1031 gtk_tree_model_get(model, iter, map->col_bytes, &value, -1);
1032 fprintf(map->out_file, "Bytes: %" G_GINT64_MODIFIER "u", value);
1034 /* XXX - we could add specific icons, e.g. depending on the amount of packets or bytes */
1036 fputs("' }\n", map->out_file);
1037 fputs("}", map->out_file);
1038 map_endpoint_opener = ",\n{\n";
1040 map->hosts_written = TRUE;
1042 return FALSE;
1045 #define MAX_TPL_LINE_LEN 4096
1046 static void
1047 open_as_map_cb(GtkWindow *copy_bt, gpointer data _U_)
1049 guint32 i;
1050 gchar *file_uri;
1051 gboolean uri_open;
1052 char *map_path, *map_filename;
1053 char *tpl_filename;
1054 char *tpl_line;
1055 GList *columns, *list;
1056 GtkTreeViewColumn *column;
1057 GtkListStore *store;
1058 map_t map;
1059 FILE *tpl_file;
1061 map.talkers = (hostlist_table *)g_object_get_data(G_OBJECT(copy_bt), HOST_PTR_KEY);
1062 if (!map.talkers)
1063 return;
1065 map.col_lat = map.col_lon = map.col_country = map.col_city = map.col_as_num = map.col_ip = map.col_packets = map.col_bytes = -1;
1066 map.hosts_written = FALSE;
1067 /* Find the interesting columns */
1068 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(map.talkers->table));
1069 list = columns;
1070 map.nb_cols = 0;
1071 while(columns) {
1072 column = (GtkTreeViewColumn *)columns->data;
1073 i = gtk_tree_view_column_get_sort_column_id(column);
1074 if(strcmp(map.talkers->default_titles[i], "Latitude") == 0) {
1075 map.col_lat = i;
1076 map.nb_cols++;
1078 if(strcmp(map.talkers->default_titles[i], "Longitude") == 0) {
1079 map.col_lon = i;
1080 map.nb_cols++;
1082 if(strcmp(map.talkers->default_titles[i], "Country") == 0) {
1083 map.col_country = i;
1084 map.nb_cols++;
1086 if(strcmp(map.talkers->default_titles[i], "City") == 0) {
1087 map.col_city = i;
1088 map.nb_cols++;
1090 if(strcmp(map.talkers->default_titles[i], "AS Number") == 0) {
1091 map.col_as_num = i;
1093 if(strcmp(map.talkers->default_titles[i], "Address") == 0) {
1094 map.col_ip = i;
1095 map.nb_cols++;
1097 if(strcmp(map.talkers->default_titles[i], "Packets") == 0) {
1098 map.col_packets = i;
1099 map.nb_cols++;
1101 if(strcmp(map.talkers->default_titles[i], "Bytes") == 0) {
1102 map.col_bytes = i;
1103 map.nb_cols++;
1105 columns = g_list_next(columns);
1107 g_list_free(list);
1109 /* check for the minimum required data */
1110 if(map.col_lat == -1 || map.col_lon == -1) {
1111 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Latitude/Longitude data not available (GeoIP installed?)");
1112 return;
1115 /* Create a location map HTML file from a template */
1116 /* XXX - add error handling */
1117 tpl_filename = get_datafile_path("ipmap.html");
1118 tpl_file = ws_fopen(tpl_filename, "r");
1119 if(tpl_file == NULL) {
1120 open_failure_alert_box(tpl_filename, errno, FALSE);
1121 g_free(tpl_filename);
1122 return;
1124 g_free(tpl_filename);
1126 /* We should probably create a file with a temporary name and a .html extension instead */
1127 if (! create_tempdir(&map_path, "Wireshark IP Map ")) {
1128 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1129 "Could not create temporary directory\n%s",
1130 map_path);
1131 fclose(tpl_file);
1132 return;
1135 map_filename = g_strdup_printf("%s%cipmap.html", map_path, G_DIR_SEPARATOR);
1136 map.out_file = ws_fopen(map_filename, "w");
1137 if(map.out_file == NULL) {
1138 open_failure_alert_box(map_filename, errno, TRUE);
1139 g_free(map_filename);
1140 fclose(tpl_file);
1141 return;
1144 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(map.talkers->table)));
1145 tpl_line = (char *)g_malloc(MAX_TPL_LINE_LEN);
1147 while (fgets(tpl_line, MAX_TPL_LINE_LEN, tpl_file) != NULL) {
1148 fputs(tpl_line, map.out_file);
1149 /* MUST match ipmap.html */
1150 if (strstr(tpl_line, "// Start endpoint list")) {
1151 map_init();
1152 gtk_tree_model_foreach(GTK_TREE_MODEL(store), map_handle, &map);
1155 g_free(tpl_line);
1157 fclose(tpl_file);
1158 fclose(map.out_file);
1160 if(!map.hosts_written) {
1161 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No latitude/longitude data found");
1162 g_free(map_filename);
1163 return;
1166 /* open the webbrowser */
1167 file_uri = g_filename_to_uri(map_filename, NULL, NULL);
1168 g_free(map_filename);
1169 uri_open = browser_open_url (file_uri);
1170 if(!uri_open) {
1171 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't open the file: \"%s\" in your web browser", file_uri);
1172 g_free(file_uri);
1173 return;
1176 g_free(file_uri);
1178 #endif /* HAVE_GEOIP */
1180 static gint default_col_size[N_COLUMNS];
1182 static void
1183 init_default_col_size(GtkWidget *view)
1186 default_col_size[ADR_COLUMN] = get_default_col_size(view, "00000000.000000000000");
1187 default_col_size[PORT_COLUMN] = get_default_col_size(view, "000000");
1188 default_col_size[PACKETS_COLUMN] = get_default_col_size(view, "00 000 000");
1189 default_col_size[BYTES_COLUMN] = get_default_col_size(view, "0 000 000 000");
1190 default_col_size[PKT_AB_COLUMN] = default_col_size[PACKETS_COLUMN];
1191 default_col_size[PKT_BA_COLUMN] = default_col_size[PACKETS_COLUMN];
1192 default_col_size[BYTES_AB_COLUMN] = default_col_size[BYTES_COLUMN];
1193 default_col_size[BYTES_BA_COLUMN] = default_col_size[BYTES_COLUMN];
1194 #ifdef HAVE_GEOIP
1195 default_col_size[GEOIP1_COLUMN] = default_col_size[ADR_COLUMN];
1196 default_col_size[GEOIP2_COLUMN] = default_col_size[GEOIP1_COLUMN];
1197 default_col_size[GEOIP3_COLUMN] = default_col_size[GEOIP1_COLUMN];
1198 default_col_size[GEOIP4_COLUMN] = default_col_size[GEOIP1_COLUMN];
1199 default_col_size[GEOIP5_COLUMN] = default_col_size[GEOIP1_COLUMN];
1200 default_col_size[GEOIP6_COLUMN] = default_col_size[GEOIP1_COLUMN];
1201 default_col_size[GEOIP7_COLUMN] = default_col_size[GEOIP1_COLUMN];
1202 default_col_size[GEOIP8_COLUMN] = default_col_size[GEOIP1_COLUMN];
1203 default_col_size[GEOIP9_COLUMN] = default_col_size[GEOIP1_COLUMN];
1204 default_col_size[GEOIP10_COLUMN] = default_col_size[GEOIP1_COLUMN];
1205 default_col_size[GEOIP11_COLUMN] = default_col_size[GEOIP1_COLUMN];
1206 default_col_size[GEOIP12_COLUMN] = default_col_size[GEOIP1_COLUMN];
1207 default_col_size[GEOIP13_COLUMN] = default_col_size[GEOIP1_COLUMN];
1209 #endif
1212 static gboolean
1213 init_hostlist_table_page(hostlist_table *hosttable, GtkWidget *vbox, gboolean hide_ports, const char *table_name, const char *tap_name,
1214 const char *filter, tap_packet_cb packet_func)
1216 guint i;
1217 GString *error_string;
1218 char title[256];
1219 GtkListStore *store;
1220 GtkWidget *tree;
1221 GtkTreeViewColumn *column;
1222 GtkCellRenderer *renderer;
1223 GtkTreeSortable *sortable;
1224 GtkTreeSelection *sel;
1225 static gboolean col_size = FALSE;
1227 hosttable->default_titles[0] = "Address";
1228 hosttable->default_titles[1] = "Port";
1229 hosttable->default_titles[2] = "Packets";
1230 hosttable->default_titles[3] = "Bytes";
1231 hosttable->default_titles[4] = "Tx Packets";
1232 hosttable->default_titles[5] = "Tx Bytes";
1233 hosttable->default_titles[6] = "Rx Packets";
1234 hosttable->default_titles[7] = "Rx Bytes";
1236 #ifdef HAVE_GEOIP
1237 for (i = 0; i < NUM_GEOIP_COLS; i++) {
1238 if (i < geoip_db_num_dbs()) {
1239 hosttable->default_titles[NUM_BUILTIN_COLS + i] = geoip_db_name(i);
1240 } else {
1241 hosttable->default_titles[NUM_BUILTIN_COLS + i] = "";
1244 #endif /* HAVE_GEOIP */
1246 if (strcmp(table_name, "NCP")==0) {
1247 hosttable->default_titles[1] = "Connection";
1250 hosttable->has_ports=!hide_ports;
1251 hosttable->num_hosts = 0;
1252 hosttable->resolve_names=TRUE;
1253 hosttable->page_lb = NULL;
1254 hosttable->fixed_col = FALSE;
1255 hosttable->geoip_visible = FALSE;
1257 g_snprintf(title, sizeof(title), "%s Endpoints", table_name);
1258 hosttable->name_lb = gtk_label_new(title);
1259 gtk_box_pack_start(GTK_BOX(vbox), hosttable->name_lb, FALSE, FALSE, 0);
1261 /* Create the store */
1262 store = gtk_list_store_new (N_COLUMNS, /* Total number of columns */
1263 G_TYPE_STRING, /* Address */
1264 G_TYPE_STRING, /* Port */
1265 G_TYPE_UINT64, /* Packets */
1266 G_TYPE_UINT64, /* Bytes */
1267 G_TYPE_UINT64, /* Packets A->B */
1268 G_TYPE_UINT64, /* Bytes A->B */
1269 G_TYPE_UINT64, /* Packets A<-B */
1270 G_TYPE_UINT64, /* Bytes A<-B */
1271 #ifdef HAVE_GEOIP
1272 G_TYPE_STRING,
1273 G_TYPE_STRING,
1274 G_TYPE_STRING,
1275 G_TYPE_STRING,
1276 G_TYPE_STRING,
1277 G_TYPE_STRING,
1278 G_TYPE_STRING,
1279 G_TYPE_STRING,
1280 G_TYPE_STRING,
1281 G_TYPE_STRING,
1282 G_TYPE_STRING,
1283 G_TYPE_STRING,
1284 G_TYPE_STRING,
1285 #endif
1286 G_TYPE_UINT); /* Index */
1288 hosttable->scrolled_window=scrolled_window_new(NULL, NULL);
1289 gtk_box_pack_start(GTK_BOX(vbox), hosttable->scrolled_window, TRUE, TRUE, 0);
1290 tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
1291 hosttable->table = GTK_TREE_VIEW(tree);
1292 sortable = GTK_TREE_SORTABLE(store);
1293 g_object_unref (G_OBJECT (store));
1295 if (!col_size) {
1296 col_size = TRUE;
1297 init_default_col_size(GTK_WIDGET(hosttable->table));
1300 g_object_set_data(G_OBJECT(store), HOST_PTR_KEY, hosttable);
1301 g_object_set_data(G_OBJECT(hosttable->table), HOST_PTR_KEY, hosttable);
1303 for (i = 0; i < N_COLUMNS -1; i++) {
1304 renderer = gtk_cell_renderer_text_new ();
1305 g_object_set(renderer, "ypad", 0, NULL);
1306 switch(i) {
1307 case 0: /* address and port */
1308 case 1:
1309 column = gtk_tree_view_column_new_with_attributes (hosttable->default_titles[i], renderer, "text",
1310 i, NULL);
1311 if(hide_ports && i == 1){
1312 /* hide srcport and dstport if we don't use ports */
1313 gtk_tree_view_column_set_visible(column, FALSE);
1315 gtk_tree_sortable_set_sort_func(sortable, i, hostlist_sort_column, GINT_TO_POINTER(i), NULL);
1316 break;
1317 case 2: /* counts */
1318 case 3:
1319 case 4:
1320 case 5:
1321 case 6:
1322 case 7: /* right align numbers */
1323 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1324 column = gtk_tree_view_column_new_with_attributes (hosttable->default_titles[i], renderer, NULL);
1325 gtk_tree_view_column_set_cell_data_func(column, renderer, u64_data_func, GINT_TO_POINTER(i), NULL);
1326 break;
1327 default: /* GEOIP */
1328 column = gtk_tree_view_column_new_with_attributes (hosttable->default_titles[i], renderer, "text",
1329 i, NULL);
1330 gtk_tree_view_column_set_visible(column, FALSE);
1331 #ifdef HAVE_GEOIP
1332 if (i >= NUM_BUILTIN_COLS && i - NUM_BUILTIN_COLS < geoip_db_num_dbs()) {
1333 int goip_type = geoip_db_type(i - NUM_BUILTIN_COLS);
1334 if (goip_type == WS_LON_FAKE_EDITION || goip_type == WS_LAT_FAKE_EDITION) {
1335 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1336 gtk_tree_sortable_set_sort_func(sortable, i, hostlist_sort_column, GINT_TO_POINTER(i), NULL);
1339 #endif
1340 break;
1342 gtk_tree_view_column_set_sort_column_id(column, i);
1343 gtk_tree_view_column_set_resizable(column, TRUE);
1344 gtk_tree_view_column_set_reorderable(column, TRUE);
1345 gtk_tree_view_column_set_min_width(column, 40);
1346 gtk_tree_view_column_set_fixed_width(column, default_col_size[i]);
1347 gtk_tree_view_append_column (hosttable->table, column);
1349 #if 0
1350 /* make total frames be the default sort order, too slow */
1351 if (i == PACKETS_COLUMN) {
1352 gtk_tree_view_column_clicked(column);
1354 #endif
1357 gtk_container_add(GTK_CONTAINER(hosttable->scrolled_window), (GtkWidget *)hosttable->table);
1359 hosttable->num_hosts=0;
1360 hosttable->hosts=NULL;
1361 hosttable->hashtable=NULL;
1363 gtk_tree_view_set_rules_hint(hosttable->table, TRUE);
1364 gtk_tree_view_set_headers_clickable(hosttable->table, TRUE);
1365 gtk_tree_view_set_reorderable (hosttable->table, TRUE);
1367 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hosttable->table));
1368 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1370 /* create popup menu for this table */
1371 hostlist_create_popup_menu(hosttable);
1373 /* register the tap and rerun the taps on the packet list */
1374 error_string=register_tap_listener(tap_name, hosttable, filter, 0, reset_hostlist_table_data_cb, packet_func, draw_hostlist_table_data_cb);
1375 if(error_string){
1376 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
1377 g_string_free(error_string, TRUE);
1378 g_free(hosttable);
1379 return FALSE;
1381 return TRUE;
1385 void
1386 init_hostlist_table(gboolean hide_ports, const char *table_name, const char *tap_name, const char *filter, tap_packet_cb packet_func)
1388 hostlist_table *hosttable;
1389 char *display_name;
1390 char title[256];
1391 GtkWidget *vbox;
1392 GtkWidget *bbox;
1393 GtkWidget *close_bt, *help_bt;
1394 gboolean ret;
1395 GtkWidget *copy_bt;
1396 #ifdef HAVE_GEOIP
1397 GtkWidget *map_bt;
1398 #endif
1399 window_geometry_t tl_geom;
1401 hosttable=g_new(hostlist_table,1);
1403 hosttable->name=table_name;
1404 hosttable->filter=filter;
1405 hosttable->use_dfilter=FALSE;
1406 display_name = cf_get_display_name(&cfile);
1407 g_snprintf(title, sizeof(title), "%s Endpoints: %s", table_name, display_name);
1408 g_free(display_name);
1409 hosttable->win = dlg_window_new(title); /* transient_for top_level */
1410 gtk_window_set_destroy_with_parent (GTK_WINDOW(hosttable->win), TRUE);
1412 window_get_geometry(top_level, &tl_geom);
1413 gtk_window_set_default_size(GTK_WINDOW(hosttable->win), tl_geom.width * 8 / 10, HL_DLG_HEIGHT);
1415 vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, DLG_LABEL_SPACING, FALSE);
1416 gtk_container_add(GTK_CONTAINER(hosttable->win), vbox);
1417 gtk_container_set_border_width(GTK_CONTAINER(vbox), DLG_OUTER_MARGIN);
1419 ret = init_hostlist_table_page(hosttable, vbox, hide_ports, table_name, tap_name, filter, packet_func);
1420 if(ret == FALSE) {
1421 g_free(hosttable);
1422 return;
1425 /* Button row. */
1426 /* XXX - maybe we want to have a "Copy as CSV" stock button here? */
1427 /*copy_bt = gtk_button_new_with_label ("Copy content to clipboard as CSV");*/
1428 #ifdef HAVE_GEOIP
1429 if( strstr(table_name, "IPv4") || strstr(table_name, "IPv6") ) {
1430 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY, WIRESHARK_STOCK_MAP, GTK_STOCK_HELP, NULL);
1431 } else {
1432 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY, GTK_STOCK_HELP, NULL);
1434 #else
1435 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY, GTK_STOCK_HELP, NULL);
1436 #endif
1438 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1440 close_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1441 window_set_cancel_button(hosttable->win, close_bt, window_cancel_button_cb);
1443 copy_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_COPY);
1444 gtk_widget_set_tooltip_text(copy_bt, "Copy all statistical values of this page to the clipboard in CSV (Comma Separated Values) format.");
1445 g_object_set_data(G_OBJECT(copy_bt), HOST_PTR_KEY, hosttable);
1446 g_signal_connect(copy_bt, "clicked", G_CALLBACK(copy_as_csv_cb), NULL);
1448 #ifdef HAVE_GEOIP
1449 map_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_MAP);
1450 if(map_bt != NULL) {
1451 gtk_widget_set_tooltip_text(map_bt, "Show a map of the IP addresses (internet connection required).");
1452 g_object_set_data(G_OBJECT(map_bt), HOST_PTR_KEY, hosttable);
1453 g_signal_connect(map_bt, "clicked", G_CALLBACK(open_as_map_cb), NULL);
1455 #endif /* HAVE_GEOIP */
1457 help_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1458 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_ENDPOINTS_DIALOG);
1460 g_signal_connect(hosttable->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
1461 g_signal_connect(hosttable->win, "destroy", G_CALLBACK(hostlist_win_destroy_cb), hosttable);
1463 gtk_widget_show_all(hosttable->win);
1464 window_present(hosttable->win);
1466 cf_retap_packets(&cfile);
1467 gdk_window_raise(gtk_widget_get_window(hosttable->win));
1471 static void
1472 ct_nb_switch_page_cb(GtkNotebook *nb, gpointer *pg _U_, guint page, gpointer data)
1474 GtkWidget *copy_bt = (GtkWidget *) data;
1475 void ** pages = (void **)g_object_get_data(G_OBJECT(nb), NB_PAGES_KEY);
1477 page++;
1479 if (pages && page > 0 && (int) page <= GPOINTER_TO_INT(pages[0]) && copy_bt) {
1480 g_object_set_data(G_OBJECT(copy_bt), HOST_PTR_KEY, pages[page]);
1484 #ifdef HAVE_GEOIP
1485 static void
1486 ct_nb_map_switch_page_cb(GtkNotebook *nb, gpointer *pg _U_, guint page, gpointer data)
1488 GtkWidget *map_bt = (GtkWidget *) data;
1489 void ** pages = (void **)g_object_get_data(G_OBJECT(nb), NB_PAGES_KEY);
1491 page++;
1493 if (pages && page > 0 && (int) page <= GPOINTER_TO_INT(pages[0]) && map_bt) {
1494 g_object_set_data(G_OBJECT(map_bt), HOST_PTR_KEY, pages[page]);
1495 if( strstr(((hostlist_table *)pages[page])->name, "IPv4") ||
1496 strstr(((hostlist_table *)pages[page])->name, "IPv6") ) {
1497 gtk_widget_set_sensitive(map_bt, TRUE);
1498 } else {
1499 gtk_widget_set_sensitive(map_bt, FALSE);
1503 #endif /* HAVE_GEOIP */
1506 static void
1507 hostlist_win_destroy_notebook_cb(GtkWindow *win _U_, gpointer data)
1509 void ** pages = (void **)data;
1510 int page;
1512 /* first "page" contains the number of pages */
1513 for (page=1; page<=GPOINTER_TO_INT(pages[0]); page++) {
1514 hostlist_win_destroy_cb(NULL, pages[page]);
1516 g_free(pages);
1522 static hostlist_table *
1523 init_hostlist_notebook_page_cb(gboolean hide_ports, const char *table_name, const char *tap_name, const char *filter,
1524 tap_packet_cb packet_func)
1526 gboolean ret;
1527 GtkWidget *page_vbox;
1528 hostlist_table *hosttable;
1530 hosttable=g_new(hostlist_table,1);
1531 hosttable->name=table_name;
1532 hosttable->filter=filter;
1533 hosttable->use_dfilter=FALSE;
1535 page_vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 6, FALSE);
1536 hosttable->win = page_vbox;
1537 gtk_container_set_border_width(GTK_CONTAINER(page_vbox), 6);
1539 ret = init_hostlist_table_page(hosttable, page_vbox, hide_ports, table_name, tap_name, filter, packet_func);
1540 if(ret == FALSE) {
1541 g_free(hosttable);
1542 return NULL;
1545 return hosttable;
1549 typedef struct {
1550 gboolean hide_ports; /* hide TCP / UDP port columns */
1551 const char *table_name; /* GUI output name */
1552 const char *tap_name; /* internal name */
1553 const char *filter; /* display filter string (unused) */
1554 tap_packet_cb packet_func; /* function to be called for new incoming packets */
1555 } register_hostlist_t;
1558 static GSList *registered_hostlist_tables = NULL;
1560 void
1561 register_hostlist_table(gboolean hide_ports, const char *table_name, const char *tap_name, const char *filter, tap_packet_cb packet_func)
1563 register_hostlist_t *table;
1565 table = g_new(register_hostlist_t,1);
1567 table->hide_ports = hide_ports;
1568 table->table_name = table_name;
1569 table->tap_name = tap_name;
1570 table->filter = filter;
1571 table->packet_func = packet_func;
1573 registered_hostlist_tables = g_slist_append(registered_hostlist_tables, table);
1577 static void
1578 hostlist_resolve_toggle_dest(GtkWidget *widget, gpointer data)
1580 int page;
1581 void ** pages = (void **)data;
1582 gboolean resolve_names;
1583 hostlist_table *hosttable;
1586 resolve_names = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1588 for (page=1; page<=GPOINTER_TO_INT(pages[0]); page++) {
1589 hosttable = (hostlist_table *)pages[page];
1590 hosttable->resolve_names = resolve_names;
1591 draw_hostlist_table_addresses(hosttable);
1596 static void
1597 hostlist_filter_toggle_dest(GtkWidget *widget, gpointer data)
1599 int page;
1600 void ** pages = (void **)data;
1601 gboolean use_filter;
1602 hostlist_table *hosttable = NULL;
1604 use_filter = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1606 for (page=1; page<=GPOINTER_TO_INT(pages[0]); page++) {
1607 hosttable = (hostlist_table *)pages[page];
1608 hosttable->use_dfilter = use_filter;
1609 reset_hostlist_table_data(hosttable);
1612 cf_retap_packets(&cfile);
1613 if (hosttable) {
1614 gdk_window_raise(gtk_widget_get_window(hosttable->win));
1619 void
1620 init_hostlist_notebook_cb(GtkWidget *w _U_, gpointer d _U_)
1622 hostlist_table *hosttable;
1623 char *display_name;
1624 char title[256];
1625 GtkWidget *vbox;
1626 GtkWidget *hbox;
1627 GtkWidget *bbox;
1628 GtkWidget *close_bt, *help_bt;
1629 GtkWidget *win;
1630 GtkWidget *resolv_cb;
1631 GtkWidget *filter_cb;
1632 int page;
1633 void ** pages;
1634 GtkWidget *nb;
1635 GtkWidget *page_lb;
1636 GSList *current_table;
1637 register_hostlist_t *registered;
1638 GtkWidget *copy_bt;
1639 #ifdef HAVE_GEOIP
1640 GtkWidget *map_bt;
1641 #endif
1642 window_geometry_t tl_geom;
1644 pages = (void **)g_malloc(sizeof(void *) * (g_slist_length(registered_hostlist_tables) + 1));
1646 win = dlg_window_new("hostlist"); /* transient_for top_level */
1647 gtk_window_set_destroy_with_parent (GTK_WINDOW(win), TRUE);
1649 display_name = cf_get_display_name(&cfile);
1650 g_snprintf(title, sizeof(title), "Endpoints: %s", display_name);
1651 g_free(display_name);
1652 gtk_window_set_title(GTK_WINDOW(win), title);
1654 window_get_geometry(top_level, &tl_geom);
1655 gtk_window_set_default_size(GTK_WINDOW(win), tl_geom.width * 8 / 10, HL_DLG_HEIGHT);
1657 vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, DLG_LABEL_SPACING, FALSE);
1658 gtk_container_add(GTK_CONTAINER(win), vbox);
1659 gtk_container_set_border_width(GTK_CONTAINER(vbox), DLG_OUTER_MARGIN);
1661 nb = gtk_notebook_new();
1662 gtk_box_pack_start(GTK_BOX(vbox), nb, TRUE, TRUE, 0);
1663 g_object_set_data(G_OBJECT(nb), NB_PAGES_KEY, pages);
1665 page = 0;
1667 current_table = registered_hostlist_tables;
1668 while(current_table) {
1669 registered = (register_hostlist_t *)current_table->data;
1670 page_lb = gtk_label_new("");
1671 hosttable = init_hostlist_notebook_page_cb(registered->hide_ports, registered->table_name, registered->tap_name,
1672 registered->filter, registered->packet_func);
1673 g_object_set_data(G_OBJECT(hosttable->win), HOST_PTR_KEY, hosttable);
1674 gtk_notebook_append_page(GTK_NOTEBOOK(nb), hosttable->win, page_lb);
1675 hosttable->win = win;
1676 hosttable->page_lb = page_lb;
1677 pages[++page] = hosttable;
1679 current_table = g_slist_next(current_table);
1682 pages[0] = GINT_TO_POINTER(page);
1684 hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DLG_UNRELATED_SPACING, FALSE);
1685 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1687 resolv_cb = gtk_check_button_new_with_mnemonic("Name resolution");
1688 gtk_box_pack_start(GTK_BOX(hbox), resolv_cb, FALSE, FALSE, 0);
1689 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolv_cb), TRUE);
1690 gtk_widget_set_tooltip_text(resolv_cb,
1691 "Show results of name resolutions rather than the \"raw\" values. Please note: The corresponding name resolution must be enabled.");
1693 g_signal_connect(resolv_cb, "toggled", G_CALLBACK(hostlist_resolve_toggle_dest), pages);
1695 filter_cb = gtk_check_button_new_with_mnemonic("Limit to display filter");
1696 gtk_box_pack_start(GTK_BOX(hbox), filter_cb, FALSE, FALSE, 0);
1697 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_cb), FALSE);
1698 gtk_widget_set_tooltip_text(filter_cb, "Limit the list to endpoints matching the current display filter.");
1700 g_signal_connect(filter_cb, "toggled", G_CALLBACK(hostlist_filter_toggle_dest), pages);
1702 /* Button row. */
1703 #ifdef HAVE_GEOIP
1704 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY, WIRESHARK_STOCK_MAP, GTK_STOCK_HELP, NULL);
1705 #else
1706 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_COPY, GTK_STOCK_HELP, NULL);
1707 #endif
1708 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1710 close_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1711 window_set_cancel_button(win, close_bt, window_cancel_button_cb);
1713 copy_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_COPY);
1714 gtk_widget_set_tooltip_text(copy_bt, "Copy all statistical values of this page to the clipboard in CSV (Comma Separated Values) format.");
1715 g_signal_connect(copy_bt, "clicked", G_CALLBACK(copy_as_csv_cb), NULL);
1716 g_object_set_data(G_OBJECT(copy_bt), HOST_PTR_KEY, pages[page]);
1718 #ifdef HAVE_GEOIP
1719 map_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_MAP);
1720 gtk_widget_set_tooltip_text(map_bt, "Show a map of the IP addresses (internet connection required).");
1721 g_object_set_data(G_OBJECT(map_bt), HOST_PTR_KEY, pages[page]);
1722 g_signal_connect(map_bt, "clicked", G_CALLBACK(open_as_map_cb), NULL);
1723 g_signal_connect(nb, "switch-page", G_CALLBACK(ct_nb_map_switch_page_cb), map_bt);
1724 gtk_widget_set_sensitive(map_bt, FALSE);
1725 #endif /* HAVE_GEOIP */
1727 g_signal_connect(nb, "switch-page", G_CALLBACK(ct_nb_switch_page_cb), copy_bt);
1729 help_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1730 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_ENDPOINTS_DIALOG);
1732 g_signal_connect(win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
1733 g_signal_connect(win, "destroy", G_CALLBACK(hostlist_win_destroy_notebook_cb), pages);
1735 gtk_widget_show_all(win);
1736 window_present(win);
1738 cf_retap_packets(&cfile);
1739 gdk_window_raise(gtk_widget_get_window(win));
1743 * Compute the hash value for a given address/port pairs if the match
1744 * is to be exact.
1746 typedef struct {
1747 address myaddress;
1748 guint32 port;
1749 } host_key_t;
1751 static guint
1752 host_hash(gconstpointer v)
1754 const host_key_t *key = (const host_key_t *)v;
1755 guint hash_val;
1757 hash_val = 0;
1758 ADD_ADDRESS_TO_HASH(hash_val, &key->myaddress);
1759 hash_val += key->port;
1760 return hash_val;
1764 * Compare two host keys for an exact match.
1766 static gint
1767 host_match(gconstpointer v, gconstpointer w)
1769 const host_key_t *v1 = (const host_key_t *)v;
1770 const host_key_t *v2 = (const host_key_t *)w;
1772 if (v1->port == v2->port &&
1773 ADDRESSES_EQUAL(&v1->myaddress, &v2->myaddress)) {
1774 return 1;
1777 * The addresses or the ports don't match.
1779 return 0;
1782 void
1783 add_hostlist_table_data(hostlist_table *hl, const address *addr, guint32 port, gboolean sender, int num_frames, int num_bytes, SAT_E sat, int port_type_val)
1785 hostlist_talker_t *talker=NULL;
1786 int talker_idx=0;
1788 /* XXX should be optimized to allocate n extra entries at a time
1789 instead of just one */
1790 /* if we dont have any entries at all yet */
1791 if(hl->hosts==NULL){
1792 hl->hosts=g_array_sized_new(FALSE, FALSE, sizeof(hostlist_talker_t), 10000);
1793 hl->hashtable = g_hash_table_new_full(host_hash,
1794 host_match, /* key_equal_func */
1795 g_free, /* key_destroy_func */
1796 NULL); /* value_destroy_func */
1798 else {
1799 /* try to find it among the existing known conversations */
1800 host_key_t existing_key;
1802 existing_key.myaddress = *addr;
1803 existing_key.port = port;
1804 talker_idx = GPOINTER_TO_UINT(g_hash_table_lookup(hl->hashtable, &existing_key));
1805 if (talker_idx) {
1806 talker_idx--;
1807 talker=&g_array_index(hl->hosts, hostlist_talker_t, talker_idx);
1811 /* if we still dont know what talker this is it has to be a new one
1812 and we have to allocate it and append it to the end of the list */
1813 if(talker==NULL){
1814 host_key_t *new_key;
1815 hostlist_talker_t host;
1817 COPY_ADDRESS(&host.myaddress, addr);
1818 host.sat=sat;
1819 host.port_type=port_type_val;
1820 host.port=port;
1821 host.rx_frames=0;
1822 host.tx_frames=0;
1823 host.rx_bytes=0;
1824 host.tx_bytes=0;
1825 host.iter_valid = FALSE;
1826 host.modified = TRUE;
1828 g_array_append_val(hl->hosts, host);
1829 talker_idx= hl->num_hosts;
1830 talker=&g_array_index(hl->hosts, hostlist_talker_t, talker_idx);
1832 /* hl->hosts address is not a constant but address.data is */
1833 new_key = g_new(host_key_t,1);
1834 SET_ADDRESS(&new_key->myaddress, talker->myaddress.type, talker->myaddress.len, talker->myaddress.data);
1835 new_key->port = port;
1836 g_hash_table_insert(hl->hashtable, new_key, GUINT_TO_POINTER(talker_idx +1));
1837 hl->num_hosts++;
1840 /* if this is a new talker we need to initialize the struct */
1841 talker->modified = TRUE;
1843 /* update the talker struct */
1844 if( sender ){
1845 talker->tx_frames+=num_frames;
1846 talker->tx_bytes+=num_bytes;
1847 } else {
1848 talker->rx_frames+=num_frames;
1849 talker->rx_bytes+=num_bytes;
1854 * Editor modelines
1856 * Local Variables:
1857 * c-basic-offset: 4
1858 * tab-width: 8
1859 * indent-tabs-mode: nil
1860 * End:
1862 * ex: set shiftwidth=4 tabstop=8 expandtab:
1863 * :indentSize=4:tabSize=8:noTabs=true: