ad77538a88ea2bb39d7b643a41332c3d9119ee10
[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=window_new(GTK_WINDOW_TOPLEVEL, "dcerpc-stat");
267         dcerpcstat_set_title(rs);
268         gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
269
270         vbox=gtk_vbox_new(FALSE, 3);
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, 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 = 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, FALSE);
340         gdk_window_raise(rs->win->window);
341 }
342
343
344
345 static e_uuid_t *dcerpc_uuid_program=NULL;
346 static guint16 dcerpc_version;
347 static GtkWidget *dlg=NULL;
348 static GtkWidget *prog_menu;
349 static GtkWidget *vers_opt, *vers_menu;
350 static GtkWidget *filter_entry;
351 static dcerpc_uuid_key *current_uuid_key=NULL;
352 static dcerpc_uuid_value *current_uuid_value=NULL;
353 static dcerpc_uuid_key *new_uuid_key=NULL;
354 static dcerpc_uuid_value *new_uuid_value=NULL;
355
356
357 static void
358 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
359 {
360         GString *str;
361         const char *filter;
362
363         str = g_string_new("dcerpc,srt");
364         g_string_append_printf(str,
365             ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%u.%u",
366             dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
367             dcerpc_uuid_program->Data3,
368             dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
369             dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
370             dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
371             dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
372             dcerpc_version, 0);
373         filter=gtk_entry_get_text(GTK_ENTRY(filter_entry));
374         if(filter[0]!=0){
375                 g_string_append_printf(str, ",%s", filter);
376         }
377
378         gtk_dcerpcstat_init(str->str,NULL);
379         g_string_free(str, TRUE);
380 }
381
382
383 static void
384 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
385 {
386         int vers=(long)key;
387
388         dcerpc_version=vers;
389 }
390
391
392
393
394 static void *
395 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
396 {
397         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
398         GtkWidget *menu_item;
399         char vs[5];
400
401         if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
402                 return NULL;
403         }
404
405         g_snprintf(vs, sizeof(vs), "%u",k->ver);
406         menu_item=gtk_menu_item_new_with_label(vs);
407         g_signal_connect(menu_item, "activate", G_CALLBACK(dcerpcstat_version_select),
408                        (gpointer)((long)k->ver));
409         gtk_widget_show(menu_item);
410         gtk_menu_shell_append(GTK_MENU_SHELL(vers_menu), menu_item);
411
412         if(dcerpc_version==0xffff){
413                 dcerpc_version=k->ver;
414         }
415
416         return NULL;
417 }
418
419
420 static void
421 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
422 {
423         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
424
425         dcerpc_uuid_program=&k->uuid;
426
427         /* change version menu */
428         dcerpc_version=0xffff;
429         gtk_object_destroy(GTK_OBJECT(vers_menu));
430         vers_menu=gtk_menu_new();
431         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
432         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
433 }
434
435
436 static GtkWidget *program_submenu_menu;
437 static GtkWidget *program_submenu_item;
438 static GtkWidget *program_submenu_label;
439 static int program_subitem_index;
440 static const char *first_menu_name;
441 static void
442 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
443 {
444         GtkWidget *program_menu_item;
445         GtkWidget *box;
446         char str[64];
447
448         switch(program_subitem_index%15){
449         case 0:
450
451                 first_menu_name=v->name;
452                 g_snprintf(str,sizeof(str),"%s ...",v->name);
453                 program_submenu_item=gtk_menu_item_new();
454                 box=gtk_hbox_new(TRUE,0);
455                 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
456
457                 program_submenu_label=gtk_label_new(str);
458                 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
459                 gtk_widget_show(program_submenu_label);
460                 gtk_widget_show(box);
461
462                 gtk_menu_shell_append(GTK_MENU_SHELL(prog_menu), program_submenu_item);
463                 gtk_widget_show(program_submenu_item);
464
465                 program_submenu_menu=gtk_menu_new();
466                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
467                 break;
468         case 14:
469                 g_snprintf(str,sizeof(str),"%s - %s",first_menu_name,v->name);
470                 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
471                 break;
472 /*qqq*/
473         }
474         program_subitem_index++;
475
476         program_menu_item=gtk_menu_item_new_with_label(v->name);
477         g_signal_connect(program_menu_item, "activate", G_CALLBACK(dcerpcstat_program_select), k);
478
479         gtk_widget_show(program_menu_item);
480         gtk_menu_shell_append(GTK_MENU_SHELL(program_submenu_menu), program_menu_item);
481
482         if(!dcerpc_uuid_program){
483                 dcerpc_uuid_program=&k->uuid;
484         }
485
486         return;
487 }
488
489 static void *
490 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
491 {
492         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
493         dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
494
495         /* first time called, just set new_uuid to this one */
496         if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
497                 new_uuid_key=k;
498                 new_uuid_value=v;
499                 return NULL;
500         }
501
502         /* if we havent got a current one yet, just check the new
503            and scan for the first one alphabetically  */
504         if(current_uuid_key==NULL){
505                 if(strcmp(new_uuid_value->name, v->name)>0){
506                         new_uuid_key=k;
507                         new_uuid_value=v;
508                         return NULL;
509                 }
510                 return NULL;
511         }
512
513         /* searching for the next one we are only interested in those
514            that sorts alphabetically after the current one */
515         if(strcmp(current_uuid_value->name, v->name)>=0){
516                 /* this one doesnt so just skip it */
517                 return NULL;
518         }
519
520         /* is it the first potential new entry? */
521         if(new_uuid_key==NULL){
522                 new_uuid_key=k;
523                 new_uuid_value=v;
524                 return NULL;
525         }
526
527         /* does it sort before the current new one? */
528         if(strcmp(new_uuid_value->name, v->name)>0){
529                 new_uuid_key=k;
530                 new_uuid_value=v;
531                 return NULL;
532         }
533
534         return NULL;
535 }
536
537
538 static void
539 dlg_destroy_cb(void)
540 {
541         dlg=NULL;
542 }
543
544
545 static void
546 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
547 {
548         GtkWidget *dlg_box;
549         GtkWidget *prog_box, *prog_label, *prog_opt;
550         GtkWidget *vers_label;
551         GtkWidget *filter_box, *filter_bt;
552         GtkWidget *bbox, *start_button, *cancel_button;
553         const char *filter;
554         static construct_args_t args = {
555           "Service Response Time Statistics Filter",
556           FALSE,
557           FALSE,
558           FALSE
559         };
560
561         /* if the window is already open, bring it to front and
562            un-minimize it, as necessary */
563         if(dlg){
564                 reactivate_window(dlg);
565                 return;
566         }
567
568         dlg=dlg_window_new("Wireshark: Compute DCE-RPC SRT statistics");
569         gtk_window_set_default_size(GTK_WINDOW(dlg), 400, -1);
570
571         dlg_box=gtk_vbox_new(FALSE, 10);
572         gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
573         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
574         gtk_widget_show(dlg_box);
575
576         /* Program box */
577         prog_box=gtk_hbox_new(FALSE, 3);
578
579         /* Program label */
580         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
581         prog_label=gtk_label_new("Program:");
582         gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
583         gtk_widget_show(prog_label);
584
585         /* Program menu */
586         prog_opt=gtk_option_menu_new();
587         prog_menu=gtk_menu_new();
588         current_uuid_key=NULL;
589         current_uuid_value=NULL;
590 /*qqq*/
591         program_submenu_item=NULL;
592         program_submenu_menu=NULL;
593         program_subitem_index=0;
594         do {
595                 new_uuid_key=NULL;
596                 new_uuid_value=NULL;
597                 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
598                 if(new_uuid_key){
599                         dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
600                 }
601                 current_uuid_key=new_uuid_key;
602                 current_uuid_value=new_uuid_value;
603         } while(new_uuid_key!=NULL);
604
605         gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
606         gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
607         gtk_widget_show(prog_opt);
608
609         /* Version label */
610         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
611         vers_label=gtk_label_new("Version:");
612         gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
613         gtk_widget_show(vers_label);
614
615         /* Version menu */
616         vers_opt=gtk_option_menu_new();
617         vers_menu=gtk_menu_new();
618         dcerpc_version=0xffff;
619         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
620         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
621         gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
622         gtk_widget_show(vers_opt);
623
624         gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
625         gtk_widget_show(prog_box);
626
627         /* Filter box */
628         filter_box=gtk_hbox_new(FALSE, 3);
629
630         /* Filter label */
631         filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
632         g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &args);
633         gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
634         gtk_widget_show(filter_bt);
635
636         /* Filter entry */
637         filter_entry=gtk_entry_new();
638         g_signal_connect(filter_entry, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
639         g_object_set_data(G_OBJECT(filter_box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
640         g_signal_connect(filter_entry, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
641         g_signal_connect(dlg, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
642         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
643         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
644         if(filter){
645                 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
646         } else {
647                 colorize_filter_te_as_empty(filter_entry);
648         }
649         gtk_widget_show(filter_entry);
650
651         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
652         gtk_widget_show(filter_box);
653
654         g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_entry);
655
656         /* button box */
657         bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
658         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
659         gtk_widget_show(bbox);
660
661         start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
662         g_signal_connect_swapped(start_button, "clicked",
663                               G_CALLBACK(dcerpcstat_start_button_clicked), NULL);
664
665         cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
666         window_set_cancel_button(dlg, cancel_button, window_cancel_button_cb);
667
668         g_signal_connect(dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
669         g_signal_connect(dlg, "destroy", dlg_destroy_cb, NULL);
670
671         /* Catch the "activate" signal on the filter text entry, so that
672            if the user types Return there, we act as if the "Create Stat"
673            button had been selected, as happens if Return is typed if some
674            widget that *doesn't* handle the Return key has the input
675            focus. */
676         dlg_set_activate(filter_entry, start_button);
677
678         gtk_widget_grab_default(start_button );
679
680         /* Give the initial focus to the "Filter" entry box. */
681         gtk_widget_grab_focus(filter_entry);
682
683         gtk_widget_show_all(dlg);
684         window_present(dlg);
685 }
686
687 void
688 register_tap_listener_gtkdcerpcstat(void)
689 {
690         register_stat_cmd_arg("dcerpc,srt,", gtk_dcerpcstat_init,NULL);
691
692         register_stat_menu_item("DCE-RPC...", REGISTER_STAT_GROUP_RESPONSE_TIME,
693             gtk_dcerpcstat_cb, NULL, NULL, NULL);
694 }