Add AIX doco and modify references to it.
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.43 1999/11/23 03:50:40 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
164                 "\nSee http://ethereal.zing.org for more information",
165                 VERSION, comp_info_str);
166 }
167
168 /* Follow the TCP stream, if any, to which the last packet that we called
169    a dissection routine on belongs (this might be the most recently
170    selected packet, or it might be the last packet in the file). */
171 void
172 follow_stream_cb( GtkWidget *w, gpointer data ) {
173   char      filename1[128+1];
174   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
175   GtkWidget *hbox, *close_bt, *print_bt, *button;
176   int        tmp_fd;
177   gchar     *follow_filter;
178
179   if( pi.ipproto == 6 ) {
180     /* we got tcp so we can follow */
181     /* Create a temporary file into which to dump the reassembled data
182        from the TCP stream, and set "data_out_file" to refer to it, so
183        that the TCP code will write to it.
184
185        XXX - it might be nicer to just have the TCP code directly
186        append stuff to the text widget for the TCP stream window,
187        if we can arrange that said window not pop up until we're
188        done. */
189     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
190     if (tmp_fd == -1) {
191       simple_dialog(ESD_TYPE_WARN, NULL,
192         "Could not create temporary file %s: %s", filename1, strerror(errno));
193       return;
194     }
195     data_out_file = fdopen( tmp_fd, "w" );
196     if( data_out_file == NULL ) {
197       simple_dialog(ESD_TYPE_WARN, NULL,
198         "Could not create temporary file %s: %s", filename1, strerror(errno));
199       close(tmp_fd);
200       unlink(filename1);
201       return;
202     }
203
204     /* Create a new filter that matches all packets in the TCP stream,
205        and set the display filter entry accordingly */
206     reset_tcp_reassembly();
207     follow_filter = build_follow_filter( &pi );
208
209     /* Run the display filter so it goes in effect. */
210     filter_packets(&cf, follow_filter);
211
212     /* the data_out_file should now be full of the streams information */
213     fclose( data_out_file );
214
215     /* the filename1 file now has all the text that was in the session */
216     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
217     gtk_widget_set_name( streamwindow, "TCP stream window" );
218 /*    gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
219                         NULL, "WM destroy" );
220     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
221                         NULL, "WM destroy" );*/
222     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
223                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
224     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
225                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
226                         
227     if( incomplete_tcp_stream ) {
228       gtk_window_set_title( GTK_WINDOW(streamwindow), 
229                             "Contents of TCP stream (incomplete)" );
230     } else {
231       gtk_window_set_title( GTK_WINDOW(streamwindow),
232                             "Contents of TCP stream" );
233     }
234     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
235     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
236
237     /* setup the container */
238     box = gtk_vbox_new( FALSE, 0 );
239     gtk_container_add( GTK_CONTAINER(streamwindow), box );
240     gtk_widget_show( box );
241
242     /* set up the table we attach to */
243     table = gtk_table_new( 1, 2, FALSE );
244     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
245     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
246     gtk_widget_show( table );
247
248     /* create a text box */
249     text = gtk_text_new( NULL, NULL );
250     gtk_text_set_editable( GTK_TEXT(text), FALSE);
251     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
252                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
253                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
254     gtk_widget_show(text);
255
256     /* Create hbox */
257     hbox = gtk_hbox_new( FALSE, 1 );
258     gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
259     gtk_widget_show(hbox);
260
261 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
262
263     /* Create Radio Buttons */
264     button = gtk_radio_button_new_with_label(NULL, "ASCII");
265     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
266     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, button);
267     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
268     gtk_signal_connect(GTK_OBJECT(button), "toggled",
269                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
270                     GTK_OBJECT(streamwindow));
271     gtk_widget_show(button);
272
273     button = gtk_radio_button_new_with_label(
274                     gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
275                     "EBCDIC");
276     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
277     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
278     gtk_widget_show(button);
279
280     /* Create Close Button */
281     close_bt = gtk_button_new_with_label("Close");
282     gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
283                     GTK_SIGNAL_FUNC(gtk_widget_destroy),
284                     GTK_OBJECT(streamwindow));
285     gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
286     gtk_widget_show( close_bt );
287
288     /* Create Print Button */
289     print_bt = gtk_button_new_with_label("Print");
290     gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
291                    GTK_SIGNAL_FUNC(follow_print_stream),
292                    GTK_OBJECT(streamwindow));
293     gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
294     gtk_widget_show( print_bt );
295
296     /* create the scrollbar */
297     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
298     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
299                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
300     gtk_widget_show( vscrollbar );
301     gtk_widget_realize( text );
302
303     /* Tuck away the filename and textbox into streamwindow */
304 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
305 #define E_FOLLOW_TEXT_KEY "follow_text_key"
306
307     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
308                     g_strdup(filename1));
309     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
310
311     follow_load_text(text, filename1, TRUE);
312
313     data_out_file = NULL;
314     gtk_widget_show( streamwindow );
315   } else {
316     simple_dialog(ESD_TYPE_WARN, NULL,
317       "Error following stream.  Please make\n"
318       "sure you have a TCP packet selected.");
319   }
320 }
321
322 /* The destroy call back has the responsibility of
323  * unlinking the temporary file */
324 static void
325 follow_destroy_cb(GtkWidget *win, gpointer data)
326 {
327         char    *filename;
328
329         filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
330                                                 E_FOLLOW_FILENAME_KEY);
331         g_assert(filename);
332
333         unlink(filename);
334         gtk_widget_destroy(win);
335 }
336
337 /* Handles the ASCII/EBCDIC toggling */
338 static void
339 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
340 {
341         gboolean        show_ascii = FALSE;
342         GtkWidget       *button, *text;
343         char            *filename;
344
345
346         button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
347                                                 E_FOLLOW_ASCII_KEY);
348         text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
349                                                 E_FOLLOW_TEXT_KEY);
350         filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
351                                                 E_FOLLOW_FILENAME_KEY);
352
353         g_assert(button);
354         g_assert(text);
355         g_assert(filename);
356
357         if (GTK_TOGGLE_BUTTON(button)->active)
358                 show_ascii = TRUE;
359
360         follow_load_text(text, filename, show_ascii);
361 }
362
363 static void follow_print_stream(GtkWidget *w, gpointer parent_w)
364 {
365        FILE *fh = NULL;
366        int to_file = -1;
367        char* print_dest = NULL;
368        char* filename;
369
370        switch (prefs.pr_dest) {
371                case PR_DEST_CMD:
372                        print_dest = prefs.pr_cmd;
373                        to_file = FALSE;
374                        break;
375
376                case PR_DEST_FILE:
377                        print_dest = prefs.pr_file;
378                        to_file = TRUE;
379                        break;
380        }
381
382        if (print_dest != NULL) {
383                fh = open_print_dest(to_file, print_dest);
384        }
385
386        if (fh == NULL) {
387                switch (to_file) {
388                        case -1:
389                                simple_dialog(ESD_TYPE_WARN, NULL,
390                                                "Couldn't figure out where to send the print "
391                                                "job. Check your preferences.");
392                                break;
393
394                        case FALSE:
395                                simple_dialog(ESD_TYPE_WARN, NULL,
396                                                "Couldn't run print command %s.", prefs.pr_cmd);
397                                break;
398
399                        case TRUE:
400                                simple_dialog(ESD_TYPE_WARN, NULL, 
401                                                file_write_error_message(errno),
402                                                prefs.pr_file);
403                                break;
404                }
405                return;
406        }
407
408        filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
409                        E_FOLLOW_FILENAME_KEY);
410
411        if (filename != NULL) {
412                print_preamble(fh);
413                print_file(fh, filename);
414                print_finale(fh);
415                close_print_dest(to_file, fh);
416        }
417        else {
418                simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
419        }
420 }
421
422 static void
423 follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii)
424 {
425         int bytes_already;
426
427         /* Delete any info already in text box */
428         bytes_already = gtk_text_get_length(GTK_TEXT(text));
429         if (bytes_already > 0) {
430                 gtk_text_set_point(GTK_TEXT(text), 0);
431                 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
432         }
433
434     /* stop the updates while we fill the text box */
435     gtk_text_freeze( GTK_TEXT(text) );
436     data_out_file = fopen( filename, "r" );
437     if( data_out_file ) {
438       char buffer[1024];
439       int nchars;
440       while( 1 ) {
441         nchars = fread( buffer, 1, 1024, data_out_file );
442         if (show_ascii) {
443                 /* If our native arch is EBCDIC, call:
444                  * ASCII_TO_EBCDIC(buffer, nchars);
445                  */
446         }
447         else {
448                 /* If our native arch is ASCII, call: */
449                 EBCDIC_to_ASCII(buffer, nchars);
450         }
451         gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
452         if( nchars < 1024 ) {
453           break;
454         }
455       }
456       if( ferror( data_out_file ) ) {
457         simple_dialog(ESD_TYPE_WARN, NULL,
458           "Error reading temporary file %s: %s", filename, strerror(errno));
459       }
460       fclose( data_out_file );
461     } else {
462       simple_dialog(ESD_TYPE_WARN, NULL,
463         "Could not open temporary file %s: %s", filename, strerror(errno));
464     }
465     gtk_text_thaw( GTK_TEXT(text) );
466 }
467
468 /* Match selected byte pattern */
469 void
470 match_selected_cb(GtkWidget *w, gpointer data)
471 {
472     char                *buf;
473     GtkWidget           *filter_te = NULL;
474     char                *ptr, *format, *stringified;
475     int                 i, dfilter_len, abbrev_len;
476     guint8              *c;
477     header_field_info   *hfinfo;
478
479     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
480
481     if (!finfo_selected) {
482         simple_dialog(ESD_TYPE_WARN, NULL,
483                       "Error determining selected bytes.  Please make\n"
484                       "sure you have selected a field within the tree\n"
485                       "view to be matched.");
486         return;
487     }
488
489     hfinfo = finfo_selected->hfinfo;
490     g_assert(hfinfo);
491     abbrev_len = strlen(hfinfo->abbrev);
492
493         switch(hfinfo->type) {
494
495                 case FT_BOOLEAN:
496                         dfilter_len = abbrev_len + 2;
497                         buf = g_malloc0(dfilter_len);
498                         snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
499                                         hfinfo->abbrev);
500                         break;
501
502                 case FT_UINT8:
503                 case FT_UINT16:
504                 case FT_UINT24:
505                 case FT_UINT32:
506                 case FT_INT8:
507                 case FT_INT16:
508                 case FT_INT24:
509                 case FT_INT32:
510                         dfilter_len = abbrev_len + 20;
511                         buf = g_malloc0(dfilter_len);
512                         format = hfinfo_numeric_format(hfinfo);
513                         snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
514                         break;
515
516                 case FT_IPv4:
517                         dfilter_len = abbrev_len + 4 + 15 + 1;
518                         buf = g_malloc0(dfilter_len);
519                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
520                                         ipv4_addr_str(&(finfo_selected->value.ipv4)));
521                         break;
522
523                 case FT_IPXNET:
524                         dfilter_len = abbrev_len + 15;
525                         buf = g_malloc0(dfilter_len);
526                         snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
527                                         finfo_selected->value.numeric);
528                         break;
529
530                 case FT_IPv6:
531                         stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
532                         dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
533                         buf = g_malloc0(dfilter_len);
534                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
535                                         stringified);
536                         break;
537
538                 case FT_DOUBLE:
539                         dfilter_len = abbrev_len + 30;
540                         buf = g_malloc0(dfilter_len);
541                         snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
542                                         finfo_selected->value.floating);
543                         break;
544
545                 case FT_ETHER:
546                         dfilter_len = abbrev_len + 22;
547                         buf = g_malloc0(dfilter_len);
548                         snprintf(buf, dfilter_len, "%s == %02x:%02x:%02x:%02x:%02x:%02x",
549                                         hfinfo->abbrev,
550                                         finfo_selected->value.ether[0],
551                                         finfo_selected->value.ether[1],
552                                         finfo_selected->value.ether[2],
553                                         finfo_selected->value.ether[3],
554                                         finfo_selected->value.ether[4],
555                                         finfo_selected->value.ether[5]);
556                         break;
557 #if 0
558
559                 case FT_ABSOLUTE_TIME:
560                 case FT_RELATIVE_TIME:
561                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
562                                 sizeof(struct timeval));
563                         break;
564
565                 case FT_STRING:
566                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
567                         fi->value.string = g_strdup(va_arg(ap, char*));
568                         break;
569
570                 case FT_TEXT_ONLY:
571                         ; /* nothing */
572                         break;
573 #endif
574                 default:
575                     c = cf.pd + finfo_selected->start;
576                     buf = g_malloc0(32 + finfo_selected->length * 3);
577                     ptr = buf;
578
579                     sprintf(ptr, "frame[%d : %d] == ", finfo_selected->start, finfo_selected->length);
580                     ptr = buf+strlen(buf);
581
582                     if (finfo_selected->length == 1) {
583                         sprintf(ptr, "0x%02x", *c++);
584                     }
585                     else {
586                             for (i=0;i<finfo_selected->length; i++) {
587                                 if (i == 0 ) {
588                                         sprintf(ptr, "%02x", *c++);
589                                 }
590                                 else {
591                                         sprintf(ptr, ":%02x", *c++);
592                                 }
593                                 ptr = buf+strlen(buf);
594                             }
595                     }
596                     break;
597         }
598
599     /* create a new one and set the display filter entry accordingly */
600     if (filter_te) {
601         gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
602     }
603     /* Run the display filter so it goes in effect. */
604     filter_packets(&cf, buf);
605
606     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
607 }
608
609 static char*
610 hfinfo_numeric_format(header_field_info *hfinfo)
611 {
612         char *format = NULL;
613
614         /* Pick the proper format string */
615         switch(hfinfo->display) {
616                 case BASE_DEC:
617                 case BASE_NONE:
618                 case BASE_OCT: /* I'm lazy */
619                 case BASE_BIN: /* I'm lazy */
620                         switch(hfinfo->type) {
621                                 case FT_UINT8:
622                                 case FT_UINT16:
623                                 case FT_UINT24:
624                                 case FT_UINT32:
625                                         format = "%s == %u";
626                                         break;
627                                 case FT_INT8:
628                                 case FT_INT16:
629                                 case FT_INT24:
630                                 case FT_INT32:
631                                         format = "%s == %d";
632                                         break;
633                                 default:
634                                         g_assert_not_reached();
635                                         ;
636                         }
637                         break;
638                 case BASE_HEX:
639                         switch(hfinfo->type) {
640                                 case FT_UINT8:
641                                         format = "%s == 0x%02x";
642                                         break;
643                                 case FT_UINT16:
644                                         format = "%s == 0x%04x";
645                                         break;
646                                 case FT_UINT24:
647                                         format = "%s == 0x%06x";
648                                         break;
649                                 case FT_UINT32:
650                                         format = "%s == 0x%08x";
651                                         break;
652                                 default:
653                                         g_assert_not_reached();
654                                         ;
655                         }
656                         break;
657                 default:
658                         g_assert_not_reached();
659                         ;
660         }
661         return format;
662 }
663
664
665 /* Run the current display filter on the current packet set, and
666    redisplay. */
667 static void
668 filter_activate_cb(GtkWidget *w, gpointer data)
669 {
670   char *s = gtk_entry_get_text(GTK_ENTRY(w));
671
672   filter_packets(&cf, g_strdup(s));
673 }
674
675 /* redisplay with no display filter */
676 static void
677 filter_reset_cb(GtkWidget *w, gpointer data)
678 {
679   GtkWidget *filter_te = NULL;
680
681   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
682     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
683   }
684
685   filter_packets(&cf, NULL);
686 }
687
688 /* What to do when a list item is selected/unselected */
689 void
690 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
691
692 #ifdef HAVE_LIBPCAP
693   if (!sync_mode) {
694 #endif
695     if (cf.wth)
696       return; 
697 #ifdef HAVE_LIBPCAP
698   }
699 #endif
700   blank_packetinfo();
701   select_packet(&cf, row);
702 }
703
704 void
705 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
706   unselect_packet(&cf);
707 }
708
709 void
710 tree_view_cb(GtkWidget *w, gpointer data) {
711
712   field_info    *finfo;
713   int           tree_selected_start = -1;
714   int           tree_selected_len = -1;
715
716   if (GTK_TREE(w)->selection) {
717     finfo = 
718         gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
719                                    E_TREEINFO_FIELD_INFO_KEY);
720     g_assert(finfo);
721     finfo_selected = finfo;
722     tree_selected_start = finfo->start;
723     tree_selected_len   = finfo->length;
724   }
725
726   gtk_text_freeze(GTK_TEXT(byte_view));
727   gtk_text_set_point(GTK_TEXT(byte_view), 0);
728   gtk_text_forward_delete(GTK_TEXT(byte_view),
729     gtk_text_get_length(GTK_TEXT(byte_view)));
730   packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
731                    tree_selected_start, tree_selected_len,
732                    cf.current_frame->encoding);
733   
734   gtk_text_thaw(GTK_TEXT(byte_view));
735 }
736
737 void collapse_all_cb(GtkWidget *widget, gpointer data) {
738   if (cf.protocol_tree)
739     collapse_all_tree(cf.protocol_tree, tree_view);
740 }
741
742 void expand_all_cb(GtkWidget *widget, gpointer data) {
743   if (cf.protocol_tree)
744     expand_all_tree(cf.protocol_tree, tree_view);
745 }
746
747 void
748 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
749   if (cf.save_file && !cf.user_saved) {
750         unlink(cf.save_file);
751   }
752   gtk_exit(0);
753 }
754
755 /* call initialization routines at program startup time */
756 static void
757 ethereal_proto_init(void) {
758   init_dissect_rpc();
759   proto_init();
760   init_dissect_udp();
761   dfilter_init();
762 }
763
764 static void
765 ethereal_proto_cleanup(void) {
766         proto_cleanup();
767         dfilter_cleanup();
768 }
769
770 static void 
771 print_usage(void) {
772
773   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
774           VERSION, comp_info_str);
775   fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
776           PACKAGE);
777   fprintf(stderr, "         [-f <filter expression>] [-i interface] [-m <medium font>] [-n]\n");
778   fprintf(stderr, "         [-P <packet list height>] [-r infile] [-s snaplen]\n");
779   fprintf(stderr, "         [-t <time stamp format>] [-T <tree view height>] [-w savefile] \n");
780 }
781
782 /* And now our feature presentation... [ fade to music ] */
783 int
784 main(int argc, char *argv[])
785 {
786 #ifdef HAVE_LIBPCAP
787   char                *command_name;
788 #endif
789   char                *s;
790   int                  i;
791 #ifndef WIN32
792   int                  opt;
793   extern char         *optarg;
794 #endif
795 #ifdef HAVE_LIBPCAP
796   extern char         pcap_version[];
797 #endif
798   char                *pf_path;
799   int                 pf_open_errno = 0;
800   int                 err;
801 #ifdef HAVE_LIBPCAP
802   gboolean            start_capture = FALSE;
803   gchar              *save_file = NULL;
804 #endif
805   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
806                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
807                       *tv_scrollw, *filter_bt, *filter_te, *filter_reset;
808   GtkStyle            *pl_style;
809   GtkAccelGroup       *accel;
810   GtkWidget           *packet_sw;
811   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
812   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
813   dfilter             *rfcode = NULL;
814   gboolean             rfilter_parse_failed = FALSE;
815   e_prefs             *prefs;
816
817   ethereal_path = argv[0];
818
819 #ifdef HAVE_LIBPCAP
820   command_name = strrchr(ethereal_path, '/');
821   if (command_name == NULL)
822     command_name = ethereal_path;
823   else
824     command_name++;
825   /* Set "capture_child" to indicate whether this is going to be a child
826      process for a "-S" capture. */
827   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
828 #endif
829
830   /* If invoked with the "-G" flag, we dump out a glossary of
831      display filter symbols.
832
833      We must do this before calling "gtk_init()", because "gtk_init()"
834      tries to open an X display, and we don't want to have to do any X
835      stuff just to do a build.
836
837      Given that we call "gtk_init()" before doing the regular argument
838      list processing, so that it can handle X and GTK+ arguments and
839      remove them from the list at which we look, this means we must do
840      this before doing the regular argument list processing, as well.
841
842      This means that:
843
844         you must give the "-G" flag as the first flag on the command line;
845
846         you must give it as "-G", nothing more, nothing less;
847
848         any arguments after the "-G" flag will not be used. */
849   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
850     ethereal_proto_init();
851     proto_registrar_dump();
852     exit(0);
853   }
854
855   /* Let GTK get its args */
856   gtk_init (&argc, &argv);
857   
858   prefs = read_prefs(&pf_path);
859   if (pf_path != NULL) {
860     /* The preferences file exists, but couldn't be opened; "pf_path" is
861        its pathname.  Remember "errno", as that says why the attempt
862        failed. */
863     pf_open_errno = errno;
864   }
865
866   /* Initialize the capture file struct */
867   cf.plist              = NULL;
868   cf.plist_end          = NULL;
869   cf.wth                = NULL;
870   cf.fh                 = NULL;
871   cf.rfcode             = NULL;
872   cf.dfilter            = NULL;
873   cf.dfcode             = NULL;
874 #ifdef HAVE_LIBPCAP
875   cf.cfilter            = NULL;
876 #endif
877   cf.iface              = NULL;
878   cf.save_file          = NULL;
879   cf.save_file_fd       = -1;
880   cf.user_saved         = 0;
881   cf.snap               = WTAP_MAX_PACKET_SIZE;
882   cf.count              = 0;
883   cf.cinfo.num_cols     = prefs->num_cols;
884   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
885   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
886   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
887   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
888   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
889
890   /* Assemble the compile-time options */
891   snprintf(comp_info_str, 256,
892 #ifdef GTK_MAJOR_VERSION
893     "GTK+ %d.%d.%d, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
894     GTK_MICRO_VERSION,
895 #else
896     "GTK+ (version unknown), %s%s",
897 #endif
898
899 #ifdef HAVE_LIBPCAP
900    "with libpcap ", pcap_version
901 #else
902    "without libpcap", ""
903 #endif
904    );
905
906 #ifndef WIN32
907   /* Now get our args */
908   while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
909     switch (opt) {
910       case 'b':        /* Bold font */
911         bold_font = g_strdup(optarg);
912         break;
913       case 'B':        /* Byte view pane height */
914         bv_size = atoi(optarg);
915         break;
916       case 'c':        /* Capture xxx packets */
917         cf.count = atoi(optarg);
918         break;
919 #ifdef HAVE_LIBPCAP
920       case 'f':
921         cf.cfilter = g_strdup(optarg);
922         break;
923 #endif
924       case 'h':        /* Print help and exit */
925         print_usage();
926         exit(0);
927         break;
928       case 'i':        /* Use interface xxx */
929         cf.iface = g_strdup(optarg);
930         break;
931       case 'm':        /* Medium font */
932         medium_font = g_strdup(optarg);
933         break;
934       case 'n':        /* No name resolution */
935         g_resolving_actif = 0;
936         break;
937 #ifdef HAVE_LIBPCAP
938       case 'k':        /* Start capture immediately */
939         start_capture = TRUE;
940         break;
941 #endif
942       case 'P':        /* Packet list pane height */
943         pl_size = atoi(optarg);
944         break;
945 #ifdef HAVE_LIBPCAP
946       case 'Q':        /* Quit after capture (just capture to file) */
947         quit_after_cap = 1;
948         start_capture = TRUE;  /*** -Q implies -k !! ***/
949         break;
950 #endif
951       case 'r':        /* Read capture file xxx */
952         cf_name = g_strdup(optarg);
953         break;
954       case 'R':        /* Read file filter */
955         rfilter = optarg;
956         break;
957 #ifdef HAVE_LIBPCAP
958       case 's':        /* Set the snapshot (capture) length */
959         cf.snap = atoi(optarg);
960         break;
961       case 'S':        /* "Sync" mode: used for following file ala tail -f */
962         sync_mode = TRUE;
963         break;
964 #endif
965       case 't':        /* Time stamp type */
966         if (strcmp(optarg, "r") == 0)
967           timestamp_type = RELATIVE;
968         else if (strcmp(optarg, "a") == 0)
969           timestamp_type = ABSOLUTE;
970         else if (strcmp(optarg, "d") == 0)
971           timestamp_type = DELTA;
972         else {
973           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
974             optarg);
975           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
976           fprintf(stderr, "or \"d\" for delta.\n");
977           exit(1);
978         }
979         break;
980       case 'T':        /* Tree view pane height */
981         tv_size = atoi(optarg);
982         break;
983       case 'v':        /* Show version and exit */
984         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
985         exit(0);
986         break;
987 #ifdef HAVE_LIBPCAP
988       case 'w':        /* Write to capture file xxx */
989         save_file = g_strdup(optarg);
990         break;
991       case 'W':        /* Write to capture file FD xxx */
992         cf.save_file_fd = atoi(optarg);
993         break;
994 #endif
995       case '?':        /* Bad flag - print usage message */
996         print_usage();
997         break;
998     }
999   }
1000 #endif
1001
1002 #ifdef HAVE_LIBPCAP
1003   if (start_capture) {
1004     if (cf.iface == NULL) {
1005       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1006       exit(1);
1007     }
1008   }
1009   if (capture_child) {
1010     if (cf.save_file_fd == -1) {
1011       /* XXX - send this to the standard output as something our parent
1012          should put in an error message box? */
1013       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1014       exit(1);
1015     }
1016   }
1017 #endif
1018
1019   /* Build the column format array */  
1020   for (i = 0; i < cf.cinfo.num_cols; i++) {
1021     cf.cinfo.col_fmt[i] = get_column_format(i);
1022     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1023     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1024       NUM_COL_FMTS);
1025     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1026     if (cf.cinfo.col_fmt[i] == COL_INFO)
1027       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1028     else
1029       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1030   }
1031
1032   if (cf.snap < 1)
1033     cf.snap = WTAP_MAX_PACKET_SIZE;
1034   else if (cf.snap < MIN_PACKET_SIZE)
1035     cf.snap = MIN_PACKET_SIZE;
1036   
1037   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1038   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1039   gtk_rc_parse(rc_file);
1040
1041   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1042     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1043     exit(1);
1044   }
1045
1046   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1047     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1048     exit(1);
1049   }
1050
1051   /* Main window */  
1052   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1053   gtk_widget_set_name(window, "main window");
1054   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
1055     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1056   gtk_signal_connect(GTK_OBJECT(window), "destroy", 
1057     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1058   gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
1059   gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
1060   gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
1061
1062   /* Container for menu bar, paned windows and progress/info box */
1063   main_vbox = gtk_vbox_new(FALSE, 1);
1064   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1065   gtk_container_add(GTK_CONTAINER(window), main_vbox);
1066   gtk_widget_show(main_vbox);
1067
1068   /* Menu bar */
1069   get_main_menu(&menubar, &accel);
1070   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
1071   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1072   gtk_widget_show(menubar);
1073
1074   /* Panes for the packet list, tree, and byte view */
1075   u_pane = gtk_vpaned_new();
1076   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1077   l_pane = gtk_vpaned_new();
1078   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1079   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1080   gtk_widget_show(u_pane);
1081   gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
1082   gtk_widget_show(l_pane);
1083
1084   /* Packet list */
1085   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1086   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1087   packet_sw = gtk_scrolled_window_new(NULL, NULL);
1088   gtk_widget_show(packet_sw);
1089   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
1090   pl_style = gtk_style_new();
1091   gdk_font_unref(pl_style->font);
1092   pl_style->font = m_r_font;
1093   gtk_widget_set_style(packet_list, pl_style);
1094   gtk_widget_set_name(packet_list, "packet list");
1095   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1096     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1097   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1098     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1099   for (i = 0; i < cf.cinfo.num_cols; i++) {
1100     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1101       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1102
1103     /* Right-justify the packet number column. */
1104     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1105       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1106         GTK_JUSTIFY_RIGHT);
1107
1108     /* Save static column sizes to use during a "-S" capture, so that
1109        the columns don't resize during a live capture. */
1110     cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1111                                                 pl_style->font);
1112   }
1113   gtk_widget_set_usize(packet_list, -1, pl_size);
1114   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
1115   gtk_widget_show(packet_list);
1116   
1117   /* Tree view */
1118   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1119   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1120     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1121   gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
1122   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1123   gtk_widget_show(tv_scrollw);
1124   
1125   tree_view = gtk_tree_new();
1126   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
1127                   tree_view);
1128   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
1129
1130   /* XXX - what's the difference between the next two lines? */
1131   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
1132   gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
1133
1134   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
1135     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
1136   gtk_widget_show(tree_view);
1137
1138   item_style = gtk_style_new();
1139   gdk_font_unref(item_style->font);
1140   item_style->font = m_r_font;
1141
1142   /* Byte view */
1143   bv_table = gtk_table_new (2, 2, FALSE);
1144   gtk_paned_add2(GTK_PANED(l_pane), bv_table);
1145   gtk_widget_set_usize(bv_table, -1, bv_size);
1146   gtk_widget_show(bv_table);
1147
1148   byte_view = gtk_text_new(NULL, NULL);
1149   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1150   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1151   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
1152     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1153   gtk_widget_show(byte_view);
1154
1155   bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
1156   gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
1157     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1158   gtk_widget_show (bv_hscroll);
1159
1160   bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1161   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
1162     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1163   gtk_widget_show(bv_vscroll);
1164   
1165   /* Progress/filter/info box */
1166   stat_hbox = gtk_hbox_new(FALSE, 1);
1167   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1168   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1169   gtk_widget_show(stat_hbox);
1170
1171   prog_bar = gtk_progress_bar_new();
1172   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1173   gtk_widget_show(prog_bar);
1174
1175   filter_bt = gtk_button_new_with_label("Filter:");
1176   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1177     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
1178   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1179   gtk_widget_show(filter_bt);
1180   
1181   filter_te = gtk_entry_new();
1182   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1183   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
1184   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1185     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1186   gtk_widget_show(filter_te);
1187
1188   filter_reset = gtk_button_new_with_label("Reset");
1189   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1190   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1191                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1192   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1193   gtk_widget_show(filter_reset);
1194
1195   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1196    * of any widget that ends up calling a callback which needs
1197    * that text entry pointer */
1198   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1199   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1200   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY,
1201     filter_te);
1202
1203   info_bar = gtk_statusbar_new();
1204   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1205   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1206   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1207   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1208   gtk_widget_show(info_bar);
1209
1210 /* 
1211    Hmmm should we do it here
1212 */
1213
1214   ethereal_proto_init();   /* Init anything that needs initializing */
1215
1216 #ifdef HAVE_LIBPCAP
1217   /* Is this a "child" ethereal, which is only supposed to pop up a
1218      capture box to let us stop the capture, and run a capture
1219      to a file that our parent will read? */
1220   if (!capture_child) {
1221 #endif
1222     /* No.  Pop up the main window, and read in a capture file if
1223        we were told to. */
1224
1225     gtk_widget_show(window);
1226
1227     colors_init(&cf);
1228
1229     /* If we were given the name of a capture file, read it in now;
1230        we defer it until now, so that, if we can't open it, and pop
1231        up an alert box, the alert box is more likely to come up on
1232        top of the main window - but before the preference-file-error
1233        alert box, so, if we get one of those, it's more likely to come
1234        up on top of us. */
1235     if (cf_name) {
1236       if (rfilter != NULL) {
1237         if (dfilter_compile(rfilter, &rfcode) != 0) {
1238           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1239           rfilter_parse_failed = TRUE;
1240         }
1241       }
1242       if (!rfilter_parse_failed) {
1243         if ((err = open_cap_file(cf_name, &cf)) == 0) {
1244           /* "open_cap_file()" succeeded, so it closed the previous
1245              capture file, and thus destroyed any previous read filter
1246              attached to "cf". */
1247           cf.rfcode = rfcode;
1248           err = read_cap_file(&cf);
1249           s = strrchr(cf_name, '/');
1250           if (s) {
1251             last_open_dir = cf_name;
1252             *s = '\0';
1253           }
1254           set_menu_sensitivity("/File/Save As...", TRUE);
1255         } else {
1256           dfilter_destroy(rfcode);
1257           cf.rfcode = NULL;
1258         }
1259       }
1260     }
1261 #ifdef HAVE_LIBPCAP
1262   }
1263 #endif
1264
1265   /* If we failed to open the preferences file, pop up an alert box;
1266      we defer it until now, so that the alert box is more likely to
1267      come up on top of the main window. */
1268   if (pf_path != NULL) {
1269       simple_dialog(ESD_TYPE_WARN, NULL,
1270         "Could not open preferences file\n\"%s\": %s.", pf_path,
1271         strerror(pf_open_errno));
1272   }
1273
1274 #ifdef HAVE_LIBPCAP
1275   if (capture_child) {
1276     /* This is the child process for a sync mode or fork mode capture,
1277        so just do the low-level work of a capture - don't create
1278        a temporary file and fork off *another* child process (so don't
1279        call "do_capture()"). */
1280
1281        capture();
1282
1283        /* The capture is done; there's nothing more for us to do. */
1284        gtk_exit(0);
1285   } else {
1286     if (start_capture) {
1287       /* "-k" was specified; start a capture. */
1288       do_capture(save_file);
1289     }
1290   }
1291 #endif
1292
1293   gtk_main();
1294
1295   ethereal_proto_cleanup();
1296   g_free(rc_file);
1297
1298   exit(0);
1299 }