c75af2a32ee249b0c93f9d593d28e06cef689b8d
[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 <string.h>
37
38 #include <gtk/gtk.h>
39
40 #include <epan/packet_info.h>
41 #include <epan/epan.h>
42 #include <epan/stat_cmd_args.h>
43 #include <epan/tap.h>
44 #include <epan/dissectors/packet-dcerpc.h>
45
46 #include "../stat_menu.h"
47 #include "../simple_dialog.h"
48 #include "../register.h"
49 #include "../globals.h"
50
51 #include "gtk/gui_stat_menu.h"
52 #include "gtk/dlg_utils.h"
53 #include "gtk/gui_utils.h"
54 #include "gtk/filter_dlg.h"
55 #include "gtk/stock_icons.h"
56 #include "gtk/service_response_time_table.h"
57 #include "gtk/gtkglobals.h"
58 #include "gtk/main.h"
59 #include "gtk/filter_autocomplete.h"
60
61
62 /* used to keep track of the statistics for an entire program interface */
63 typedef struct _rpcstat_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 } rpcstat_t;
71
72
73 static int
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 0;
88         }
89         return 1;
90 }
91
92 static char *
93 dcerpcstat_gen_title(rpcstat_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(rpcstat_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         rpcstat_t *rs = rs_arg;
115
116         reset_srt_table_data(&rs->srt_table);
117         dcerpcstat_set_title(rs);
118 }
119
120
121 static int
122 dcerpcstat_packet(void *rs_arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ri_arg)
123 {
124         rpcstat_t *rs = rs_arg;
125         const dcerpc_info *ri = ri_arg;
126
127         if(!ri->call_data){
128                 return 0;
129         }
130         if(!ri->call_data->req_frame){
131                 /* we have not seen the request so we dont know the delta*/
132                 return 0;
133         }
134         if(ri->call_data->opnum>=rs->num_procedures){
135                 /* dont handle this since its outside of known table */
136                 return 0;
137         }
138
139         /* we are only interested in reply packets */
140         if(ri->ptype != PDU_RESP){
141                 return 0;
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 0;
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 1;
155 }
156
157 static void
158 dcerpcstat_draw(void *rs_arg)
159 {
160         rpcstat_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         rpcstat_t *rs=(rpcstat_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         rpcstat_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(optarg,"dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d,%n", &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos)==13){
224                 uuid.Data1=d1;
225                 uuid.Data2=d2;
226                 uuid.Data3=d3;
227                 uuid.Data4[0]=d40;
228                 uuid.Data4[1]=d41;
229                 uuid.Data4[2]=d42;
230                 uuid.Data4[3]=d43;
231                 uuid.Data4[4]=d44;
232                 uuid.Data4[5]=d45;
233                 uuid.Data4[6]=d46;
234                 uuid.Data4[7]=d47;
235                 if(pos){
236                         filter=optarg+pos;
237                 } else {
238                         filter=NULL;
239                 }
240         } else {
241                 fprintf(stderr, "wireshark: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
242                 exit(1);
243         }
244         if (major < 0 || major > 65535) {
245                 fprintf(stderr,"wireshark: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535\n", major);
246                 exit(1);
247         }
248         if (minor < 0 || minor > 65535) {
249                 fprintf(stderr,"wireshark: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535\n", minor);
250                 exit(1);
251         }
252         ver = major;
253
254         rs=g_malloc(sizeof(rpcstat_t));
255         rs->prog=dcerpc_get_proto_name(&uuid, ver);
256         if(!rs->prog){
257                 g_free(rs);
258                 fprintf(stderr,"wireshark: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%u not supported\n",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);
259                 exit(1);
260         }
261         hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, ver);
262         procs=dcerpc_get_proto_sub_dissector(&uuid, ver);
263         rs->uuid=uuid;
264         rs->ver=ver;
265
266         rs->win = dlg_window_new("dcerpc-stat");  /* transient_for top_level */
267         gtk_window_set_destroy_with_parent (GTK_WINDOW(rs->win), TRUE);
268
269         dcerpcstat_set_title(rs);
270         gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
271
272         vbox=gtk_vbox_new(FALSE, 3);
273         gtk_container_add(GTK_CONTAINER(rs->win), vbox);
274         gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
275
276         title_string=dcerpcstat_gen_title(rs);
277         stat_label=gtk_label_new(title_string);
278         g_free(title_string);
279         gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
280
281         filter_string = g_strdup_printf("Filter: %s",filter ? filter : "");
282         filter_label=gtk_label_new(filter_string);
283         g_free(filter_string);
284         gtk_label_set_line_wrap(GTK_LABEL(filter_label), TRUE);
285         gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
286
287         for(i=0,max_procs=0;procs[i].name;i++){
288                 if(procs[i].num>max_procs){
289                         max_procs=procs[i].num;
290                 }
291         }
292         rs->num_procedures=max_procs+1;
293
294         /* We must display TOP LEVEL Widget before calling init_srt_table() */
295         gtk_widget_show_all(rs->win);
296
297         if(hf_opnum!=-1){
298                 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
299         } else {
300                 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
301         }
302
303         for(i=0;i<(max_procs+1);i++){
304                 int j;
305                 const char *proc_name;
306
307                 proc_name="unknown";
308                 for(j=0;procs[j].name;j++){
309                         if(procs[j].num==i){
310                                 proc_name=procs[j].name;
311                         }
312                 }
313
314                 init_srt_table_row(&rs->srt_table, i, proc_name);
315         }
316
317
318         error_string=register_tap_listener("dcerpc", rs, filter, 0, dcerpcstat_reset, dcerpcstat_packet, dcerpcstat_draw);
319         if(error_string){
320                 /* error, we failed to attach to the tap. clean up */
321                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
322                 g_string_free(error_string, TRUE);
323                 free_srt_table_data(&rs->srt_table);
324                 g_free(rs);
325                 return;
326         }
327
328         /* Button row. */
329         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
330         gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
331
332         close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
333         window_set_cancel_button(rs->win, close_bt, window_cancel_button_cb);
334
335         g_signal_connect(rs->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
336         g_signal_connect(rs->win, "destroy", G_CALLBACK(win_destroy_cb), rs);
337
338         gtk_widget_show_all(rs->win);
339         window_present(rs->win);
340
341         cf_retap_packets(&cfile);
342         gdk_window_raise(rs->win->window);
343 }
344
345
346
347 static e_uuid_t *dcerpc_uuid_program=NULL;
348 static guint16 dcerpc_version;
349 static GtkWidget *dlg=NULL;
350 static GtkWidget *prog_menu;
351 static GtkWidget *vers_opt, *vers_menu;
352 static GtkWidget *filter_entry;
353 static dcerpc_uuid_key *current_uuid_key=NULL;
354 static dcerpc_uuid_value *current_uuid_value=NULL;
355 static dcerpc_uuid_key *new_uuid_key=NULL;
356 static dcerpc_uuid_value *new_uuid_value=NULL;
357
358
359 static void
360 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
361 {
362         GString *str;
363         const char *filter;
364
365         str = g_string_new("dcerpc,srt");
366         g_string_append_printf(str,
367             ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%u.%u",
368             dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
369             dcerpc_uuid_program->Data3,
370             dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
371             dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
372             dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
373             dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
374             dcerpc_version, 0);
375         filter=gtk_entry_get_text(GTK_ENTRY(filter_entry));
376         if(filter[0]!=0){
377                 g_string_append_printf(str, ",%s", filter);
378         }
379
380         gtk_dcerpcstat_init(str->str,NULL);
381         g_string_free(str, TRUE);
382 }
383
384
385 static void
386 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
387 {
388         int vers=(long)key;
389
390         dcerpc_version=vers;
391 }
392
393
394
395
396 static void *
397 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
398 {
399         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
400         GtkWidget *menu_item;
401         char vs[5];
402
403         if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
404                 return NULL;
405         }
406
407         g_snprintf(vs, sizeof(vs), "%u",k->ver);
408         menu_item=gtk_menu_item_new_with_label(vs);
409         g_signal_connect(menu_item, "activate", G_CALLBACK(dcerpcstat_version_select),
410                        (gpointer)((long)k->ver));
411         gtk_widget_show(menu_item);
412         gtk_menu_shell_append(GTK_MENU_SHELL(vers_menu), menu_item);
413
414         if(dcerpc_version==0xffff){
415                 dcerpc_version=k->ver;
416         }
417
418         return NULL;
419 }
420
421
422 static void
423 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
424 {
425         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
426
427         dcerpc_uuid_program=&k->uuid;
428
429         /* change version menu */
430         dcerpc_version=0xffff;
431         gtk_object_destroy(GTK_OBJECT(vers_menu));
432         vers_menu=gtk_menu_new();
433         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
434         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
435 }
436
437
438 static GtkWidget *program_submenu_menu;
439 static GtkWidget *program_submenu_item;
440 static GtkWidget *program_submenu_label;
441 static int program_subitem_index;
442 static const char *first_menu_name;
443 static void
444 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
445 {
446         GtkWidget *program_menu_item;
447         GtkWidget *box;
448         char str[64];
449
450         switch(program_subitem_index%15){
451         case 0:
452
453                 first_menu_name=v->name;
454                 g_snprintf(str,sizeof(str),"%s ...",v->name);
455                 program_submenu_item=gtk_menu_item_new();
456                 box=gtk_hbox_new(TRUE,0);
457                 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
458
459                 program_submenu_label=gtk_label_new(str);
460                 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
461                 gtk_widget_show(program_submenu_label);
462                 gtk_widget_show(box);
463
464                 gtk_menu_shell_append(GTK_MENU_SHELL(prog_menu), program_submenu_item);
465                 gtk_widget_show(program_submenu_item);
466
467                 program_submenu_menu=gtk_menu_new();
468                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
469                 break;
470         case 14:
471                 g_snprintf(str,sizeof(str),"%s - %s",first_menu_name,v->name);
472                 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
473                 break;
474 /*qqq*/
475         }
476         program_subitem_index++;
477
478         program_menu_item=gtk_menu_item_new_with_label(v->name);
479         g_signal_connect(program_menu_item, "activate", G_CALLBACK(dcerpcstat_program_select), k);
480
481         gtk_widget_show(program_menu_item);
482         gtk_menu_shell_append(GTK_MENU_SHELL(program_submenu_menu), program_menu_item);
483
484         if(!dcerpc_uuid_program){
485                 dcerpc_uuid_program=&k->uuid;
486         }
487
488         return;
489 }
490
491 static void *
492 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
493 {
494         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
495         dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
496
497         /* first time called, just set new_uuid to this one */
498         if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
499                 new_uuid_key=k;
500                 new_uuid_value=v;
501                 return NULL;
502         }
503
504         /* if we havent got a current one yet, just check the new
505            and scan for the first one alphabetically  */
506         if(current_uuid_key==NULL){
507                 if(strcmp(new_uuid_value->name, v->name)>0){
508                         new_uuid_key=k;
509                         new_uuid_value=v;
510                         return NULL;
511                 }
512                 return NULL;
513         }
514
515         /* searching for the next one we are only interested in those
516            that sorts alphabetically after the current one */
517         if(strcmp(current_uuid_value->name, v->name)>=0){
518                 /* this one doesnt so just skip it */
519                 return NULL;
520         }
521
522         /* is it the first potential new entry? */
523         if(new_uuid_key==NULL){
524                 new_uuid_key=k;
525                 new_uuid_value=v;
526                 return NULL;
527         }
528
529         /* does it sort before the current new one? */
530         if(strcmp(new_uuid_value->name, v->name)>0){
531                 new_uuid_key=k;
532                 new_uuid_value=v;
533                 return NULL;
534         }
535
536         return NULL;
537 }
538
539
540 static void
541 dlg_destroy_cb(void)
542 {
543         dlg=NULL;
544 }
545
546
547 static void
548 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
549 {
550         GtkWidget *dlg_box;
551         GtkWidget *prog_box, *prog_label, *prog_opt;
552         GtkWidget *vers_label;
553         GtkWidget *filter_box, *filter_bt;
554         GtkWidget *bbox, *start_button, *cancel_button;
555         const char *filter;
556         static construct_args_t args = {
557           "Service Response Time Statistics Filter",
558           FALSE,
559           FALSE,
560           FALSE
561         };
562
563         /* if the window is already open, bring it to front and
564            un-minimize it, as necessary */
565         if(dlg){
566                 reactivate_window(dlg);
567                 return;
568         }
569
570         dlg=dlg_window_new("Wireshark: Compute DCE-RPC SRT statistics");
571         gtk_window_set_default_size(GTK_WINDOW(dlg), 400, -1);
572
573         dlg_box=gtk_vbox_new(FALSE, 10);
574         gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
575         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
576         gtk_widget_show(dlg_box);
577
578         /* Program box */
579         prog_box=gtk_hbox_new(FALSE, 3);
580
581         /* Program label */
582         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
583         prog_label=gtk_label_new("Program:");
584         gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
585         gtk_widget_show(prog_label);
586
587         /* Program menu */
588         prog_opt=gtk_option_menu_new();
589         prog_menu=gtk_menu_new();
590         current_uuid_key=NULL;
591         current_uuid_value=NULL;
592 /*qqq*/
593         program_submenu_item=NULL;
594         program_submenu_menu=NULL;
595         program_subitem_index=0;
596         do {
597                 new_uuid_key=NULL;
598                 new_uuid_value=NULL;
599                 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
600                 if(new_uuid_key){
601                         dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
602                 }
603                 current_uuid_key=new_uuid_key;
604                 current_uuid_value=new_uuid_value;
605         } while(new_uuid_key!=NULL);
606
607         gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
608         gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
609         gtk_widget_show(prog_opt);
610
611         /* Version label */
612         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
613         vers_label=gtk_label_new("Version:");
614         gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
615         gtk_widget_show(vers_label);
616
617         /* Version menu */
618         vers_opt=gtk_option_menu_new();
619         vers_menu=gtk_menu_new();
620         dcerpc_version=0xffff;
621         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
622         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
623         gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
624         gtk_widget_show(vers_opt);
625
626         gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
627         gtk_widget_show(prog_box);
628
629         /* Filter box */
630         filter_box=gtk_hbox_new(FALSE, 3);
631
632         /* Filter label */
633         filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
634         g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &args);
635         gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
636         gtk_widget_show(filter_bt);
637
638         /* Filter entry */
639         filter_entry=gtk_entry_new();
640         g_signal_connect(filter_entry, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
641         g_object_set_data(G_OBJECT(filter_box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
642         g_signal_connect(filter_entry, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
643         g_signal_connect(dlg, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
644         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
645         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
646         if(filter){
647                 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
648         } else {
649                 colorize_filter_te_as_empty(filter_entry);
650         }
651         gtk_widget_show(filter_entry);
652
653         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
654         gtk_widget_show(filter_box);
655
656         g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_entry);
657
658         /* button box */
659         bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
660         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
661         gtk_widget_show(bbox);
662
663         start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
664         g_signal_connect_swapped(start_button, "clicked",
665                               G_CALLBACK(dcerpcstat_start_button_clicked), NULL);
666
667         cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
668         window_set_cancel_button(dlg, cancel_button, window_cancel_button_cb);
669
670         g_signal_connect(dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
671         g_signal_connect(dlg, "destroy", dlg_destroy_cb, NULL);
672
673         /* Catch the "activate" signal on the filter text entry, so that
674            if the user types Return there, we act as if the "Create Stat"
675            button had been selected, as happens if Return is typed if some
676            widget that *doesn't* handle the Return key has the input
677            focus. */
678         dlg_set_activate(filter_entry, start_button);
679
680         gtk_widget_grab_default(start_button );
681
682         /* Give the initial focus to the "Filter" entry box. */
683         gtk_widget_grab_focus(filter_entry);
684
685         gtk_widget_show_all(dlg);
686         window_present(dlg);
687 }
688
689 void
690 register_tap_listener_gtkdcerpcstat(void)
691 {
692         register_stat_cmd_arg("dcerpc,srt,", gtk_dcerpcstat_init,NULL);
693
694         register_stat_menu_item("DCE-RPC...", REGISTER_STAT_GROUP_RESPONSE_TIME,
695             gtk_dcerpcstat_cb, NULL, NULL, NULL);
696 }