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