Removed unused argument to new_packet_list_copy_summary_cb().
[obnox/wireshark/wip.git] / gtk / dcerpc_stat.c
1 /* dcerpc_stat.c
2  * dcerpc_stat   2002 Ronnie Sahlberg
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 /* This module provides rpc call/reply SRT statistics to Wireshark,
26  * and displays them graphically.
27  * It is only used by Wireshark and not tshark
28  *
29  * It serves as an example on how to use the tap api.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <string.h>
38
39 #include <gtk/gtk.h>
40
41 #include <epan/packet_info.h>
42 #include <epan/epan.h>
43 #include <epan/stat_cmd_args.h>
44 #include <epan/tap.h>
45 #include <epan/dissectors/packet-dcerpc.h>
46
47 #include "../stat_menu.h"
48 #include "../simple_dialog.h"
49
50 #include "gtk/gui_stat_menu.h"
51 #include "gtk/dlg_utils.h"
52 #include "gtk/gui_utils.h"
53 #include "gtk/filter_dlg.h"
54 #include "gtk/stock_icons.h"
55 #include "gtk/service_response_time_table.h"
56 #include "gtk/gtkglobals.h"
57 #include "gtk/main.h"
58 #include "gtk/filter_autocomplete.h"
59
60 #include "gtk/old-gtk-compat.h"
61
62 /* used to keep track of the statistics for an entire program interface */
63 typedef struct _dcerpcstat_t {
64         GtkWidget *win;
65         srt_stat_table srt_table;
66         const char *prog;
67         e_uuid_t uuid;
68         guint16 ver;
69         int num_procedures;
70 } dcerpcstat_t;
71
72
73 static gboolean
74 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
75 {
76         if( (uuid1->Data1    != uuid2->Data1)
77           ||(uuid1->Data2    != uuid2->Data2)
78           ||(uuid1->Data3    != uuid2->Data3)
79           ||(uuid1->Data4[0] != uuid2->Data4[0])
80           ||(uuid1->Data4[1] != uuid2->Data4[1])
81           ||(uuid1->Data4[2] != uuid2->Data4[2])
82           ||(uuid1->Data4[3] != uuid2->Data4[3])
83           ||(uuid1->Data4[4] != uuid2->Data4[4])
84           ||(uuid1->Data4[5] != uuid2->Data4[5])
85           ||(uuid1->Data4[6] != uuid2->Data4[6])
86           ||(uuid1->Data4[7] != uuid2->Data4[7]) ){
87                 return FALSE;
88         }
89         return TRUE;
90 }
91
92 static char *
93 dcerpcstat_gen_title(dcerpcstat_t *rs)
94 {
95         char *title;
96
97         title = g_strdup_printf("DCE-RPC Service Response Time statistics for %s major version %u: %s", rs->prog, rs->ver, cf_get_display_name(&cfile));
98         return title;
99 }
100
101 static void
102 dcerpcstat_set_title(dcerpcstat_t *rs)
103 {
104         char *title;
105
106         title = dcerpcstat_gen_title(rs);
107         gtk_window_set_title(GTK_WINDOW(rs->win), title);
108         g_free(title);
109 }
110
111 static void
112 dcerpcstat_reset(void *rs_arg)
113 {
114         dcerpcstat_t *rs = rs_arg;
115
116         reset_srt_table_data(&rs->srt_table);
117         dcerpcstat_set_title(rs);
118 }
119
120
121 static gboolean
122 dcerpcstat_packet(void *rs_arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ri_arg)
123 {
124         dcerpcstat_t *rs = rs_arg;
125         const dcerpc_info *ri = ri_arg;
126
127         if(!ri->call_data){
128                 return FALSE;
129         }
130         if(!ri->call_data->req_frame){
131                 /* we have not seen the request so we don't know the delta*/
132                 return FALSE;
133         }
134         if(ri->call_data->opnum >= rs->num_procedures){
135                 /* don't handle this since its outside of known table */
136                 return FALSE;
137         }
138
139         /* we are only interested in reply packets */
140         if(ri->ptype != PDU_RESP){
141                 return FALSE;
142         }
143
144         /* we are only interested in certain program/versions */
145         if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
146           ||(ri->call_data->ver != rs->ver)){
147                 return FALSE;
148         }
149
150
151         add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
152
153
154         return TRUE;
155 }
156
157 static void
158 dcerpcstat_draw(void *rs_arg)
159 {
160         dcerpcstat_t *rs = rs_arg;
161
162         draw_srt_table_data(&rs->srt_table);
163 }
164
165
166 /* since the gtk2 implementation of tap is multithreaded we must protect
167  * remove_tap_listener() from modifying the list while draw_tap_listener()
168  * is running.  the other protected block is in main.c
169  *
170  * there should not be any other critical regions in gtk2
171  */
172 static void
173 win_destroy_cb(GtkWindow *win _U_, gpointer data)
174 {
175         dcerpcstat_t *rs = (dcerpcstat_t *)data;
176
177         protect_thread_critical_region();
178         remove_tap_listener(rs);
179         unprotect_thread_critical_region();
180
181         free_srt_table_data(&rs->srt_table);
182         g_free(rs);
183 }
184
185
186
187 /* When called, this function will create a new instance of gtk-dcerpcstat.
188  */
189 static void
190 gtk_dcerpcstat_init(const char *optarg, void* userdata _U_)
191 {
192         dcerpcstat_t *rs;
193         guint32 i, max_procs;
194         char *title_string;
195         char *filter_string;
196         GtkWidget *vbox;
197         GtkWidget *stat_label;
198         GtkWidget *filter_label;
199         GtkWidget *bbox;
200         GtkWidget *close_bt;
201         dcerpc_sub_dissector *procs;
202         e_uuid_t uuid;
203         guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
204         int major, minor;
205         guint16 ver;
206         int pos = 0;
207         const char *filter = NULL;
208         GString *error_string;
209         int hf_opnum;
210
211         /*
212          * XXX - DCE RPC statistics are maintained only by major version,
213          * not by major and minor version, so the minor version number is
214          * ignored.
215          *
216          * Should we just stop supporting minor version numbers here?
217          * Or should we allow it to be omitted?  Or should we keep
218          * separate statistics for different minor version numbers,
219          * and allow the minor version number to be omitted, and
220          * report aggregate statistics for all minor version numbers
221          * if it's omitted?
222          */
223         if(sscanf(
224                    optarg,
225                    "dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d,%n",
226                    &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos)
227            == 13) {
228                 uuid.Data1    = d1;
229                 uuid.Data2    = d2;
230                 uuid.Data3    = d3;
231                 uuid.Data4[0] = d40;
232                 uuid.Data4[1] = d41;
233                 uuid.Data4[2] = d42;
234                 uuid.Data4[3] = d43;
235                 uuid.Data4[4] = d44;
236                 uuid.Data4[5] = d45;
237                 uuid.Data4[6] = d46;
238                 uuid.Data4[7] = d47;
239                 if(pos) {
240                         filter = optarg+pos;
241                 } else {
242                         filter = NULL;
243                 }
244         } else {
245                 fprintf(stderr, "wireshark: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
246                 exit(1);
247         }
248         if ((major < 0) || (major > 65535)) {
249                 fprintf(stderr,"wireshark: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535\n", major);
250                 exit(1);
251         }
252         if ((minor < 0) || (minor > 65535)) {
253                 fprintf(stderr,"wireshark: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535\n", minor);
254                 exit(1);
255         }
256         ver = major;
257
258         rs = g_malloc(sizeof(dcerpcstat_t));
259         rs->prog = dcerpc_get_proto_name(&uuid, ver);
260         if(!rs->prog){
261                 g_free(rs);
262                 fprintf(stderr,
263                         "wireshark: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%u not supported\n",
264                         uuid.Data1,uuid.Data2,uuid.Data3,uuid.Data4[0],uuid.Data4[1],uuid.Data4[2],uuid.Data4[3],uuid.Data4[4],uuid.Data4[5],uuid.Data4[6],uuid.Data4[7],ver);
265                 exit(1);
266         }
267         hf_opnum = dcerpc_get_proto_hf_opnum(&uuid, ver);
268         procs    = dcerpc_get_proto_sub_dissector(&uuid, ver);
269         rs->uuid = uuid;
270         rs->ver  = ver;
271
272         rs->win  = dlg_window_new("dcerpc-stat");  /* transient_for top_level */
273         gtk_window_set_destroy_with_parent(GTK_WINDOW(rs->win), TRUE);
274
275         dcerpcstat_set_title(rs);
276         gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
277
278         vbox = gtk_vbox_new(FALSE, 3);
279         gtk_container_add(GTK_CONTAINER(rs->win), vbox);
280         gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
281
282         title_string = dcerpcstat_gen_title(rs);
283         stat_label   = gtk_label_new(title_string);
284         g_free(title_string);
285         gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
286
287         filter_string = g_strdup_printf("Filter: %s",filter ? filter : "");
288         filter_label  = gtk_label_new(filter_string);
289         g_free(filter_string);
290         gtk_label_set_line_wrap(GTK_LABEL(filter_label), TRUE);
291         gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
292
293         for(i=0,max_procs=0;procs[i].name;i++){
294                 if(procs[i].num>max_procs){
295                         max_procs = procs[i].num;
296                 }
297         }
298         rs->num_procedures = max_procs+1;
299
300         /* We must display TOP LEVEL Widget before calling init_srt_table() */
301         gtk_widget_show_all(rs->win);
302
303         if(hf_opnum != -1){
304                 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
305         } else {
306                 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
307         }
308
309         for(i=0;i<(max_procs+1);i++){
310                 int j;
311                 const char *proc_name;
312
313                 proc_name = "unknown";
314                 for(j=0;procs[j].name;j++){
315                         if (procs[j].num == i){
316                                 proc_name = procs[j].name;
317                         }
318                 }
319
320                 init_srt_table_row(&rs->srt_table, i, proc_name);
321         }
322
323
324         error_string = register_tap_listener("dcerpc", rs, filter, 0, dcerpcstat_reset, dcerpcstat_packet, dcerpcstat_draw);
325         if(error_string){
326                 /* error, we failed to attach to the tap. clean up */
327                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
328                 g_string_free(error_string, TRUE);
329                 free_srt_table_data(&rs->srt_table);
330                 g_free(rs);
331                 return;
332         }
333
334         /* Button row. */
335         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
336         gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
337
338         close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
339         window_set_cancel_button(rs->win, close_bt, window_cancel_button_cb);
340
341         g_signal_connect(rs->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
342         g_signal_connect(rs->win, "destroy",      G_CALLBACK(win_destroy_cb), rs);
343
344         gtk_widget_show_all(rs->win);
345         window_present(rs->win);
346
347         cf_retap_packets(&cfile);
348         gdk_window_raise(gtk_widget_get_window(rs->win));
349 }
350
351
352
353 static e_uuid_t          *dcerpc_uuid_program;
354 static guint16            dcerpc_version;
355 static GtkWidget         *dlg = NULL;
356 static GtkWidget         *filter_entry;
357 static dcerpc_uuid_key   *current_uuid_key;
358 static dcerpc_uuid_value *current_uuid_value;
359 static dcerpc_uuid_key   *new_uuid_key;
360 static dcerpc_uuid_value *new_uuid_value;
361
362 static void
363 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
364 {
365         GString *str;
366         const char *filter;
367
368         if (dcerpc_uuid_program == NULL) {
369                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Please select a program");
370                 return;
371         }
372         str = g_string_new("dcerpc,srt");
373         g_string_append_printf(str,
374             ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%u.%u",
375             dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
376             dcerpc_uuid_program->Data3,
377             dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
378             dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
379             dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
380             dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
381             dcerpc_version, 0);
382         filter = gtk_entry_get_text(GTK_ENTRY(filter_entry));
383         if(filter[0] != 0){
384                 g_string_append_printf(str, ",%s", filter);
385         }
386
387         gtk_dcerpcstat_init(str->str,NULL);
388         g_string_free(str, TRUE);
389 }
390
391
392 static void
393 dcerpcstat_version_select(GtkWidget *vers_combo_box, gpointer user_data _U_)
394 {
395         dcerpc_uuid_key *k;
396
397         if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(vers_combo_box), (gpointer)&k)) {
398                 g_assert_not_reached();  /* Programming error: somehow no active item */
399         }
400
401         dcerpc_version = k->ver;
402 }
403
404 static void
405 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer user_data)
406 {
407         dcerpc_uuid_key *k = (dcerpc_uuid_key *)key;
408         GtkWidget       *vers_combo_box = user_data;
409         char vs[5];
410
411         if(!uuid_equal(&(k->uuid), dcerpc_uuid_program)){
412                 return;
413         }
414         g_snprintf(vs, sizeof(vs), "%u", k->ver);
415         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(vers_combo_box), vs, k);
416 }
417
418 static void
419 dcerpcstat_program_select(GtkWidget *prog_combo_box, gpointer user_data)
420 {
421         dcerpc_uuid_key *k;
422         GtkWidget *vers_combo_box;
423
424         vers_combo_box = user_data;
425
426         if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(prog_combo_box), (gpointer)&k)) {
427                 g_assert_not_reached();  /* Programming error: somehow no active item */
428         }
429
430         g_signal_handlers_disconnect_by_func(vers_combo_box, G_CALLBACK(dcerpcstat_version_select), NULL );
431         ws_combo_box_clear_text_and_pointer(GTK_COMBO_BOX(vers_combo_box));
432
433         g_assert((k != NULL) && "dcerpc_stat: invalid selection"); /* Somehow selected top level ?? */
434         dcerpc_uuid_program = &(k->uuid);
435
436         /* re-create version menu */
437         g_signal_handlers_disconnect_by_func(vers_combo_box, G_CALLBACK(dcerpcstat_version_select), NULL );
438         ws_combo_box_clear_text_and_pointer(GTK_COMBO_BOX(vers_combo_box));
439
440         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, vers_combo_box);
441
442         g_signal_connect(vers_combo_box, "changed", G_CALLBACK(dcerpcstat_version_select), NULL);
443         ws_combo_box_set_active(GTK_COMBO_BOX(vers_combo_box), 0); /* default: triggers dcerpcstat_version_select callback */
444
445 }
446
447 static GtkTreeIter
448 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v, GtkWidget *prog_combo_box, int program_item_index)
449 {
450         static GtkTreeIter iter;
451         char str[64];
452
453         switch(program_item_index%15){
454         case 0:
455                 g_snprintf(str,sizeof(str),"%s ...",v->name);
456                 iter = ws_combo_box_append_text_and_pointer_full(
457                         GTK_COMBO_BOX(prog_combo_box), NULL, str, NULL, FALSE); /* top-level entries are insensitive */
458                 break;
459
460         default:
461                 break;
462         }
463
464         return ws_combo_box_append_text_and_pointer_full(
465                 GTK_COMBO_BOX(prog_combo_box), &iter, v->name, k, TRUE);
466 }
467
468 static void
469 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
470 {
471         dcerpc_uuid_key   *k = (dcerpc_uuid_key *)key;
472         dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
473
474         /* first time called, just set new_uuid to this one */
475         if((current_uuid_key==NULL) && (new_uuid_key==NULL)){
476                 new_uuid_key   = k;
477                 new_uuid_value = v;
478                 return;
479         }
480
481         /* if we haven't got a current one yet, just check the new
482            and scan for the first one alphabetically  */
483         if(current_uuid_key==NULL){
484                 if(strcmp(new_uuid_value->name, v->name)>0){
485                         new_uuid_key   = k;
486                         new_uuid_value = v;
487                         return;
488                 }
489                 return;
490         }
491
492         /* searching for the next one we are only interested in those
493            that sorts alphabetically after the current one */
494         if(strcmp(current_uuid_value->name, v->name) >= 0){
495                 /* this one doesnt so just skip it */
496                 return;
497         }
498
499         /* is it the first potential new entry? */
500         if(new_uuid_key==NULL){
501                 new_uuid_key   = k;
502                 new_uuid_value = v;
503                 return;
504         }
505
506         /* does it sort before the current new one? */
507         if(strcmp(new_uuid_value->name, v->name) > 0){
508                 new_uuid_key   = k;
509                 new_uuid_value = v;
510                 return;
511         }
512
513         return;
514 }
515
516
517 static void
518 dlg_destroy_cb(GtkWidget *w _U_, gpointer user_data _U_)
519 {
520         dlg = NULL;
521 }
522
523
524 #ifdef MAIN_MENU_USE_UIMANAGER
525 void gtk_dcerpcstat_cb(GtkAction *action _U_, gpointer user_data _U_)
526 #else
527 static void
528 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
529 #endif
530 {
531         GtkWidget       *dlg_box;
532         GtkWidget       *prog_box,   *prog_label, *prog_combo_box;
533         GtkWidget       *vers_label, *vers_combo_box;
534         GtkWidget       *filter_box, *filter_bt;
535         GtkWidget       *bbox, *start_button, *cancel_button;
536         GtkCellRenderer *cell_renderer;
537 #if 0
538         GtkTreeIter      program_first_item_iter;
539 #endif
540         const char      *filter;
541         int              program_item_index = 0;
542
543         static construct_args_t args = {
544           "Service Response Time Statistics Filter",
545           FALSE,
546           FALSE,
547           FALSE
548         };
549
550         /* if the window is already open, bring it to front and
551            un-minimize it, as necessary */
552         if(dlg){
553                 reactivate_window(dlg);
554                 return;
555         }
556
557         dlg = dlg_window_new("Wireshark: Compute DCE-RPC SRT statistics");
558         gtk_window_set_default_size(GTK_WINDOW(dlg), 400, -1);
559
560         dlg_box = gtk_vbox_new(FALSE, 10);
561         gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
562         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
563         gtk_widget_show(dlg_box);
564
565         /* Program box */
566         prog_box = gtk_hbox_new(FALSE, 3);
567
568         /* Program label */
569         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
570         prog_label = gtk_label_new("Program:");
571         gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
572         gtk_widget_show(prog_label);
573
574         /* Program menu */
575         dcerpc_uuid_program = NULL;   /* default: no program selected */
576
577         /* The "program combo box" is implemented with a two-level tree.
578            Each top-level of the tree has (up to) 15 selectable "program name"
579            children and shows the name of the first child of that entry
580            as "child_name ...". Each of the top-level entries can be expanded
581            (to show the children) but is "insensitive": ie: cannot be selected.
582            (dcerpcstat_add_program_to_menu() does the actual work to add entries
583             to the combo box).
584             XXX: A simpler alternative might be to just do away with all the two-level
585                  complexity and just use a standard ws_combo_box... even though the
586                  list of "program names" is quite large.
587             XXX: The gtkrc file distributed with Windows Wireshark has the
588                  "appears-as-list" GtkComboBox style property set to 1 and thus
589                  on Windows the entries for this combo box will appear as a tree-view.
590                  The default is 0(FALSE). In this case the the combo box entries will
591                  display as a menu with sub-menus.
592                  A possibility would be to set "appears-as-list" to 0  just for this
593                  particular combo box on Windows so that the entries will appear as a
594                  menu even on Windows).
595         */
596         prog_combo_box = ws_combo_box_new_text_and_pointer_full(&cell_renderer);
597         {
598                 /* XXX: Hack So that the top-level insensitive entries don't show
599                         as "grayed out"; The "foreground normal" color is used instead.
600                         This may not really be necessary but seems better to me.
601                 */
602 #if GTK_CHECK_VERSION(3,0,0)
603                 GtkStyleContext *context;
604                 GdkRGBA                 *new_rgba_fg_color;
605                 context = gtk_widget_get_style_context (prog_combo_box);
606                 gtk_style_context_get (context, GTK_STATE_NORMAL,
607                                  "color", &new_rgba_fg_color,
608                                   NULL);
609
610                 g_object_set(cell_renderer,
611                              "foreground-rgba", &new_rgba_fg_color,
612                              "foreground-set", TRUE,
613                              NULL);
614
615 #else
616                 GtkStyle *s;
617                 s = gtk_widget_get_style(prog_combo_box);
618                 g_object_set(cell_renderer,
619                              "foreground-gdk", &(s->fg[GTK_STATE_NORMAL]),
620                              "foreground-set", TRUE,
621                              NULL);
622 #endif
623         }
624
625         current_uuid_key   = NULL;
626         current_uuid_value = NULL;
627         do {
628                 new_uuid_key   = NULL;
629                 new_uuid_value = NULL;
630                 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
631                 if(new_uuid_key){
632 #if 0
633                         GtkTreeIter tmp_iter;
634                         tmp_iter = dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value,
635                                                                   prog_combo_box, program_item_index);
636                         if (program_item_index == 0)
637                                 program_first_item_iter = tmp_iter;
638 #else
639                         dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value,
640                                                         prog_combo_box, program_item_index);
641 #endif
642                         program_item_index += 1;
643                 }
644                 current_uuid_key   = new_uuid_key;
645                 current_uuid_value = new_uuid_value;
646         } while(new_uuid_key != NULL);
647         gtk_box_pack_start(GTK_BOX(prog_box), prog_combo_box, TRUE, TRUE, 0);
648         gtk_widget_show(prog_combo_box);
649
650         /* Version label */
651         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
652         vers_label = gtk_label_new("Version:");
653         gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
654         gtk_widget_show(vers_label);
655
656         /* Version combo-box */
657         /* Note: version combo box rows set when dcerpcstat_program_select() callback invoked */
658         vers_combo_box = ws_combo_box_new_text_and_pointer();
659         gtk_box_pack_start(GTK_BOX(prog_box), vers_combo_box, TRUE, TRUE, 0);
660         gtk_widget_show(vers_combo_box);
661
662         g_signal_connect(prog_combo_box, "changed", G_CALLBACK(dcerpcstat_program_select), vers_combo_box);
663 #if 0 /* Don't select an active entry given the way the drop down treeview appears if a default (active) entry is set */
664         ws_combo_box_set_active_iter(GTK_COMBO_BOX(prog_combo_box), &program_first_item_iter); /* triggers callback */
665 #endif
666         gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
667         gtk_widget_show(prog_box);
668
669         /* Filter box */
670         filter_box = gtk_hbox_new(FALSE, 3);
671
672         /* Filter label */
673         filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
674         g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &args);
675         gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
676         gtk_widget_show(filter_bt);
677
678         /* Filter entry */
679         filter_entry = gtk_entry_new();
680         g_signal_connect(filter_entry, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
681         g_object_set_data(G_OBJECT(filter_box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
682         g_signal_connect(filter_entry, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
683         g_signal_connect(dlg, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
684         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
685         filter = gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
686         if(filter){
687                 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
688         } else {
689                 colorize_filter_te_as_empty(filter_entry);
690         }
691         gtk_widget_show(filter_entry);
692
693         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
694         gtk_widget_show(filter_box);
695
696         g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_entry);
697
698         /* button box */
699         bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
700         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
701         gtk_widget_show(bbox);
702
703         start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
704         g_signal_connect_swapped(start_button, "clicked",
705                                  G_CALLBACK(dcerpcstat_start_button_clicked), NULL);
706
707         cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
708         window_set_cancel_button(dlg, cancel_button, window_cancel_button_cb);
709
710         g_signal_connect(dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
711         g_signal_connect(dlg, "destroy", G_CALLBACK(dlg_destroy_cb), NULL);
712
713         /* Catch the "activate" signal on the filter text entry, so that
714            if the user types Return there, we act as if the "Create Stat"
715            button had been selected, as happens if Return is typed if some
716            widget that *doesn't* handle the Return key has the input
717            focus. */
718         dlg_set_activate(filter_entry, start_button);
719
720         gtk_widget_grab_default(start_button );
721
722         /* Give the initial focus to the "Filter" entry box. */
723         gtk_widget_grab_focus(filter_entry);
724
725         gtk_widget_show_all(dlg);
726         window_present(dlg);
727 }
728
729 void
730 register_tap_listener_gtkdcerpcstat(void)
731 {
732         register_stat_cmd_arg("dcerpc,srt,", gtk_dcerpcstat_init,NULL);
733
734 #ifdef MAIN_MENU_USE_UIMANAGER
735 #else
736         register_stat_menu_item("DCE-RPC...", REGISTER_STAT_GROUP_RESPONSE_TIME,
737             gtk_dcerpcstat_cb, NULL, NULL, NULL);
738 #endif
739 }