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