Fix for bug 2964.
[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
60
61 /* used to keep track of the statistics for an entire program interface */
62 typedef struct _rpcstat_t {
63         GtkWidget *win;
64         srt_stat_table srt_table;
65         const char *prog;
66         e_uuid_t uuid;
67         guint16 ver;
68         int num_procedures;
69 } rpcstat_t;
70
71
72 static int
73 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
74 {
75         if( (uuid1->Data1!=uuid2->Data1)
76           ||(uuid1->Data2!=uuid2->Data2)
77           ||(uuid1->Data3!=uuid2->Data3)
78           ||(uuid1->Data4[0]!=uuid2->Data4[0])
79           ||(uuid1->Data4[1]!=uuid2->Data4[1])
80           ||(uuid1->Data4[2]!=uuid2->Data4[2])
81           ||(uuid1->Data4[3]!=uuid2->Data4[3])
82           ||(uuid1->Data4[4]!=uuid2->Data4[4])
83           ||(uuid1->Data4[5]!=uuid2->Data4[5])
84           ||(uuid1->Data4[6]!=uuid2->Data4[6])
85           ||(uuid1->Data4[7]!=uuid2->Data4[7]) ){
86                 return 0;
87         }
88         return 1;
89 }
90
91 static char *
92 dcerpcstat_gen_title(rpcstat_t *rs)
93 {
94         char *title;
95
96         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));
97         return title;
98 }
99
100 static void
101 dcerpcstat_set_title(rpcstat_t *rs)
102 {
103         char *title;
104
105         title = dcerpcstat_gen_title(rs);
106         gtk_window_set_title(GTK_WINDOW(rs->win), title);
107         g_free(title);
108 }
109
110 static void
111 dcerpcstat_reset(void *rs_arg)
112 {
113         rpcstat_t *rs = rs_arg;
114
115         reset_srt_table_data(&rs->srt_table);
116         dcerpcstat_set_title(rs);
117 }
118
119
120 static int
121 dcerpcstat_packet(void *rs_arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ri_arg)
122 {
123         rpcstat_t *rs = rs_arg;
124         const dcerpc_info *ri = ri_arg;
125
126         if(!ri->call_data){
127                 return 0;
128         }
129         if(!ri->call_data->req_frame){
130                 /* we have not seen the request so we dont know the delta*/
131                 return 0;
132         }
133         if(ri->call_data->opnum>=rs->num_procedures){
134                 /* dont handle this since its outside of known table */
135                 return 0;
136         }
137
138         /* we are only interested in reply packets */
139         if(ri->ptype != PDU_RESP){
140                 return 0;
141         }
142
143         /* we are only interested in certain program/versions */
144         if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
145           ||(ri->call_data->ver!=rs->ver)){
146                 return 0;
147         }
148
149
150         add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
151
152
153         return 1;
154 }
155
156 static void
157 dcerpcstat_draw(void *rs_arg)
158 {
159         rpcstat_t *rs = rs_arg;
160
161         draw_srt_table_data(&rs->srt_table);
162 }
163
164
165 /* since the gtk2 implementation of tap is multithreaded we must protect
166  * remove_tap_listener() from modifying the list while draw_tap_listener()
167  * is running.  the other protected block is in main.c
168  *
169  * there should not be any other critical regions in gtk2
170  */
171 static void
172 win_destroy_cb(GtkWindow *win _U_, gpointer data)
173 {
174         rpcstat_t *rs=(rpcstat_t *)data;
175
176         protect_thread_critical_region();
177         remove_tap_listener(rs);
178         unprotect_thread_critical_region();
179
180         free_srt_table_data(&rs->srt_table);
181         g_free(rs);
182 }
183
184
185
186 /* When called, this function will create a new instance of gtk-dcerpcstat.
187  */
188 static void
189 gtk_dcerpcstat_init(const char *optarg, void* userdata _U_)
190 {
191         rpcstat_t *rs;
192         guint32 i, max_procs;
193         char *title_string;
194         char *filter_string;
195         GtkWidget *vbox;
196         GtkWidget *stat_label;
197         GtkWidget *filter_label;
198         GtkWidget *bbox;
199         GtkWidget *close_bt;
200         dcerpc_sub_dissector *procs;
201         e_uuid_t uuid;
202         guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
203         int major, minor;
204         guint16 ver;
205         int pos=0;
206         const char *filter=NULL;
207         GString *error_string;
208         int hf_opnum;
209
210         /*
211          * XXX - DCE RPC statistics are maintained only by major version,
212          * not by major and minor version, so the minor version number is
213          * ignored.
214          *
215          * Should we just stop supporting minor version numbers here?
216          * Or should we allow it to be omitted?  Or should we keep
217          * separate statistics for different minor version numbers,
218          * and allow the minor version number to be omitted, and
219          * report aggregate statistics for all minor version numbers
220          * if it's omitted?
221          */
222         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){
223                 uuid.Data1=d1;
224                 uuid.Data2=d2;
225                 uuid.Data3=d3;
226                 uuid.Data4[0]=d40;
227                 uuid.Data4[1]=d41;
228                 uuid.Data4[2]=d42;
229                 uuid.Data4[3]=d43;
230                 uuid.Data4[4]=d44;
231                 uuid.Data4[5]=d45;
232                 uuid.Data4[6]=d46;
233                 uuid.Data4[7]=d47;
234                 if(pos){
235                         filter=optarg+pos;
236                 } else {
237                         filter=NULL;
238                 }
239         } else {
240                 fprintf(stderr, "wireshark: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
241                 exit(1);
242         }
243         if (major < 0 || major > 65535) {
244                 fprintf(stderr,"wireshark: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535\n", major);
245                 exit(1);
246         }
247         if (minor < 0 || minor > 65535) {
248                 fprintf(stderr,"wireshark: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535\n", minor);
249                 exit(1);
250         }
251         ver = major;
252
253         rs=g_malloc(sizeof(rpcstat_t));
254         rs->prog=dcerpc_get_proto_name(&uuid, ver);
255         if(!rs->prog){
256                 g_free(rs);
257                 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);
258                 exit(1);
259         }
260         hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, ver);
261         procs=dcerpc_get_proto_sub_dissector(&uuid, ver);
262         rs->uuid=uuid;
263         rs->ver=ver;
264
265         rs->win=window_new(GTK_WINDOW_TOPLEVEL, "dcerpc-stat");
266         dcerpcstat_set_title(rs);
267         gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
268
269         vbox=gtk_vbox_new(FALSE, 3);
270         gtk_container_add(GTK_CONTAINER(rs->win), vbox);
271         gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
272
273         title_string=dcerpcstat_gen_title(rs);
274         stat_label=gtk_label_new(title_string);
275         g_free(title_string);
276         gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
277
278         filter_string = g_strdup_printf("Filter: %s",filter ? filter : "");
279         filter_label=gtk_label_new(filter_string);
280         g_free(filter_string);
281         gtk_label_set_line_wrap(GTK_LABEL(filter_label), TRUE);
282         gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
283
284         for(i=0,max_procs=0;procs[i].name;i++){
285                 if(procs[i].num>max_procs){
286                         max_procs=procs[i].num;
287                 }
288         }
289         rs->num_procedures=max_procs+1;
290
291         /* We must display TOP LEVEL Widget before calling init_srt_table() */
292         gtk_widget_show_all(rs->win);
293
294         if(hf_opnum!=-1){
295                 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
296         } else {
297                 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
298         }
299
300         for(i=0;i<(max_procs+1);i++){
301                 int j;
302                 const char *proc_name;
303
304                 proc_name="unknown";
305                 for(j=0;procs[j].name;j++){
306                         if(procs[j].num==i){
307                                 proc_name=procs[j].name;
308                         }
309                 }
310
311                 init_srt_table_row(&rs->srt_table, i, proc_name);
312         }
313
314
315         error_string=register_tap_listener("dcerpc", rs, filter, dcerpcstat_reset, dcerpcstat_packet, dcerpcstat_draw);
316         if(error_string){
317                 /* error, we failed to attach to the tap. clean up */
318                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
319                 g_string_free(error_string, TRUE);
320                 free_srt_table_data(&rs->srt_table);
321                 g_free(rs);
322                 return;
323         }
324
325         /* Button row. */
326         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
327         gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
328
329         close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
330         window_set_cancel_button(rs->win, close_bt, window_cancel_button_cb);
331
332         g_signal_connect(rs->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
333         g_signal_connect(rs->win, "destroy", G_CALLBACK(win_destroy_cb), rs);
334
335         gtk_widget_show_all(rs->win);
336         window_present(rs->win);
337
338         cf_retap_packets(&cfile, FALSE);
339         gdk_window_raise(rs->win->window);
340 }
341
342
343
344 static e_uuid_t *dcerpc_uuid_program=NULL;
345 static guint16 dcerpc_version;
346 static GtkWidget *dlg=NULL;
347 static GtkWidget *prog_menu;
348 static GtkWidget *vers_opt, *vers_menu;
349 static GtkWidget *filter_entry;
350 static dcerpc_uuid_key *current_uuid_key=NULL;
351 static dcerpc_uuid_value *current_uuid_value=NULL;
352 static dcerpc_uuid_key *new_uuid_key=NULL;
353 static dcerpc_uuid_value *new_uuid_value=NULL;
354
355
356 static void
357 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
358 {
359         GString *str;
360         const char *filter;
361
362         str = g_string_new("dcerpc,srt");
363         g_string_append_printf(str,
364             ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%u.%u",
365             dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
366             dcerpc_uuid_program->Data3,
367             dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
368             dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
369             dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
370             dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
371             dcerpc_version, 0);
372         filter=gtk_entry_get_text(GTK_ENTRY(filter_entry));
373         if(filter[0]!=0){
374                 g_string_append_printf(str, ",%s", filter);
375         }
376
377         gtk_dcerpcstat_init(str->str,NULL);
378         g_string_free(str, TRUE);
379 }
380
381
382 static void
383 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
384 {
385         int vers=(long)key;
386
387         dcerpc_version=vers;
388 }
389
390
391
392
393 static void *
394 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
395 {
396         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
397         GtkWidget *menu_item;
398         char vs[5];
399
400         if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
401                 return NULL;
402         }
403
404         g_snprintf(vs, 5, "%u",k->ver);
405         menu_item=gtk_menu_item_new_with_label(vs);
406         g_signal_connect(menu_item, "activate", G_CALLBACK(dcerpcstat_version_select),
407                        (gpointer)((long)k->ver));
408         gtk_widget_show(menu_item);
409         gtk_menu_shell_append(GTK_MENU_SHELL(vers_menu), menu_item);
410
411         if(dcerpc_version==0xffff){
412                 dcerpc_version=k->ver;
413         }
414
415         return NULL;
416 }
417
418
419 static void
420 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
421 {
422         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
423
424         dcerpc_uuid_program=&k->uuid;
425
426         /* change version menu */
427         dcerpc_version=0xffff;
428         gtk_object_destroy(GTK_OBJECT(vers_menu));
429         vers_menu=gtk_menu_new();
430         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
431         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
432 }
433
434
435 static GtkWidget *program_submenu_menu;
436 static GtkWidget *program_submenu_item;
437 static GtkWidget *program_submenu_label;
438 static int program_subitem_index;
439 static const char *first_menu_name;
440 static void
441 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
442 {
443         GtkWidget *program_menu_item;
444         GtkWidget *box;
445         char str[64];
446
447         switch(program_subitem_index%15){
448         case 0:
449
450                 first_menu_name=v->name;
451                 g_snprintf(str,63,"%s ...",v->name);
452                 program_submenu_item=gtk_menu_item_new();
453                 box=gtk_hbox_new(TRUE,0);
454                 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
455
456                 program_submenu_label=gtk_label_new(str);
457                 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
458                 gtk_widget_show(program_submenu_label);
459                 gtk_widget_show(box);
460
461                 gtk_menu_shell_append(GTK_MENU_SHELL(prog_menu), program_submenu_item);
462                 gtk_widget_show(program_submenu_item);
463
464                 program_submenu_menu=gtk_menu_new();
465                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
466                 break;
467         case 14:
468                 g_snprintf(str,63,"%s - %s",first_menu_name,v->name);
469                 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
470                 break;
471 /*qqq*/
472         }
473         program_subitem_index++;
474
475         program_menu_item=gtk_menu_item_new_with_label(v->name);
476         g_signal_connect(program_menu_item, "activate", G_CALLBACK(dcerpcstat_program_select), k);
477
478         gtk_widget_show(program_menu_item);
479         gtk_menu_shell_append(GTK_MENU_SHELL(program_submenu_menu), program_menu_item);
480
481         if(!dcerpc_uuid_program){
482                 dcerpc_uuid_program=&k->uuid;
483         }
484
485         return;
486 }
487
488 static void *
489 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
490 {
491         dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
492         dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
493
494         /* first time called, just set new_uuid to this one */
495         if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
496                 new_uuid_key=k;
497                 new_uuid_value=v;
498                 return NULL;
499         }
500
501         /* if we havent got a current one yet, just check the new
502            and scan for the first one alphabetically  */
503         if(current_uuid_key==NULL){
504                 if(strcmp(new_uuid_value->name, v->name)>0){
505                         new_uuid_key=k;
506                         new_uuid_value=v;
507                         return NULL;
508                 }
509                 return NULL;
510         }
511
512         /* searching for the next one we are only interested in those
513            that sorts alphabetically after the current one */
514         if(strcmp(current_uuid_value->name, v->name)>=0){
515                 /* this one doesnt so just skip it */
516                 return NULL;
517         }
518
519         /* is it the first potential new entry? */
520         if(new_uuid_key==NULL){
521                 new_uuid_key=k;
522                 new_uuid_value=v;
523                 return NULL;
524         }
525
526         /* does it sort before the current new one? */
527         if(strcmp(new_uuid_value->name, v->name)>0){
528                 new_uuid_key=k;
529                 new_uuid_value=v;
530                 return NULL;
531         }
532
533         return NULL;
534 }
535
536
537 static void
538 dlg_destroy_cb(void)
539 {
540         dlg=NULL;
541 }
542
543
544 static void
545 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
546 {
547         GtkWidget *dlg_box;
548         GtkWidget *prog_box, *prog_label, *prog_opt;
549         GtkWidget *vers_label;
550         GtkWidget *filter_box, *filter_bt;
551         GtkWidget *bbox, *start_button, *cancel_button;
552         const char *filter;
553         static construct_args_t args = {
554           "Service Response Time Statistics Filter",
555           FALSE,
556           FALSE,
557           FALSE
558         };
559
560         /* if the window is already open, bring it to front and
561            un-minimize it, as necessary */
562         if(dlg){
563                 reactivate_window(dlg);
564                 return;
565         }
566
567         dlg=dlg_window_new("Wireshark: Compute DCE-RPC SRT statistics");
568         gtk_window_set_default_size(GTK_WINDOW(dlg), 400, -1);
569
570         dlg_box=gtk_vbox_new(FALSE, 10);
571         gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
572         gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
573         gtk_widget_show(dlg_box);
574
575         /* Program box */
576         prog_box=gtk_hbox_new(FALSE, 3);
577
578         /* Program label */
579         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
580         prog_label=gtk_label_new("Program:");
581         gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
582         gtk_widget_show(prog_label);
583
584         /* Program menu */
585         prog_opt=gtk_option_menu_new();
586         prog_menu=gtk_menu_new();
587         current_uuid_key=NULL;
588         current_uuid_value=NULL;
589 /*qqq*/
590         program_submenu_item=NULL;
591         program_submenu_menu=NULL;
592         program_subitem_index=0;
593         do {
594                 new_uuid_key=NULL;
595                 new_uuid_value=NULL;
596                 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
597                 if(new_uuid_key){
598                         dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
599                 }
600                 current_uuid_key=new_uuid_key;
601                 current_uuid_value=new_uuid_value;
602         } while(new_uuid_key!=NULL);
603
604         gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
605         gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
606         gtk_widget_show(prog_opt);
607
608         /* Version label */
609         gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
610         vers_label=gtk_label_new("Version:");
611         gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
612         gtk_widget_show(vers_label);
613
614         /* Version menu */
615         vers_opt=gtk_option_menu_new();
616         vers_menu=gtk_menu_new();
617         dcerpc_version=0xffff;
618         g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
619         gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
620         gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
621         gtk_widget_show(vers_opt);
622
623         gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
624         gtk_widget_show(prog_box);
625
626         /* Filter box */
627         filter_box=gtk_hbox_new(FALSE, 3);
628
629         /* Filter label */
630         filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
631         g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &args);
632         gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
633         gtk_widget_show(filter_bt);
634
635         /* Filter entry */
636         filter_entry=gtk_entry_new();
637         g_signal_connect(filter_entry, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
638         gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
639         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
640         if(filter){
641                 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
642         } else {
643                 colorize_filter_te_as_empty(filter_entry);
644         }
645         gtk_widget_show(filter_entry);
646
647         gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
648         gtk_widget_show(filter_box);
649
650         g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_entry);
651
652         /* button box */
653         bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
654         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
655         gtk_widget_show(bbox);
656
657         start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
658         g_signal_connect_swapped(start_button, "clicked",
659                               G_CALLBACK(dcerpcstat_start_button_clicked), NULL);
660
661         cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
662         window_set_cancel_button(dlg, cancel_button, window_cancel_button_cb);
663
664         g_signal_connect(dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
665         g_signal_connect(dlg, "destroy", dlg_destroy_cb, NULL);
666
667         /* Catch the "activate" signal on the filter text entry, so that
668            if the user types Return there, we act as if the "Create Stat"
669            button had been selected, as happens if Return is typed if some
670            widget that *doesn't* handle the Return key has the input
671            focus. */
672         dlg_set_activate(filter_entry, start_button);
673
674         gtk_widget_grab_default(start_button );
675
676         /* Give the initial focus to the "Filter" entry box. */
677         gtk_widget_grab_focus(filter_entry);
678
679         gtk_widget_show_all(dlg);
680         window_present(dlg);
681 }
682
683 void
684 register_tap_listener_gtkdcerpcstat(void)
685 {
686         register_stat_cmd_arg("dcerpc,srt,", gtk_dcerpcstat_init,NULL);
687
688         register_stat_menu_item("DCE-RPC...", REGISTER_STAT_GROUP_RESPONSE_TIME,
689             gtk_dcerpcstat_cb, NULL, NULL, NULL);
690 }