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