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