Remove a couple commented-out lines that I had left in from an earlier
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.48 1999/11/28 14:50:23 gram Exp $
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@zing.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10  *                              needed by dissect routines
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  *
27  * To do:
28  * - Graphs
29  * - Check for end of packet in dissect_* routines.
30  * - Playback window
31  * - Multiple window support
32  * - Add cut/copy/paste
33  * - Create header parsing routines
34  * - Make byte view scrollbars automatic?
35  * - Make byte view selections more fancy?
36  *
37  */
38
39 #ifdef HAVE_CONFIG_H
40 # include "config.h"
41 #endif
42
43 #include <gtk/gtk.h>
44
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 #include <errno.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56
57 #ifdef HAVE_DIRECT_H
58 #include <direct.h>
59 #endif
60
61 #ifdef HAVE_NETINET_IN_H
62 #include <netinet/in.h>
63 #endif
64
65 #include <signal.h>
66
67 #ifdef NEED_SNPRINTF_H
68 # ifdef HAVE_STDARG_H
69 #  include <stdarg.h>
70 # else
71 #  include <varargs.h>
72 # endif
73 # include "snprintf.h"
74 #endif
75
76 #ifdef NEED_STRERROR_H
77 #include "strerror.h"
78 #endif
79
80 #include "main.h"
81 #include "timestamp.h"
82 #include "packet.h"
83 #include "capture.h"
84 #include "summary.h"
85 #include "file.h"
86 #include "menu.h"
87 #include "prefs_dlg.h"
88 #include "column.h"
89 #include "print.h"
90 #include "resolv.h"
91 #include "follow.h"
92 #include "util.h"
93 #include "proto_draw.h"
94 #include "dfilter.h"
95 #include "keys.h"
96
97 FILE        *data_out_file = NULL;
98 packet_info  pi;
99 capture_file cf;
100 GtkWidget   *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
101             *info_bar;
102 GdkFont     *m_r_font, *m_b_font;
103 guint        main_ctx, file_ctx;
104 gchar        comp_info_str[256];
105 gchar       *ethereal_path = NULL;
106 gchar       *medium_font = MONO_MEDIUM_FONT;
107 gchar       *bold_font = MONO_BOLD_FONT;
108 gchar       *last_open_dir = NULL;
109
110 ts_type timestamp_type = RELATIVE;
111
112 GtkStyle *item_style;
113
114 /* Specifies the field currently selected in the GUI protocol tree */
115 field_info *finfo_selected = NULL;
116
117 static void follow_destroy_cb(GtkWidget *win, gpointer data);
118 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
119 static void follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii);
120 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
121 static char* hfinfo_numeric_format(header_field_info *hfinfo);
122
123 /* About Ethereal window */
124 void
125 about_ethereal( GtkWidget *w, gpointer data ) {
126   simple_dialog(ESD_TYPE_INFO, NULL,
127                 "GNU Ethereal - network protocol analyzer\n"
128                 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
129                 "Compiled with %s\n\n"
130                 "Contributors:\n"
131
132                 "Gilbert Ramirez          <gramirez@tivoli.com>\n"
133                 "Hannes R. Boehm          <hannes@boehm.org>\n"
134                 "Mike Hall                <mlh@io.com>\n"
135                 "Bobo Rajec               <bobo@bsp-consulting.sk>\n"
136                 "Laurent Deniel           <deniel@worldnet.fr>\n"
137                 "Don Lafontaine           <lafont02@cn.ca>\n"
138                 "Guy Harris               <guy@alum.mit.edu>\n"
139                 "Simon Wilkinson          <sxw@dcs.ed.ac.uk>\n"
140                 "Joerg Mayer              <jmayer@telemation.de>\n"
141                 "Martin Maciaszek         <fastjack@i-s-o.net>\n"
142                 "Didier Jorand            <Didier.Jorand@alcatel.fr>\n"
143                 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
144                 "Richard Sharpe           <sharpe@ns.aus.com>\n"
145                 "John McDermott           <jjm@jkintl.com>\n"
146                 "Jeff Jahr                <jjahr@shastanets.com>\n"
147                 "Brad Robel-Forrest       <bradr@watchguard.com>\n"
148                 "Ashok Narayanan          <ashokn@cisco.com>\n"
149                 "Aaron Hillegass          <aaron@classmax.com>\n"
150                 "Jason Lango              <jal@netapp.com>\n"
151                 "Johan Feyaerts           <Johan.Feyaerts@siemens.atea.be>\n"
152                 "Olivier Abad             <abad@daba.dhis.org>\n"
153                 "Thierry Andry            <Thierry.Andry@advalvas.be>\n"
154                 "Jeff Foster              <jfoste@woodward.com>\n"
155                 "Peter Torvals            <petertv@xoommail.com>\n"
156                 "Christophe Tronche       <ch.tronche@computer.org>\n"
157                 "Nathan Neulinger         <nneul@umr.edu>\n"
158                 "Tomislav Vujec           <tvujec@carnet.hr>\n"
159                 "Kojak                    <kojak@bigwig.net>\n"
160                 "Uwe Girlich              <Uwe.Girlich@philosys.de>\n"
161                 "Warren Young             <tangent@mail.com>\n"
162                 "Heikki Vatiainen         <hessu@cs.tut.fi>\n"
163                 "Greg Hankins             <gregh@twoguys.org>\n"
164
165                 "\nSee http://ethereal.zing.org for more information",
166                 VERSION, comp_info_str);
167 }
168
169 /* Follow the TCP stream, if any, to which the last packet that we called
170    a dissection routine on belongs (this might be the most recently
171    selected packet, or it might be the last packet in the file). */
172 void
173 follow_stream_cb( GtkWidget *w, gpointer data ) {
174   char      filename1[128+1];
175   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
176                 *filter_te;
177   GtkWidget *hbox, *close_bt, *print_bt, *button;
178   int        tmp_fd;
179   gchar     *follow_filter;
180
181   if( pi.ipproto == 6 ) {
182     /* we got tcp so we can follow */
183     /* Create a temporary file into which to dump the reassembled data
184        from the TCP stream, and set "data_out_file" to refer to it, so
185        that the TCP code will write to it.
186
187        XXX - it might be nicer to just have the TCP code directly
188        append stuff to the text widget for the TCP stream window,
189        if we can arrange that said window not pop up until we're
190        done. */
191     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
192     if (tmp_fd == -1) {
193       simple_dialog(ESD_TYPE_WARN, NULL,
194         "Could not create temporary file %s: %s", filename1, strerror(errno));
195       return;
196     }
197     data_out_file = fdopen( tmp_fd, "w" );
198     if( data_out_file == NULL ) {
199       simple_dialog(ESD_TYPE_WARN, NULL,
200         "Could not create temporary file %s: %s", filename1, strerror(errno));
201       close(tmp_fd);
202       unlink(filename1);
203       return;
204     }
205
206     /* Create a new filter that matches all packets in the TCP stream,
207        and set the display filter entry accordingly */
208     reset_tcp_reassembly();
209     follow_filter = build_follow_filter( &pi );
210
211     /* set the display filter entry accordingly */
212     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
213     gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
214
215     /* Run the display filter so it goes in effect. */
216     filter_packets(&cf, follow_filter);
217
218     /* the data_out_file should now be full of the streams information */
219     fclose( data_out_file );
220
221     /* the filename1 file now has all the text that was in the session */
222     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
223     gtk_widget_set_name( streamwindow, "TCP stream window" );
224
225     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
226                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
227     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
228                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
229                         
230     if( incomplete_tcp_stream ) {
231       gtk_window_set_title( GTK_WINDOW(streamwindow), 
232                             "Contents of TCP stream (incomplete)" );
233     } else {
234       gtk_window_set_title( GTK_WINDOW(streamwindow),
235                             "Contents of TCP stream" );
236     }
237     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
238     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
239
240     /* setup the container */
241     box = gtk_vbox_new( FALSE, 0 );
242     gtk_container_add( GTK_CONTAINER(streamwindow), box );
243     gtk_widget_show( box );
244
245     /* set up the table we attach to */
246     table = gtk_table_new( 1, 2, FALSE );
247     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
248     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
249     gtk_widget_show( table );
250
251     /* create a text box */
252     text = gtk_text_new( NULL, NULL );
253     gtk_text_set_editable( GTK_TEXT(text), FALSE);
254     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
255                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
256                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
257     gtk_widget_show(text);
258
259     /* Create hbox */
260     hbox = gtk_hbox_new( FALSE, 1 );
261     gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
262     gtk_widget_show(hbox);
263
264 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
265
266     /* Create Radio Buttons */
267     button = gtk_radio_button_new_with_label(NULL, "ASCII");
268     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
269     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, button);
270     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
271     gtk_signal_connect(GTK_OBJECT(button), "toggled",
272                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
273                     GTK_OBJECT(streamwindow));
274     gtk_widget_show(button);
275
276     button = gtk_radio_button_new_with_label(
277                     gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
278                     "EBCDIC");
279     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
280     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
281     gtk_widget_show(button);
282
283     /* Create Close Button */
284     close_bt = gtk_button_new_with_label("Close");
285     gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
286                     GTK_SIGNAL_FUNC(gtk_widget_destroy),
287                     GTK_OBJECT(streamwindow));
288     gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
289     gtk_widget_show( close_bt );
290
291     /* Create Print Button */
292     print_bt = gtk_button_new_with_label("Print");
293     gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
294                    GTK_SIGNAL_FUNC(follow_print_stream),
295                    GTK_OBJECT(streamwindow));
296     gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
297     gtk_widget_show( print_bt );
298
299     /* create the scrollbar */
300     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
301     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
302                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
303     gtk_widget_show( vscrollbar );
304     gtk_widget_realize( text );
305
306     /* Tuck away the filename and textbox into streamwindow */
307 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
308 #define E_FOLLOW_TEXT_KEY "follow_text_key"
309
310     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
311                     g_strdup(filename1));
312     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
313
314     follow_load_text(text, filename1, TRUE);
315
316     data_out_file = NULL;
317     gtk_widget_show( streamwindow );
318   } else {
319     simple_dialog(ESD_TYPE_WARN, NULL,
320       "Error following stream.  Please make\n"
321       "sure you have a TCP packet selected.");
322   }
323 }
324
325 /* The destroy call back has the responsibility of
326  * unlinking the temporary file */
327 static void
328 follow_destroy_cb(GtkWidget *win, gpointer data)
329 {
330         char    *filename;
331
332         filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
333                                                 E_FOLLOW_FILENAME_KEY);
334         g_assert(filename);
335
336         unlink(filename);
337         gtk_widget_destroy(win);
338 }
339
340 /* Handles the ASCII/EBCDIC toggling */
341 static void
342 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
343 {
344         gboolean        show_ascii = FALSE;
345         GtkWidget       *button, *text;
346         char            *filename;
347
348
349         button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
350                                                 E_FOLLOW_ASCII_KEY);
351         text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
352                                                 E_FOLLOW_TEXT_KEY);
353         filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
354                                                 E_FOLLOW_FILENAME_KEY);
355
356         g_assert(button);
357         g_assert(text);
358         g_assert(filename);
359
360         if (GTK_TOGGLE_BUTTON(button)->active)
361                 show_ascii = TRUE;
362
363         follow_load_text(text, filename, show_ascii);
364 }
365
366 static void follow_print_stream(GtkWidget *w, gpointer parent_w)
367 {
368        FILE *fh = NULL;
369        int to_file = -1;
370        char* print_dest = NULL;
371        char* filename;
372
373        switch (prefs.pr_dest) {
374                case PR_DEST_CMD:
375                        print_dest = prefs.pr_cmd;
376                        to_file = FALSE;
377                        break;
378
379                case PR_DEST_FILE:
380                        print_dest = prefs.pr_file;
381                        to_file = TRUE;
382                        break;
383        }
384
385        if (print_dest != NULL) {
386                fh = open_print_dest(to_file, print_dest);
387        }
388
389        if (fh == NULL) {
390                switch (to_file) {
391                        case -1:
392                                simple_dialog(ESD_TYPE_WARN, NULL,
393                                                "Couldn't figure out where to send the print "
394                                                "job. Check your preferences.");
395                                break;
396
397                        case FALSE:
398                                simple_dialog(ESD_TYPE_WARN, NULL,
399                                                "Couldn't run print command %s.", prefs.pr_cmd);
400                                break;
401
402                        case TRUE:
403                                simple_dialog(ESD_TYPE_WARN, NULL, 
404                                                file_write_error_message(errno),
405                                                prefs.pr_file);
406                                break;
407                }
408                return;
409        }
410
411        filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
412                        E_FOLLOW_FILENAME_KEY);
413
414        if (filename != NULL) {
415                print_preamble(fh);
416                print_file(fh, filename);
417                print_finale(fh);
418                close_print_dest(to_file, fh);
419        }
420        else {
421                simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
422        }
423 }
424
425 #define FLT_BUF_SIZE 1024
426 static void
427 follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii)
428 {
429         int bytes_already, bcount;
430         tcp_stream_chunk sc;
431         guint32 client_addr = 0;
432         guint16 client_port = 0;
433         GdkColor client = { 0, 16383, 0, 0 };
434         GdkColor server = { 0, 0, 0, 16383 };
435
436         /* Delete any info already in text box */
437         bytes_already = gtk_text_get_length(GTK_TEXT(text));
438         if (bytes_already > 0) {
439                 gtk_text_set_point(GTK_TEXT(text), 0);
440                 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
441         }
442
443     /* stop the updates while we fill the text box */
444     gtk_text_freeze( GTK_TEXT(text) );
445     data_out_file = fopen( filename, "r" );
446     if( data_out_file ) {
447       char buffer[FLT_BUF_SIZE];
448       int nchars;
449       while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
450         if (client_addr == 0) {
451           client_addr = sc.src_addr;
452           client_port = sc.src_port;
453         }
454         
455         while (sc.dlen > 0) {
456           bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
457           nchars = fread( buffer, 1, bcount, data_out_file );
458           if (nchars == 0)
459             break;
460           sc.dlen -= bcount;
461           if (show_ascii) {
462                   /* If our native arch is EBCDIC, call:
463                    * ASCII_TO_EBCDIC(buffer, nchars);
464                    */
465           }
466           else {
467                   /* If our native arch is ASCII, call: */
468                   EBCDIC_to_ASCII(buffer, nchars);
469           }
470           if (client_addr == sc.src_addr && client_port == sc.src_port)
471             gtk_text_insert( GTK_TEXT(text), m_r_font, &client, NULL, buffer, nchars );
472           else
473             gtk_text_insert( GTK_TEXT(text), m_r_font, &server, NULL, buffer, nchars );
474         }
475       }
476       if( ferror( data_out_file ) ) {
477         simple_dialog(ESD_TYPE_WARN, NULL,
478           "Error reading temporary file %s: %s", filename, strerror(errno));
479       }
480       fclose( data_out_file );
481     } else {
482       simple_dialog(ESD_TYPE_WARN, NULL,
483         "Could not open temporary file %s: %s", filename, strerror(errno));
484     }
485     gtk_text_thaw( GTK_TEXT(text) );
486 }
487
488 /* Match selected byte pattern */
489 void
490 match_selected_cb(GtkWidget *w, gpointer data)
491 {
492     char                *buf;
493     GtkWidget           *filter_te;
494     char                *ptr, *format, *stringified;
495     int                 i, dfilter_len, abbrev_len;
496     guint8              *c;
497     header_field_info   *hfinfo;
498
499     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
500
501     if (!finfo_selected) {
502         simple_dialog(ESD_TYPE_WARN, NULL,
503                       "Error determining selected bytes.  Please make\n"
504                       "sure you have selected a field within the tree\n"
505                       "view to be matched.");
506         return;
507     }
508
509     hfinfo = finfo_selected->hfinfo;
510     g_assert(hfinfo);
511     abbrev_len = strlen(hfinfo->abbrev);
512
513         switch(hfinfo->type) {
514
515                 case FT_BOOLEAN:
516                         dfilter_len = abbrev_len + 2;
517                         buf = g_malloc0(dfilter_len);
518                         snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
519                                         hfinfo->abbrev);
520                         break;
521
522                 case FT_UINT8:
523                 case FT_UINT16:
524                 case FT_UINT24:
525                 case FT_UINT32:
526                 case FT_INT8:
527                 case FT_INT16:
528                 case FT_INT24:
529                 case FT_INT32:
530                         dfilter_len = abbrev_len + 20;
531                         buf = g_malloc0(dfilter_len);
532                         format = hfinfo_numeric_format(hfinfo);
533                         snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
534                         break;
535
536                 case FT_IPv4:
537                         dfilter_len = abbrev_len + 4 + 15 + 1;
538                         buf = g_malloc0(dfilter_len);
539                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
540                                         ipv4_addr_str(&(finfo_selected->value.ipv4)));
541                         break;
542
543                 case FT_IPXNET:
544                         dfilter_len = abbrev_len + 15;
545                         buf = g_malloc0(dfilter_len);
546                         snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
547                                         finfo_selected->value.numeric);
548                         break;
549
550                 case FT_IPv6:
551                         stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
552                         dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
553                         buf = g_malloc0(dfilter_len);
554                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
555                                         stringified);
556                         break;
557
558                 case FT_DOUBLE:
559                         dfilter_len = abbrev_len + 30;
560                         buf = g_malloc0(dfilter_len);
561                         snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
562                                         finfo_selected->value.floating);
563                         break;
564
565                 case FT_ETHER:
566                         dfilter_len = abbrev_len + 22;
567                         buf = g_malloc0(dfilter_len);
568                         snprintf(buf, dfilter_len, "%s == %s",
569                                         hfinfo->abbrev,
570                                         ether_to_str(finfo_selected->value.ether));
571                         break;
572 #if 0
573
574                 case FT_ABSOLUTE_TIME:
575                 case FT_RELATIVE_TIME:
576                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
577                                 sizeof(struct timeval));
578                         break;
579
580                 case FT_STRING:
581                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
582                         fi->value.string = g_strdup(va_arg(ap, char*));
583                         break;
584
585                 case FT_TEXT_ONLY:
586                         ; /* nothing */
587                         break;
588 #endif
589                 default:
590                     c = cf.pd + finfo_selected->start;
591                     buf = g_malloc0(32 + finfo_selected->length * 3);
592                     ptr = buf;
593
594                     sprintf(ptr, "frame[%d] == ", finfo_selected->start);
595                     ptr = buf+strlen(buf);
596
597                     if (finfo_selected->length == 1) {
598                         sprintf(ptr, "0x%02x", *c++);
599                     }
600                     else {
601                             for (i=0;i<finfo_selected->length; i++) {
602                                 if (i == 0 ) {
603                                         sprintf(ptr, "%02x", *c++);
604                                 }
605                                 else {
606                                         sprintf(ptr, ":%02x", *c++);
607                                 }
608                                 ptr = buf+strlen(buf);
609                             }
610                     }
611                     break;
612         }
613
614     /* create a new one and set the display filter entry accordingly */
615     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
616
617     /* Run the display filter so it goes in effect. */
618     filter_packets(&cf, buf);
619
620     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
621 }
622
623 static char*
624 hfinfo_numeric_format(header_field_info *hfinfo)
625 {
626         char *format = NULL;
627
628         /* Pick the proper format string */
629         switch(hfinfo->display) {
630                 case BASE_DEC:
631                 case BASE_NONE:
632                 case BASE_OCT: /* I'm lazy */
633                 case BASE_BIN: /* I'm lazy */
634                         switch(hfinfo->type) {
635                                 case FT_UINT8:
636                                 case FT_UINT16:
637                                 case FT_UINT24:
638                                 case FT_UINT32:
639                                         format = "%s == %u";
640                                         break;
641                                 case FT_INT8:
642                                 case FT_INT16:
643                                 case FT_INT24:
644                                 case FT_INT32:
645                                         format = "%s == %d";
646                                         break;
647                                 default:
648                                         g_assert_not_reached();
649                                         ;
650                         }
651                         break;
652                 case BASE_HEX:
653                         switch(hfinfo->type) {
654                                 case FT_UINT8:
655                                         format = "%s == 0x%02x";
656                                         break;
657                                 case FT_UINT16:
658                                         format = "%s == 0x%04x";
659                                         break;
660                                 case FT_UINT24:
661                                         format = "%s == 0x%06x";
662                                         break;
663                                 case FT_UINT32:
664                                         format = "%s == 0x%08x";
665                                         break;
666                                 default:
667                                         g_assert_not_reached();
668                                         ;
669                         }
670                         break;
671                 default:
672                         g_assert_not_reached();
673                         ;
674         }
675         return format;
676 }
677
678
679 /* Run the current display filter on the current packet set, and
680    redisplay. */
681 static void
682 filter_activate_cb(GtkWidget *w, gpointer data)
683 {
684   GtkCombo  *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
685   GList     *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
686   GList     *li, *nl = NULL;
687   gboolean   add_filter = TRUE;
688   
689   char *s = gtk_entry_get_text(GTK_ENTRY(w));
690   
691   /* GtkCombos don't let us get at their list contents easily, so we maintain
692      our own filter list, and feed it to gtk_combo_set_popdown_strings when
693      a new filter is added. */
694   if (filter_packets(&cf, g_strdup(s))) {
695     li = g_list_first(filter_list);
696     while (li) {
697       if (li->data && strcmp(s, li->data) == 0)
698         add_filter = FALSE;
699       li = li->next;
700     }
701
702     if (add_filter) {
703       filter_list = g_list_append(filter_list, g_strdup(s));
704       li = g_list_first(filter_list);
705       while (li) {
706         nl = g_list_append(nl, strdup(li->data));
707         li = li->next;
708       }
709       gtk_combo_set_popdown_strings(filter_cm, nl);
710       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
711     }
712   }
713 }
714
715 /* redisplay with no display filter */
716 static void
717 filter_reset_cb(GtkWidget *w, gpointer data)
718 {
719   GtkWidget *filter_te = NULL;
720
721   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
722     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
723   }
724
725   filter_packets(&cf, NULL);
726 }
727
728 /* What to do when a list item is selected/unselected */
729 void
730 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
731
732 #ifdef HAVE_LIBPCAP
733   if (!sync_mode) {
734 #endif
735     if (cf.wth)
736       return; 
737 #ifdef HAVE_LIBPCAP
738   }
739 #endif
740   blank_packetinfo();
741   select_packet(&cf, row);
742 }
743
744 void
745 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
746   unselect_packet(&cf);
747 }
748
749 void
750 tree_view_cb(GtkWidget *w, gpointer data) {
751
752   field_info    *finfo;
753   int           tree_selected_start = -1;
754   int           tree_selected_len = -1;
755
756   if (GTK_TREE(w)->selection) {
757     finfo = 
758         gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
759                                    E_TREEINFO_FIELD_INFO_KEY);
760     g_assert(finfo);
761     finfo_selected = finfo;
762     tree_selected_start = finfo->start;
763     tree_selected_len   = finfo->length;
764   }
765
766   gtk_text_freeze(GTK_TEXT(byte_view));
767   gtk_text_set_point(GTK_TEXT(byte_view), 0);
768   gtk_text_forward_delete(GTK_TEXT(byte_view),
769     gtk_text_get_length(GTK_TEXT(byte_view)));
770   packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
771                    tree_selected_start, tree_selected_len,
772                    cf.current_frame->encoding);
773   
774   gtk_text_thaw(GTK_TEXT(byte_view));
775 }
776
777 void collapse_all_cb(GtkWidget *widget, gpointer data) {
778   if (cf.protocol_tree)
779     collapse_all_tree(cf.protocol_tree, tree_view);
780 }
781
782 void expand_all_cb(GtkWidget *widget, gpointer data) {
783   if (cf.protocol_tree)
784     expand_all_tree(cf.protocol_tree, tree_view);
785 }
786
787 void
788 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
789   if (cf.save_file && !cf.user_saved) {
790         unlink(cf.save_file);
791   }
792   gtk_exit(0);
793 }
794
795 /* call initialization routines at program startup time */
796 static void
797 ethereal_proto_init(void) {
798   init_dissect_rpc();
799   proto_init();
800   init_dissect_udp();
801   dfilter_init();
802 }
803
804 static void
805 ethereal_proto_cleanup(void) {
806         proto_cleanup();
807         dfilter_cleanup();
808 }
809
810 static void 
811 print_usage(void) {
812
813   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
814           VERSION, comp_info_str);
815   fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
816           PACKAGE);
817   fprintf(stderr, "         [-f <filter expression>] [-i interface] [-m <medium font>] [-n]\n");
818   fprintf(stderr, "         [-P <packet list height>] [-r infile] [-s snaplen]\n");
819   fprintf(stderr, "         [-t <time stamp format>] [-T <tree view height>] [-w savefile] \n");
820 }
821
822 /* And now our feature presentation... [ fade to music ] */
823 int
824 main(int argc, char *argv[])
825 {
826 #ifdef HAVE_LIBPCAP
827   char                *command_name;
828 #endif
829   char                *s;
830   int                  i;
831 #ifndef WIN32
832   int                  opt;
833   extern char         *optarg;
834 #endif
835 #ifdef HAVE_LIBPCAP
836   extern char         pcap_version[];
837 #endif
838   char                *pf_path;
839   int                 pf_open_errno = 0;
840   int                 err;
841 #ifdef HAVE_LIBPCAP
842   gboolean            start_capture = FALSE;
843   gchar              *save_file = NULL;
844 #endif
845   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
846                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
847                       *tv_scrollw, *filter_bt, *filter_cm, *filter_te,
848                       *filter_reset;
849   GList               *filter_list = NULL;
850   GtkStyle            *pl_style;
851   GtkAccelGroup       *accel;
852   GtkWidget           *packet_sw;
853   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
854   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
855   dfilter             *rfcode = NULL;
856   gboolean             rfilter_parse_failed = FALSE;
857   e_prefs             *prefs;
858
859   ethereal_path = argv[0];
860
861 #ifdef HAVE_LIBPCAP
862   command_name = strrchr(ethereal_path, '/');
863   if (command_name == NULL)
864     command_name = ethereal_path;
865   else
866     command_name++;
867   /* Set "capture_child" to indicate whether this is going to be a child
868      process for a "-S" capture. */
869   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
870 #endif
871
872   /* If invoked with the "-G" flag, we dump out a glossary of
873      display filter symbols.
874
875      We must do this before calling "gtk_init()", because "gtk_init()"
876      tries to open an X display, and we don't want to have to do any X
877      stuff just to do a build.
878
879      Given that we call "gtk_init()" before doing the regular argument
880      list processing, so that it can handle X and GTK+ arguments and
881      remove them from the list at which we look, this means we must do
882      this before doing the regular argument list processing, as well.
883
884      This means that:
885
886         you must give the "-G" flag as the first flag on the command line;
887
888         you must give it as "-G", nothing more, nothing less;
889
890         any arguments after the "-G" flag will not be used. */
891   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
892     ethereal_proto_init();
893     proto_registrar_dump();
894     exit(0);
895   }
896
897   /* Let GTK get its args */
898   gtk_init (&argc, &argv);
899   
900   prefs = read_prefs(&pf_path);
901   if (pf_path != NULL) {
902     /* The preferences file exists, but couldn't be opened; "pf_path" is
903        its pathname.  Remember "errno", as that says why the attempt
904        failed. */
905     pf_open_errno = errno;
906   }
907
908   /* Initialize the capture file struct */
909   cf.plist              = NULL;
910   cf.plist_end          = NULL;
911   cf.wth                = NULL;
912   cf.fh                 = NULL;
913   cf.rfcode             = NULL;
914   cf.dfilter            = NULL;
915   cf.dfcode             = NULL;
916 #ifdef HAVE_LIBPCAP
917   cf.cfilter            = NULL;
918 #endif
919   cf.iface              = NULL;
920   cf.save_file          = NULL;
921   cf.save_file_fd       = -1;
922   cf.user_saved         = 0;
923   cf.snap               = WTAP_MAX_PACKET_SIZE;
924   cf.count              = 0;
925   cf.cinfo.num_cols     = prefs->num_cols;
926   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
927   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
928   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
929   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
930   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
931
932   /* Assemble the compile-time options */
933   snprintf(comp_info_str, 256,
934 #ifdef GTK_MAJOR_VERSION
935     "GTK+ %d.%d.%d, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
936     GTK_MICRO_VERSION,
937 #else
938     "GTK+ (version unknown), %s%s",
939 #endif
940
941 #ifdef HAVE_LIBPCAP
942    "with libpcap ", pcap_version
943 #else
944    "without libpcap", ""
945 #endif
946    );
947
948 #ifndef WIN32
949   /* Now get our args */
950   while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
951     switch (opt) {
952       case 'b':        /* Bold font */
953         bold_font = g_strdup(optarg);
954         break;
955       case 'B':        /* Byte view pane height */
956         bv_size = atoi(optarg);
957         break;
958       case 'c':        /* Capture xxx packets */
959         cf.count = atoi(optarg);
960         break;
961 #ifdef HAVE_LIBPCAP
962       case 'f':
963         cf.cfilter = g_strdup(optarg);
964         break;
965 #endif
966       case 'h':        /* Print help and exit */
967         print_usage();
968         exit(0);
969         break;
970       case 'i':        /* Use interface xxx */
971         cf.iface = g_strdup(optarg);
972         break;
973       case 'm':        /* Medium font */
974         medium_font = g_strdup(optarg);
975         break;
976       case 'n':        /* No name resolution */
977         g_resolving_actif = 0;
978         break;
979 #ifdef HAVE_LIBPCAP
980       case 'k':        /* Start capture immediately */
981         start_capture = TRUE;
982         break;
983 #endif
984       case 'P':        /* Packet list pane height */
985         pl_size = atoi(optarg);
986         break;
987 #ifdef HAVE_LIBPCAP
988       case 'Q':        /* Quit after capture (just capture to file) */
989         quit_after_cap = 1;
990         start_capture = TRUE;  /*** -Q implies -k !! ***/
991         break;
992 #endif
993       case 'r':        /* Read capture file xxx */
994         cf_name = g_strdup(optarg);
995         break;
996       case 'R':        /* Read file filter */
997         rfilter = optarg;
998         break;
999 #ifdef HAVE_LIBPCAP
1000       case 's':        /* Set the snapshot (capture) length */
1001         cf.snap = atoi(optarg);
1002         break;
1003       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1004         sync_mode = TRUE;
1005         break;
1006 #endif
1007       case 't':        /* Time stamp type */
1008         if (strcmp(optarg, "r") == 0)
1009           timestamp_type = RELATIVE;
1010         else if (strcmp(optarg, "a") == 0)
1011           timestamp_type = ABSOLUTE;
1012         else if (strcmp(optarg, "d") == 0)
1013           timestamp_type = DELTA;
1014         else {
1015           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1016             optarg);
1017           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1018           fprintf(stderr, "or \"d\" for delta.\n");
1019           exit(1);
1020         }
1021         break;
1022       case 'T':        /* Tree view pane height */
1023         tv_size = atoi(optarg);
1024         break;
1025       case 'v':        /* Show version and exit */
1026         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1027         exit(0);
1028         break;
1029 #ifdef HAVE_LIBPCAP
1030       case 'w':        /* Write to capture file xxx */
1031         save_file = g_strdup(optarg);
1032         break;
1033       case 'W':        /* Write to capture file FD xxx */
1034         cf.save_file_fd = atoi(optarg);
1035         break;
1036 #endif
1037       case '?':        /* Bad flag - print usage message */
1038         print_usage();
1039         break;
1040     }
1041   }
1042 #endif
1043
1044 #ifdef HAVE_LIBPCAP
1045   if (start_capture) {
1046     if (cf.iface == NULL) {
1047       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1048       exit(1);
1049     }
1050   }
1051   if (capture_child) {
1052     if (cf.save_file_fd == -1) {
1053       /* XXX - send this to the standard output as something our parent
1054          should put in an error message box? */
1055       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1056       exit(1);
1057     }
1058   }
1059 #endif
1060
1061   /* Build the column format array */  
1062   for (i = 0; i < cf.cinfo.num_cols; i++) {
1063     cf.cinfo.col_fmt[i] = get_column_format(i);
1064     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1065     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1066       NUM_COL_FMTS);
1067     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1068     if (cf.cinfo.col_fmt[i] == COL_INFO)
1069       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1070     else
1071       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1072   }
1073
1074   if (cf.snap < 1)
1075     cf.snap = WTAP_MAX_PACKET_SIZE;
1076   else if (cf.snap < MIN_PACKET_SIZE)
1077     cf.snap = MIN_PACKET_SIZE;
1078   
1079   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1080   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1081   gtk_rc_parse(rc_file);
1082
1083   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1084     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1085     exit(1);
1086   }
1087
1088   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1089     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1090     exit(1);
1091   }
1092
1093   /* Main window */  
1094   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1095   gtk_widget_set_name(window, "main window");
1096   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
1097     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1098   gtk_signal_connect(GTK_OBJECT(window), "destroy", 
1099     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1100   gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
1101   gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
1102   gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
1103
1104   /* Container for menu bar, paned windows and progress/info box */
1105   main_vbox = gtk_vbox_new(FALSE, 1);
1106   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1107   gtk_container_add(GTK_CONTAINER(window), main_vbox);
1108   gtk_widget_show(main_vbox);
1109
1110   /* Menu bar */
1111   get_main_menu(&menubar, &accel);
1112   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
1113   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1114   gtk_widget_show(menubar);
1115
1116   /* Panes for the packet list, tree, and byte view */
1117   u_pane = gtk_vpaned_new();
1118   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1119   l_pane = gtk_vpaned_new();
1120   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1121   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1122   gtk_widget_show(u_pane);
1123   gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
1124   gtk_widget_show(l_pane);
1125
1126   /* Packet list */
1127   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1128   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1129   packet_sw = gtk_scrolled_window_new(NULL, NULL);
1130   gtk_widget_show(packet_sw);
1131   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
1132   pl_style = gtk_style_new();
1133   gdk_font_unref(pl_style->font);
1134   pl_style->font = m_r_font;
1135   gtk_widget_set_style(packet_list, pl_style);
1136   gtk_widget_set_name(packet_list, "packet list");
1137   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1138     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1139   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1140     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1141   for (i = 0; i < cf.cinfo.num_cols; i++) {
1142     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1143       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1144
1145     /* Right-justify the packet number column. */
1146     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1147       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1148         GTK_JUSTIFY_RIGHT);
1149
1150     /* Save static column sizes to use during a "-S" capture, so that
1151        the columns don't resize during a live capture. */
1152     cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1153                                                 pl_style->font);
1154   }
1155   gtk_widget_set_usize(packet_list, -1, pl_size);
1156   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
1157   gtk_widget_show(packet_list);
1158   
1159   /* Tree view */
1160   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1161   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1162     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1163   gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
1164   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1165   gtk_widget_show(tv_scrollw);
1166   
1167   tree_view = gtk_tree_new();
1168   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
1169                   tree_view);
1170   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
1171
1172   /* XXX - what's the difference between the next two lines? */
1173   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
1174   gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
1175
1176   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
1177     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
1178   gtk_widget_show(tree_view);
1179
1180   item_style = gtk_style_new();
1181   gdk_font_unref(item_style->font);
1182   item_style->font = m_r_font;
1183
1184   /* Byte view */
1185   bv_table = gtk_table_new (2, 2, FALSE);
1186   gtk_paned_add2(GTK_PANED(l_pane), bv_table);
1187   gtk_widget_set_usize(bv_table, -1, bv_size);
1188   gtk_widget_show(bv_table);
1189
1190   byte_view = gtk_text_new(NULL, NULL);
1191   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1192   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1193   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
1194     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1195   gtk_widget_show(byte_view);
1196
1197   bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
1198   gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
1199     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1200   gtk_widget_show (bv_hscroll);
1201
1202   bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1203   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
1204     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1205   gtk_widget_show(bv_vscroll);
1206   
1207   /* Progress/filter/info box */
1208   stat_hbox = gtk_hbox_new(FALSE, 1);
1209   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1210   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1211   gtk_widget_show(stat_hbox);
1212
1213   prog_bar = gtk_progress_bar_new();
1214   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1215   gtk_widget_show(prog_bar);
1216
1217   filter_bt = gtk_button_new_with_label("Filter:");
1218   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1219     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
1220   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1221   gtk_widget_show(filter_bt);
1222   
1223   filter_cm = gtk_combo_new();
1224   filter_list = g_list_append (filter_list, "");
1225   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1226   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1227   filter_te = GTK_COMBO(filter_cm)->entry;
1228   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1229   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1230   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1231   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1232   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1233     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1234   gtk_widget_show(filter_cm);
1235
1236   filter_reset = gtk_button_new_with_label("Reset");
1237   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1238   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1239                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1240   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1241   gtk_widget_show(filter_reset);
1242
1243   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1244    * of any widget that ends up calling a callback which needs
1245    * that text entry pointer */
1246   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1247   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1248   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1249   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1250
1251   info_bar = gtk_statusbar_new();
1252   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1253   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1254   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1255   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1256   gtk_widget_show(info_bar);
1257
1258 /* 
1259    Hmmm should we do it here
1260 */
1261
1262   ethereal_proto_init();   /* Init anything that needs initializing */
1263
1264 #ifdef HAVE_LIBPCAP
1265   /* Is this a "child" ethereal, which is only supposed to pop up a
1266      capture box to let us stop the capture, and run a capture
1267      to a file that our parent will read? */
1268   if (!capture_child) {
1269 #endif
1270     /* No.  Pop up the main window, and read in a capture file if
1271        we were told to. */
1272
1273     gtk_widget_show(window);
1274
1275     colors_init(&cf);
1276
1277     /* If we were given the name of a capture file, read it in now;
1278        we defer it until now, so that, if we can't open it, and pop
1279        up an alert box, the alert box is more likely to come up on
1280        top of the main window - but before the preference-file-error
1281        alert box, so, if we get one of those, it's more likely to come
1282        up on top of us. */
1283     if (cf_name) {
1284       if (rfilter != NULL) {
1285         if (dfilter_compile(rfilter, &rfcode) != 0) {
1286           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1287           rfilter_parse_failed = TRUE;
1288         }
1289       }
1290       if (!rfilter_parse_failed) {
1291         if ((err = open_cap_file(cf_name, &cf)) == 0) {
1292           /* "open_cap_file()" succeeded, so it closed the previous
1293              capture file, and thus destroyed any previous read filter
1294              attached to "cf". */
1295           cf.rfcode = rfcode;
1296           err = read_cap_file(&cf);
1297           s = strrchr(cf_name, '/');
1298           if (s) {
1299             last_open_dir = cf_name;
1300             *s = '\0';
1301           }
1302           set_menu_sensitivity("/File/Save As...", TRUE);
1303         } else {
1304           dfilter_destroy(rfcode);
1305           cf.rfcode = NULL;
1306         }
1307       }
1308     }
1309 #ifdef HAVE_LIBPCAP
1310   }
1311 #endif
1312
1313   /* If we failed to open the preferences file, pop up an alert box;
1314      we defer it until now, so that the alert box is more likely to
1315      come up on top of the main window. */
1316   if (pf_path != NULL) {
1317       simple_dialog(ESD_TYPE_WARN, NULL,
1318         "Could not open preferences file\n\"%s\": %s.", pf_path,
1319         strerror(pf_open_errno));
1320   }
1321
1322 #ifdef HAVE_LIBPCAP
1323   if (capture_child) {
1324     /* This is the child process for a sync mode or fork mode capture,
1325        so just do the low-level work of a capture - don't create
1326        a temporary file and fork off *another* child process (so don't
1327        call "do_capture()"). */
1328
1329        capture();
1330
1331        /* The capture is done; there's nothing more for us to do. */
1332        gtk_exit(0);
1333   } else {
1334     if (start_capture) {
1335       /* "-k" was specified; start a capture. */
1336       do_capture(save_file);
1337     }
1338   }
1339 #endif
1340
1341   gtk_main();
1342
1343   ethereal_proto_cleanup();
1344   g_free(rc_file);
1345
1346   exit(0);
1347 }