Cleaned up the two routines besides the main display filter mechanism
[obnox/wireshark/wip.git] / ethereal.c
1 /* ethereal.c
2  *
3  * $Id: ethereal.c,v 1.98 1999/08/20 19:43:10 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  * - Live browser/capture display
29  * - Graphs
30  * - Get AIX to work
31  * - Check for end of packet in dissect_* routines.
32  * - Playback window
33  * - Multiple window support
34  * - Add cut/copy/paste
35  * - Create header parsing routines
36  * - Check fopens, freads, fwrites
37  * - Make byte view scrollbars automatic?
38  * - Make byte view selections more fancy?
39  *
40  */
41
42 #ifdef HAVE_CONFIG_H
43 # include "config.h"
44 #endif
45
46 #include <gtk/gtk.h>
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #include <errno.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60
61 #ifdef HAVE_DIRECT_H
62 #include <direct.h>
63 #endif
64
65 #ifdef HAVE_NETINET_IN_H
66 #include <netinet/in.h>
67 #endif
68
69 #include <signal.h>
70
71 #ifdef NEED_SNPRINTF_H
72 # ifdef HAVE_STDARG_H
73 #  include <stdarg.h>
74 # else
75 #  include <varargs.h>
76 # endif
77 # include "snprintf.h"
78 #endif
79
80 #ifdef NEED_STRERROR_H
81 #include "strerror.h"
82 #endif
83
84 #include "ethereal.h"
85 #include "timestamp.h"
86 #include "packet.h"
87 #include "capture.h"
88 #include "summary.h"
89 #include "file.h"
90 #include "menu.h"
91 #include "etypes.h"
92 #include "prefs.h"
93 #include "column.h"
94 #include "print.h"
95 #include "resolv.h"
96 #include "follow.h"
97 #include "util.h"
98 #include "gtkpacket.h"
99 #include "dfilter.h"
100
101 static void file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs);
102 static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
103 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
104 static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data);
105 static void print_file_cb(GtkWidget *file_bt, gpointer file_te);
106 static void print_fs_ok_cb(GtkWidget *w, gpointer data);
107 static void print_fs_cancel_cb(GtkWidget *w, gpointer data);
108 static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
109 static void print_close_cb(GtkWidget *close_bt, gpointer parent_w);
110
111 FILE        *data_out_file = NULL;
112 packet_info  pi;
113 capture_file cf;
114 GtkWidget   *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
115             *info_bar;
116 GdkFont     *m_r_font, *m_b_font;
117 guint        main_ctx, file_ctx;
118 gint         start_capture = 0;
119 gchar        comp_info_str[256];
120 gchar       *ethereal_path = NULL;
121 gchar       *medium_font = MONO_MEDIUM_FONT;
122 gchar       *bold_font = MONO_BOLD_FONT;
123 gchar       *last_open_dir = NULL;
124
125 ts_type timestamp_type = RELATIVE;
126
127 GtkStyle *item_style;
128
129 #ifdef HAVE_LIBPCAP
130 int sync_mode;  /* allow sync */
131 int sync_pipe[2]; /* used to sync father */
132 int fork_mode;  /* fork a child to do the capture */
133 int sigusr2_received = 0;
134 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
135 #endif
136
137 /* Specifies byte offsets for object selected in tree */
138 static gint tree_selected_start=-1, tree_selected_len=-1; 
139
140 #define E_DFILTER_TE_KEY "display_filter_te"
141 #define E_RFILTER_TE_KEY "read_filter_te"
142
143 /* About Ethereal window */
144 void
145 about_ethereal( GtkWidget *w, gpointer data ) {
146   simple_dialog(ESD_TYPE_INFO, NULL,
147                 "GNU Ethereal - network protocol analyzer\n"
148                 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
149                 "Compiled with %s\n\n"
150                 "Contributors:\n"
151
152                 "Gilbert Ramirez          <gramirez@tivoli.com>\n"
153                 "Hannes R. Boehm          <hannes@boehm.org>\n"
154                 "Mike Hall                <mlh@io.com>\n"
155                 "Bobo Rajec               <bobo@bsp-consulting.sk>\n"
156                 "Laurent Deniel           <deniel@worldnet.fr>\n"
157                 "Don Lafontaine           <lafont02@cn.ca>\n"
158                 "Guy Harris               <guy@netapp.com>\n"
159                 "Simon Wilkinson          <sxw@dcs.ed.ac.uk>\n"
160                 "Joerg Mayer              <jmayer@telemation.de>\n"
161                 "Martin Maciaszek         <fastjack@i-s-o.net>\n"
162                 "Didier Jorand            <Didier.Jorand@alcatel.fr>\n"
163                 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
164                 "Richard Sharpe           <sharpe@ns.aus.com>\n"
165                 "John McDermott           <jjm@jkintl.com>\n"
166                 "Jeff Jahr                <jjahr@shastanets.com>\n"
167                 "Brad Robel-Forrest       <bradr@watchguard.com>\n"
168                 "Ashok Narayanan          <ashokn@cisco.com>\n"
169                 "Aaron Hillegass          <aaron@classmax.com>\n"
170                 "Jason Lango              <jal@netapp.com>\n"
171                 "Johan Feyaerts           <Johan.Feyaerts@siemens.atea.be>\n"
172                 "Olivier Abad             <abad@daba.dhis.org>\n"
173                 "Thierry Andry            <Thierry.Andry@advalvas.be>\n"
174                 "Jeff Foster              <jjfoste@woodward.com>\n"
175
176                 "\nSee http://ethereal.zing.org for more information",
177                 VERSION, comp_info_str);
178 }
179
180 /* Update the progress bar */
181 gint
182 file_progress_cb(gpointer p) {
183   capture_file *cf = (capture_file*) p;
184   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
185     (gfloat) ftell(cf->fh) / (gfloat) cf->f_len);
186   return TRUE;
187 }
188
189 /* Follow the TCP stream, if any, to which the last packet that we called
190    a dissection routine on belongs (this might be the most recently
191    selected packet, or it might be the last packet in the file). */
192 void
193 follow_stream_cb( GtkWidget *w, gpointer data ) {
194   char      filename1[128+1];
195   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
196   int        tmp_fd;
197   gchar     *old_dfilter;
198
199   if( pi.ipproto == 6 ) {
200     /* we got tcp so we can follow */
201     /* Create a temporary file into which to dump the reassembled data
202        from the TCP stream, and set "data_out_file" to refer to it, so
203        that the TCP code will write to it.
204
205        XXX - it might be nicer to just have the TCP code directly
206        append stuff to the text widget for the TCP stream window,
207        if we can arrange that said window not pop up until we're
208        done. */
209     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
210     if (tmp_fd == -1) {
211       simple_dialog(ESD_TYPE_WARN, NULL,
212         "Could not create temporary file %s: %s", filename1, strerror(errno));
213       return;
214     }
215     data_out_file = fdopen( tmp_fd, "w" );
216     if( data_out_file == NULL ) {
217       simple_dialog(ESD_TYPE_WARN, NULL,
218         "Could not create temporary file %s: %s", filename1, strerror(errno));
219       close(tmp_fd);
220       unlink(filename1);
221       return;
222     }
223
224     /* Save any display filter we currently have. */
225     old_dfilter = cf.dfilter;
226
227     /* Create a new filter that matches all packets in the TCP stream,
228        and set the display filter entry accordingly */
229     reset_tcp_reassembly();
230     cf.dfilter = build_follow_filter( &pi );
231
232     /* Run the display filter so it goes in effect. */
233     filter_packets(&cf);
234
235     /* the data_out_file should now be full of the streams information */
236     fclose( data_out_file );
237
238     /* the filename1 file now has all the text that was in the session */
239     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
240     gtk_widget_set_name( streamwindow, "TCP stream window" );
241     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
242                         NULL, "WM destroy" );
243     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
244                         NULL, "WM destroy" );
245     if( incomplete_tcp_stream ) {
246       gtk_window_set_title( GTK_WINDOW(streamwindow), 
247                             "Contents of TCP stream (incomplete)" );
248     } else {
249       gtk_window_set_title( GTK_WINDOW(streamwindow),
250                             "Contents of TCP stream" );
251     }
252     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
253     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
254
255     /* setup the container */
256     box = gtk_vbox_new( FALSE, 0 );
257     gtk_container_add( GTK_CONTAINER(streamwindow), box );
258     gtk_widget_show( box );
259
260     /* set up the table we attach to */
261     table = gtk_table_new( 1, 2, FALSE );
262     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
263     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
264     gtk_widget_show( table );
265
266     /* create a text box */
267     text = gtk_text_new( NULL, NULL );
268     gtk_text_set_editable( GTK_TEXT(text), FALSE);
269     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
270                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
271                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
272     gtk_widget_show(text);
273
274     /* create the scrollbar */
275     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
276     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
277                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
278     gtk_widget_show( vscrollbar );
279     gtk_widget_realize( text );
280
281     /* stop the updates while we fill the text box */
282     gtk_text_freeze( GTK_TEXT(text) );
283     data_out_file = fopen( filename1, "r" );
284     if( data_out_file ) {
285       char buffer[1024];
286       int nchars;
287       while( 1 ) {
288         nchars = fread( buffer, 1, 1024, data_out_file );
289         gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
290         if( nchars < 1024 ) {
291           break;
292         }
293       }
294       if( ferror( data_out_file ) ) {
295         simple_dialog(ESD_TYPE_WARN, NULL,
296           "Error reading temporary file %s: %s", filename1, strerror(errno));
297       }
298       fclose( data_out_file );
299     } else {
300       simple_dialog(ESD_TYPE_WARN, NULL,
301         "Could not open temporary file %s: %s", filename1, strerror(errno));
302     }
303     gtk_text_thaw( GTK_TEXT(text) );
304     unlink( filename1 );
305     data_out_file = NULL;
306     gtk_widget_show( streamwindow );
307     if( cf.dfilter != NULL ) {
308       g_free( cf.dfilter );
309     }
310     cf.dfilter = old_dfilter;
311     filter_packets(&cf);
312   } else {
313     simple_dialog(ESD_TYPE_WARN, NULL,
314       "Error following stream.  Please make\n"
315       "sure you have a TCP packet selected.");
316   }
317 }
318
319 /* Match selected byte pattern */
320 void
321 match_selected_cb(GtkWidget *w, gpointer data)
322 {
323     char *buf = g_malloc(1024);
324     GtkWidget *filter_te = NULL;
325     char *ptr;
326     int i;
327     guint8 *c;
328
329     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
330
331     if (tree_selected_start<0) {
332         simple_dialog(ESD_TYPE_WARN, NULL,
333                       "Error determining selected bytes.  Please make\n"
334                       "sure you have selected a field within the tree\n"
335                       "view to be matched.");
336         return;
337     }
338
339     c = cf.pd + tree_selected_start;
340     ptr = buf;
341
342     sprintf(ptr, "frame[%d : %d] == ", tree_selected_start, tree_selected_len);
343     ptr = buf+strlen(buf);
344
345     if (tree_selected_len == 1) {
346         sprintf(ptr, "0x%02x", *c++);
347     }
348     else {
349             for (i=0;i<tree_selected_len; i++) {
350                 if (i == 0 ) {
351                         sprintf(ptr, "%02x", *c++);
352                 }
353                 else {
354                         sprintf(ptr, ":%02x", *c++);
355                 }
356                 ptr = buf+strlen(buf);
357             }
358     }
359
360     if( cf.dfilter != NULL ) {
361       /* get rid of this one */
362       g_free( cf.dfilter );
363     }
364     /* create a new one and set the display filter entry accordingly */
365     cf.dfilter = buf;
366     if (filter_te) {
367         gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
368         printf("set text to %s\n", cf.dfilter);
369     }
370     /* Run the display filter so it goes in effect. */
371     filter_packets(&cf);
372 }
373
374 /* Open a file */
375 void
376 file_open_cmd_cb(GtkWidget *w, gpointer data) {
377   GtkWidget *filter_hbox, *filter_bt, *filter_te;
378
379   if (last_open_dir)
380           chdir(last_open_dir);
381
382   file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
383   
384   /* Connect the ok_button to file_open_ok_cb function and pass along a
385      pointer to the file selection box widget */
386   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
387     "clicked", (GtkSignalFunc) file_open_ok_cb, file_sel );
388
389   gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
390       E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
391
392   filter_hbox = gtk_hbox_new(FALSE, 1);
393   gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
394   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_sel)->action_area),
395     filter_hbox, FALSE, FALSE, 0);
396   gtk_widget_show(filter_hbox);
397
398   filter_bt = gtk_button_new_with_label("Filter:");
399   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
400     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
401   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
402   gtk_widget_show(filter_bt);
403   
404   filter_te = gtk_entry_new();
405   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
406   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
407   gtk_widget_show(filter_te);
408
409   gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
410     E_RFILTER_TE_KEY, filter_te);
411
412   /* Connect the cancel_button to destroy the widget */
413   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
414     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
415     gtk_widget_destroy, GTK_OBJECT (file_sel));
416
417 #ifdef HAVE_LIBPCAP
418   if( fork_mode && (cf.save_file != NULL) )
419 #else
420   if( cf.save_file != NULL )
421 #endif
422     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
423   else
424     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
425
426   gtk_widget_show(file_sel);
427 }
428
429 static void
430 file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
431   gchar     *cf_name, *rfilter, *s;
432   GtkWidget *filter_te;
433   dfilter   *rfcode = NULL;
434   int        err;
435
436   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
437   filter_te = gtk_object_get_data(GTK_OBJECT(w), E_RFILTER_TE_KEY);
438   rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
439   if (rfilter[0] != '\0') {
440         rfcode = dfilter_new();
441         if (dfilter_compile(rfcode, rfilter) != 0) {
442                 simple_dialog(ESD_TYPE_WARN, NULL,
443                     "Unable to parse filter string \"%s\".", rfilter);
444                 dfilter_destroy(rfcode);
445                 return;
446         }
447   }
448
449   /* Try to open the capture file. */
450   if ((err = open_cap_file(cf_name, &cf)) != 0) {
451     /* We couldn't open it; don't dismiss the open dialog box,
452        just leave it around so that the user can, after they
453        dismiss the alert box popped up for the open error,
454        try again. */
455     if (rfcode != NULL)
456       dfilter_destroy(rfcode);
457     return;
458   }
459
460   /* Attach the new read filter to "cf" ("open_cap_file()" succeeded, so
461      it closed the previous capture file, and thus destroyed any
462      previous read filter attached to "cf"). */
463   cf.rfcode = rfcode;
464
465   /* We've crossed the Rubicon; get rid of the file selection box. */
466   gtk_widget_hide(GTK_WIDGET (fs));
467   gtk_widget_destroy(GTK_WIDGET (fs));
468
469   err = read_cap_file(&cf);
470   /* Save the directory name; we can write over cf_name. */
471   s = strrchr(cf_name, '/');
472   if (s && last_open_dir) {
473           *s = '\0';
474           if (strcmp(last_open_dir, cf_name) != 0) {
475                   g_free(last_open_dir);
476                   last_open_dir = g_strdup(cf_name);
477           }
478   }
479   else if (s) { /* ! last_open_dir */
480           *s = '\0';
481           last_open_dir = g_strdup(cf_name);
482   }
483   else {
484           last_open_dir = NULL;
485   }
486   set_menu_sensitivity("/File/Save", FALSE);
487   set_menu_sensitivity("/File/Save As...", TRUE);
488   g_free(cf_name);
489 }
490
491 /* Close a file */
492 void
493 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
494   close_cap_file(&cf, info_bar, file_ctx);
495 }
496
497 void
498 file_save_cmd_cb(GtkWidget *w, gpointer data) {
499   file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
500  
501   /* Connect the ok_button to file_save_ok_cb function and pass along a
502      pointer to the file selection box widget */
503   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
504     "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
505
506   /* Connect the cancel_button to destroy the widget */
507   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
508     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
509     gtk_widget_destroy, GTK_OBJECT (file_sel));
510
511   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
512
513   gtk_widget_show(file_sel);
514 }
515
516 void
517 file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
518   file_sel = gtk_file_selection_new ("Ethereal: Save Capture File As");
519
520   /* Connect the ok_button to file_save_as_ok_cb function and pass along a
521      pointer to the file selection box widget */
522   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
523     "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
524
525   /* Connect the cancel_button to destroy the widget */
526   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
527     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
528     gtk_widget_destroy, GTK_OBJECT (file_sel));
529
530   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
531   gtk_widget_show(file_sel);
532 }
533
534 static void
535 file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
536         gchar   *cf_name;
537         int     err;
538
539         cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
540         gtk_widget_hide(GTK_WIDGET (fs));
541         gtk_widget_destroy(GTK_WIDGET (fs));
542
543         if (!file_mv(cf.save_file, cf_name))
544                 return;
545
546         g_free(cf.save_file);
547         cf.save_file = g_strdup(cf_name);
548         cf.user_saved = 1;
549         if ((err = open_cap_file(cf_name, &cf)) == 0) {
550                 err = read_cap_file(&cf);
551                 set_menu_sensitivity("/File/Save", FALSE);
552                 set_menu_sensitivity("/File/Save As...", TRUE);
553         }
554 }
555
556 static void
557 file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
558         gchar   *cf_name;
559         int     err;
560
561         cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
562         gtk_widget_hide(GTK_WIDGET (fs));
563         gtk_widget_destroy(GTK_WIDGET (fs));
564         if (!file_cp(cf.filename, cf_name))
565                 return;
566         g_free(cf.filename);
567         cf.filename = g_strdup(cf_name);
568         cf.user_saved = 1;
569         if ((err = open_cap_file(cf.filename, &cf)) == 0) {
570                 err = read_cap_file(&cf);
571                 set_menu_sensitivity("/File/Save", FALSE);
572                 set_menu_sensitivity("/File/Save As...", TRUE);
573         }
574 }
575
576 /* Reload a file using the current read and display filters */
577 void
578 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
579   /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
580   GtkWidget *filter_te;
581
582   filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
583
584   if (cf.dfilter) g_free(cf.dfilter);
585   cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
586   if (open_cap_file(cf.filename, &cf) == 0)
587     read_cap_file(&cf);
588   /* XXX - change the menu if the open fails? */
589 }
590
591 /* Run the current display filter on the current packet set, and
592    redisplay. */
593 static void
594 filter_activate_cb(GtkWidget *w, gpointer data)
595 {
596   char *s = gtk_entry_get_text(GTK_ENTRY(w));
597
598   if (cf.dfilter)
599         g_free(cf.dfilter);
600
601   /* simple check for empty string. XXX - need to modify to search for /^\s+$/ */
602   if (s[0] == '\0' ) {
603         cf.dfilter = NULL;
604   }
605   else {
606         cf.dfilter = g_strdup(s);
607   }
608
609   filter_packets(&cf);
610 }
611
612 /*
613  * Remember whether we printed to a printer or a file the last time we
614  * printed something.
615  */
616 static int     print_to_file;
617
618 /* Keys for gtk_object_set_data */
619 #define PRINT_CMD_LB_KEY  "printer_command_label"
620 #define PRINT_CMD_TE_KEY  "printer_command_entry"
621 #define PRINT_FILE_BT_KEY "printer_file_button"
622 #define PRINT_FILE_TE_KEY "printer_file_entry"
623 #define PRINT_DEST_RB_KEY "printer_destination_radio_button"
624
625 /* Print the capture */
626 void
627 file_print_cmd_cb(GtkWidget *widget, gpointer data)
628 {
629   GtkWidget     *print_w;
630   GtkWidget     *main_vb, *main_tb, *button;
631 #if 0
632   GtkWidget     *format_hb, *format_lb;
633   GSList        *format_grp;
634 #endif
635   GtkWidget     *dest_rb;
636   GtkWidget     *dest_hb, *dest_lb;
637   GtkWidget     *cmd_lb, *cmd_te;
638   GtkWidget     *file_bt_hb, *file_bt, *file_te;
639   GSList        *dest_grp;
640   GtkWidget     *bbox, *ok_bt, *cancel_bt;
641
642   /* XXX - don't pop up one if there's already one open; instead,
643        give it the input focus if that's possible. */
644
645   print_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
646   gtk_window_set_title(GTK_WINDOW(print_w), "Ethereal: Print");
647
648   /* Enclosing containers for each row of widgets */
649   main_vb = gtk_vbox_new(FALSE, 5);
650   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
651   gtk_container_add(GTK_CONTAINER(print_w), main_vb);
652   gtk_widget_show(main_vb);
653   
654   main_tb = gtk_table_new(4, 2, FALSE);
655   gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
656   gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
657   gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
658   gtk_widget_show(main_tb);
659
660   /* XXX - printing multiple frames in PostScript looks as if it's
661      tricky - you have to deal with page boundaries, I think -
662      and I'll have to spend some time learning enough about
663      PostScript to figure it out, so, for now, we only print
664      multiple frames as text. */
665 #if 0
666   /* Output format */
667   format_lb = gtk_label_new("Format:");
668   gtk_misc_set_alignment(GTK_MISC(format_lb), 1.0, 0.5);
669   gtk_table_attach_defaults(GTK_TABLE(main_tb), format_lb, 0, 1, 0, 1);
670   gtk_widget_show(format_lb);
671
672   format_hb = gtk_hbox_new(FALSE, 0);
673   gtk_table_attach_defaults(GTK_TABLE(main_tb), format_hb, 1, 2, 0, 1);
674   gtk_widget_show(format_hb);
675
676   button = gtk_radio_button_new_with_label(NULL, "Plain Text");
677   if (prefs.pr_format == PR_FMT_TEXT)
678     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
679   format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
680   gtk_box_pack_start(GTK_BOX(format_hb), button, FALSE, FALSE, 10);
681   gtk_widget_show(button);
682
683   button = gtk_radio_button_new_with_label(format_grp, "PostScript");
684   if (prefs.pr_format == PR_FMT_PS)
685     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
686   gtk_box_pack_start(GTK_BOX(format_hb), button, FALSE, FALSE, 10);
687   gtk_widget_show(button);
688 #endif
689
690   /* Output destination */
691   dest_lb = gtk_label_new("Print to:");
692   gtk_misc_set_alignment(GTK_MISC(dest_lb), 1.0, 0.5);
693   gtk_table_attach_defaults(GTK_TABLE(main_tb), dest_lb, 0, 1, 1, 2);
694   gtk_widget_show(dest_lb);
695
696   dest_hb = gtk_hbox_new(FALSE, 0);
697   gtk_table_attach_defaults(GTK_TABLE(main_tb), dest_hb, 1, 2, 1, 2);
698   gtk_widget_show(dest_hb);
699
700   button = gtk_radio_button_new_with_label(NULL, "Command");
701   if (!print_to_file)
702     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
703   dest_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
704   gtk_box_pack_start(GTK_BOX(dest_hb), button, FALSE, FALSE, 10);
705   gtk_widget_show(button);
706
707   dest_rb = gtk_radio_button_new_with_label(dest_grp, "File");
708   if (print_to_file)
709     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dest_rb), TRUE);
710   gtk_signal_connect(GTK_OBJECT(dest_rb), "toggled",
711                         GTK_SIGNAL_FUNC(print_cmd_toggle_dest), NULL);
712   gtk_box_pack_start(GTK_BOX(dest_hb), dest_rb, FALSE, FALSE, 10);
713   gtk_widget_show(dest_rb);
714
715   /* Command text entry */
716   cmd_lb = gtk_label_new("Command:");
717   gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_CMD_LB_KEY, cmd_lb);
718   gtk_misc_set_alignment(GTK_MISC(cmd_lb), 1.0, 0.5);
719   gtk_table_attach_defaults(GTK_TABLE(main_tb), cmd_lb, 0, 1, 2, 3);
720   gtk_widget_set_sensitive(cmd_lb, !print_to_file);
721   gtk_widget_show(cmd_lb);
722
723   cmd_te = gtk_entry_new();
724   gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_CMD_TE_KEY, cmd_te);
725   if (prefs.pr_cmd)
726     gtk_entry_set_text(GTK_ENTRY(cmd_te), prefs.pr_cmd);
727   gtk_table_attach_defaults(GTK_TABLE(main_tb), cmd_te, 1, 2, 2, 3);
728   gtk_widget_set_sensitive(cmd_te, !print_to_file);
729   gtk_widget_show(cmd_te);
730
731   /* File button and text entry */
732   file_bt_hb = gtk_hbox_new(FALSE, 0);
733   gtk_table_attach_defaults(GTK_TABLE(main_tb), file_bt_hb, 0, 1, 3, 4);
734   gtk_widget_show(file_bt_hb);
735
736   file_bt = gtk_button_new_with_label("File:");
737   gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_FILE_BT_KEY, file_bt);
738   gtk_box_pack_end(GTK_BOX(file_bt_hb), file_bt, FALSE, FALSE, 0);
739   gtk_widget_set_sensitive(file_bt, print_to_file);
740   gtk_widget_show(file_bt);
741
742   file_te = gtk_entry_new();
743   gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_FILE_TE_KEY, file_te);
744   gtk_table_attach_defaults(GTK_TABLE(main_tb), file_te, 1, 2, 3, 4);
745   gtk_widget_set_sensitive(file_te, print_to_file);
746   gtk_widget_show(file_te);
747
748   gtk_signal_connect(GTK_OBJECT(file_bt), "clicked",
749                 GTK_SIGNAL_FUNC(print_file_cb), GTK_OBJECT(file_te));
750
751   /* Button row: OK and Cancel buttons */
752   bbox = gtk_hbutton_box_new();
753   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
754   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
755   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
756   gtk_widget_show(bbox);
757
758   ok_bt = gtk_button_new_with_label ("OK");
759   gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_DEST_RB_KEY, dest_rb);
760   gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_CMD_TE_KEY, cmd_te);
761   gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_FILE_TE_KEY, file_te);
762   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
763     GTK_SIGNAL_FUNC(print_ok_cb), GTK_OBJECT(print_w));
764   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
765   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
766   gtk_widget_grab_default(ok_bt);
767   gtk_widget_show(ok_bt);
768
769   cancel_bt = gtk_button_new_with_label ("Cancel");
770   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
771     GTK_SIGNAL_FUNC(print_close_cb), GTK_OBJECT(print_w));
772   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
773   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
774   gtk_widget_show(cancel_bt);
775
776 #if 0
777   display_opt_window_active = TRUE;
778 #endif
779   gtk_widget_show(print_w);
780 }
781
782 static void
783 print_cmd_toggle_dest(GtkWidget *widget, gpointer data)
784 {
785   GtkWidget     *cmd_lb, *cmd_te, *file_bt, *file_te;
786   int            to_file;
787
788   cmd_lb = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
789     PRINT_CMD_LB_KEY));
790   cmd_te = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
791     PRINT_CMD_TE_KEY));
792   file_bt = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
793     PRINT_FILE_BT_KEY));
794   file_te = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget),
795     PRINT_FILE_TE_KEY));
796   if (GTK_TOGGLE_BUTTON (widget)->active) {
797     /* They selected "Print to File" */
798     to_file = TRUE;
799   } else {
800     /* They selected "Print to Command" */
801     to_file = FALSE;
802   }
803   gtk_widget_set_sensitive(cmd_lb, !to_file);
804   gtk_widget_set_sensitive(cmd_te, !to_file);
805   gtk_widget_set_sensitive(file_bt, to_file);
806   gtk_widget_set_sensitive(file_te, to_file);
807 }
808
809 static void
810 print_file_cb(GtkWidget *file_bt, gpointer file_te)
811 {
812   GtkWidget *fs;
813
814   fs = gtk_file_selection_new ("Ethereal: Print to File");
815         gtk_object_set_data(GTK_OBJECT(fs), PRINT_FILE_TE_KEY, file_te);
816
817   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
818     "clicked", (GtkSignalFunc) print_fs_ok_cb, fs);
819
820   /* Connect the cancel_button to destroy the widget */
821   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
822     "clicked", (GtkSignalFunc) print_fs_cancel_cb, fs);
823
824   gtk_widget_show(fs);
825 }
826
827 static void
828 print_fs_ok_cb(GtkWidget *w, gpointer data)
829 {
830   
831   gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(data),
832       PRINT_FILE_TE_KEY)),
833       gtk_file_selection_get_filename (GTK_FILE_SELECTION(data)));
834   gtk_widget_destroy(GTK_WIDGET(data));
835 }
836
837 static void
838 print_fs_cancel_cb(GtkWidget *w, gpointer data)
839 {
840   gtk_widget_destroy(GTK_WIDGET(data));
841 }
842
843 static void
844 print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
845 {
846   GtkWidget *button;
847   char *dest;
848
849   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(ok_bt),
850                                               PRINT_DEST_RB_KEY);
851   if (GTK_TOGGLE_BUTTON (button)->active)
852     print_to_file = TRUE;
853   else
854     print_to_file = FALSE;
855
856   if (print_to_file)
857     dest = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(ok_bt),
858       PRINT_FILE_TE_KEY))));
859   else
860     dest = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(ok_bt),
861       PRINT_CMD_TE_KEY))));
862
863   gtk_widget_destroy(GTK_WIDGET(parent_w));
864 #if 0
865   display_opt_window_active = FALSE;
866 #endif
867
868   /* Now print the packets */
869   if (!print_packets(&cf, print_to_file, dest)) {
870     if (print_to_file)
871       simple_dialog(ESD_TYPE_WARN, NULL,
872         file_write_error_message(errno), dest);
873     else
874       simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't run print command %s.",
875         prefs.pr_cmd);
876   }
877
878   g_free(dest);
879 }
880
881 static void
882 print_close_cb(GtkWidget *close_bt, gpointer parent_w)
883 {
884
885   gtk_grab_remove(GTK_WIDGET(parent_w));
886   gtk_widget_destroy(GTK_WIDGET(parent_w));
887 #if 0
888   display_opt_window_active = FALSE;
889 #endif
890 }
891
892 /* Print a packet */
893 void
894 file_print_packet_cmd_cb(GtkWidget *widget, gpointer data) {
895   FILE *fh;
896
897   switch (prefs.pr_dest) {
898
899   case PR_DEST_CMD:
900     fh = popen(prefs.pr_cmd, "w");
901     break;
902
903   case PR_DEST_FILE:
904     fh = fopen(prefs.pr_file, "w");
905     break;
906
907   default:
908     fh = NULL;  /* XXX - "can't happen" */
909     break;
910   }
911   if (fh == NULL) {
912     switch (prefs.pr_dest) {
913
914     case PR_DEST_CMD:
915       simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't run print command %s.",
916         prefs.pr_cmd);
917       break;
918
919     case PR_DEST_FILE:
920       simple_dialog(ESD_TYPE_WARN, NULL, file_write_error_message(errno),
921         prefs.pr_file);
922       break;
923     }
924     return;
925   }
926
927   print_preamble(fh);
928   proto_tree_print(-1, (GNode*) cf.protocol_tree, cf.pd, cf.fd, fh);
929   print_finale(fh);
930   close_print_dest(prefs.pr_dest == PR_DEST_FILE, fh);
931 }
932
933 /* What to do when a list item is selected/unselected */
934 void
935 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
936
937 #ifdef HAVE_LIBPCAP
938   if (!sync_mode) {
939 #endif
940     if (cf.wth)
941       return; 
942 #ifdef HAVE_LIBPCAP
943   }
944 #endif
945   blank_packetinfo();
946   select_packet(&cf, row);
947 }
948
949 void
950 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
951   unselect_packet(&cf);
952 }
953
954 void
955 tree_view_cb(GtkWidget *w, gpointer data) {
956
957   tree_selected_start = -1;
958   tree_selected_len = -1;
959
960   if (GTK_TREE(w)->selection) {
961     tree_selected_start = 
962         (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
963                                    E_TREEINFO_START_KEY);
964     tree_selected_len   = 
965         (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
966                                    E_TREEINFO_LEN_KEY);
967   }
968
969   gtk_text_freeze(GTK_TEXT(byte_view));
970   gtk_text_set_point(GTK_TEXT(byte_view), 0);
971   gtk_text_forward_delete(GTK_TEXT(byte_view),
972     gtk_text_get_length(GTK_TEXT(byte_view)));
973   packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.fd->cap_len, 
974                    tree_selected_start, 
975                    tree_selected_len);
976   
977   gtk_text_thaw(GTK_TEXT(byte_view));
978 }
979
980 void
981 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
982   if (cf.save_file && !cf.user_saved) {
983         unlink(cf.save_file);
984   }
985   gtk_exit(0);
986 }
987
988 void blank_packetinfo() {
989   pi.ip_src   = 0;
990   pi.ip_dst   = 0;
991   pi.ipproto  = 0;
992   pi.srcport  = 0;
993   pi.destport = 0;
994 }
995
996 /* Things to do when the main window is realized */
997 void
998 main_realize_cb(GtkWidget *w, gpointer data) {
999 #ifdef HAVE_LIBPCAP
1000   if (start_capture) {
1001     capture();
1002     start_capture = 0;
1003   }
1004 #endif
1005 }
1006
1007 #ifdef HAVE_LIBPCAP
1008 static void 
1009 sigusr2_handler(int sig) {
1010   sigusr2_received = 1;
1011   signal(SIGUSR2, sigusr2_handler);
1012 }
1013 #endif
1014
1015 /* call initialization routines at program startup time */
1016 static void
1017 ethereal_proto_init(void) {
1018   proto_init();
1019   init_dissect_udp();
1020   dfilter_init();
1021 }
1022
1023 static void 
1024 print_usage(void) {
1025
1026   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
1027           VERSION, comp_info_str);
1028   fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n",
1029           PACKAGE);
1030   fprintf(stderr, "         [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n");
1031   fprintf(stderr, "         [-P packet list height] [-r infile] [-s snaplen]\n");
1032   fprintf(stderr, "         [-t <time stamp format>] [-T tree view height] [-w savefile] \n");
1033 }
1034
1035 /* And now our feature presentation... [ fade to music ] */
1036 int
1037 main(int argc, char *argv[])
1038 {
1039   char               *command_name, *s;
1040   int                  i;
1041 #ifndef WIN32
1042   int                  opt;
1043   extern char         *optarg;
1044 #endif
1045   char                *pf_path;
1046   int                 pf_open_errno = 0;
1047   int                 err;
1048   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
1049                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
1050                       *tv_scrollw, *filter_bt, *filter_te;
1051   GtkStyle            *pl_style;
1052   GtkAccelGroup       *accel;
1053   GtkWidget           *packet_sw;
1054   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1055   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1056   dfilter             *rfcode = NULL;
1057   gboolean             rfilter_parse_failed = FALSE;
1058   e_prefs             *prefs;
1059   gchar              **col_title;
1060
1061   ethereal_path = argv[0];
1062
1063   /* If invoked as "ethereal-dump-fields", we dump out a glossary of
1064      display filter symbols; we specify that by checking the name,
1065      so that we can do so before looking at the argument list -
1066      we don't want to look at the argument list, because we don't
1067      want to call "gtk_init()", because we don't want to have to
1068      do any X stuff just to do a build. */
1069   command_name = strrchr(ethereal_path, '/');
1070   if (command_name == NULL)
1071     command_name = ethereal_path;
1072   else
1073     command_name++;
1074   if (strcmp(command_name, "ethereal-dump-fields") == 0) {
1075     ethereal_proto_init();
1076     proto_registrar_dump();
1077     exit(0);
1078   }
1079   
1080   /* Let GTK get its args */
1081   gtk_init (&argc, &argv);
1082   
1083   prefs = read_prefs(&pf_path);
1084   if (pf_path != NULL) {
1085     /* The preferences file exists, but couldn't be opened; "pf_path" is
1086        its pathname.  Remember "errno", as that says why the attempt
1087        failed. */
1088     pf_open_errno = errno;
1089   }
1090
1091   /* Initialize the capture file struct */
1092   cf.plist              = NULL;
1093   cf.plist_end          = NULL;
1094   cf.wth                = NULL;
1095   cf.fh                 = NULL;
1096   cf.rfcode             = NULL;
1097   cf.dfilter            = NULL;
1098   cf.dfcode             = dfilter_new();
1099 #ifdef HAVE_LIBPCAP
1100   cf.cfilter            = NULL;
1101 #endif
1102   cf.iface              = NULL;
1103   cf.save_file          = NULL;
1104   cf.save_file_fd       = -1;
1105   cf.user_saved         = 0;
1106   cf.snap               = MAX_PACKET_SIZE;
1107   cf.count              = 0;
1108   cf.cinfo.num_cols     = prefs->num_cols;
1109   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1110   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1111   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1112   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1113
1114   /* Assemble the compile-time options */
1115   snprintf(comp_info_str, 256,
1116 #ifdef GTK_MAJOR_VERSION
1117     "GTK+ %d.%d.%d, %s libpcap", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1118     GTK_MICRO_VERSION,
1119 #else
1120     "GTK+ (version unknown), %s libpcap",
1121 #endif
1122
1123 #ifdef HAVE_LIBPCAP
1124    "with"
1125 #else
1126    "without"
1127 #endif
1128    );
1129
1130 #ifndef WIN32
1131   /* Now get our args */
1132   while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1133     switch (opt) {
1134       case 'b':        /* Bold font */
1135         bold_font = g_strdup(optarg);
1136         break;
1137       case 'B':        /* Byte view pane height */
1138         bv_size = atoi(optarg);
1139         break;
1140       case 'c':        /* Capture xxx packets */
1141         cf.count = atoi(optarg);
1142         break;
1143 #ifdef HAVE_LIBPCAP
1144       case 'f':
1145         cf.cfilter = g_strdup(optarg);
1146         break;
1147       case 'F':        /* Fork to capture */
1148         fork_mode = 1;
1149         break;
1150 #endif
1151       case 'h':        /* Print help and exit */
1152         print_usage();
1153         exit(0);
1154         break;
1155       case 'i':        /* Use interface xxx */
1156         cf.iface = g_strdup(optarg);
1157         break;
1158       case 'm':        /* Medium font */
1159         medium_font = g_strdup(optarg);
1160         break;
1161       case 'n':        /* No name resolution */
1162         g_resolving_actif = 0;
1163         break;
1164 #ifdef HAVE_LIBPCAP
1165       case 'k':        /* Start capture immediately */
1166         start_capture = 1;
1167         break;
1168 #endif
1169       case 'P':        /* Packet list pane height */
1170         pl_size = atoi(optarg);
1171         break;
1172 #ifdef HAVE_LIBPCAP
1173       case 'Q':        /* Quit after capture (just capture to file) */
1174         quit_after_cap = 1;
1175         start_capture = 1;  /*** -Q implies -k !! ***/
1176         break;
1177 #endif
1178       case 'r':        /* Read capture file xxx */
1179         cf_name = g_strdup(optarg);
1180         break;
1181       case 'R':        /* Read file filter */
1182         rfilter = optarg;
1183         break;
1184 #ifdef HAVE_LIBPCAP
1185       case 's':        /* Set the snapshot (capture) length */
1186         cf.snap = atoi(optarg);
1187         break;
1188       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1189         sync_mode = 1;
1190         fork_mode = 1; /* -S implies -F */
1191         break;
1192 #endif
1193       case 't':        /* Time stamp type */
1194         if (strcmp(optarg, "r") == 0)
1195           timestamp_type = RELATIVE;
1196         else if (strcmp(optarg, "a") == 0)
1197           timestamp_type = ABSOLUTE;
1198         else if (strcmp(optarg, "d") == 0)
1199           timestamp_type = DELTA;
1200         else {
1201           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1202             optarg);
1203           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1204           fprintf(stderr, "or \"d\" for delta.\n");
1205           exit(1);
1206         }
1207         break;
1208       case 'T':        /* Tree view pane height */
1209         tv_size = atoi(optarg);
1210         break;
1211       case 'v':        /* Show version and exit */
1212         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1213         exit(0);
1214         break;
1215 #ifdef HAVE_LIBPCAP
1216       case 'w':        /* Write to capture file xxx */
1217         cf.save_file = g_strdup(optarg);
1218         break;
1219       case 'W':        /* Write to capture file FD xxx */
1220         cf.save_file_fd = atoi(optarg);
1221         break;
1222 #endif
1223     }
1224   }
1225 #endif
1226
1227   if (start_capture) {
1228     if (cf.iface == NULL) {
1229       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1230       exit(1);
1231     }
1232     if (cf.save_file == NULL) {
1233       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-w\" flag\n");
1234       exit(1);
1235     }
1236     if (fork_mode) {
1237       if (cf.save_file_fd == -1) {
1238         fprintf(stderr, "ethereal: \"-k\" flag was specified with \"-%c\" flag but without \"-W\" flag\n",
1239             (sync_mode ? 'S' : 'F'));
1240         exit(1);
1241       }
1242     }
1243   }
1244
1245 #ifdef HAVE_LIBPCAP
1246   if (sync_mode)
1247     signal(SIGUSR2, sigusr2_handler);
1248 #endif
1249
1250   /* Build the column format array */  
1251   col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1252   
1253   for (i = 0; i < cf.cinfo.num_cols; i++) {
1254     cf.cinfo.col_fmt[i] = get_column_format(i);
1255     col_title[i] = g_strdup(get_column_title(i));
1256     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1257       NUM_COL_FMTS);
1258     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1259     cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1260   }
1261
1262   if (cf.snap < 1)
1263     cf.snap = MAX_PACKET_SIZE;
1264   else if (cf.snap < MIN_PACKET_SIZE)
1265     cf.snap = MIN_PACKET_SIZE;
1266   
1267   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1268   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1269   gtk_rc_parse(rc_file);
1270
1271   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1272     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1273     exit(1);
1274   }
1275
1276   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1277     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1278     exit(1);
1279   }
1280
1281   /* Main window */  
1282   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1283   gtk_widget_set_name(window, "main window");
1284   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
1285     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1286   gtk_signal_connect(GTK_OBJECT(window), "destroy", 
1287     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1288   gtk_signal_connect(GTK_OBJECT (window), "realize",
1289     GTK_SIGNAL_FUNC(main_realize_cb), NULL);
1290   gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
1291   gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
1292   gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
1293
1294   /* Container for menu bar, paned windows and progress/info box */
1295   main_vbox = gtk_vbox_new(FALSE, 1);
1296   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1297   gtk_container_add(GTK_CONTAINER(window), main_vbox);
1298   gtk_widget_show(main_vbox);
1299
1300   /* Menu bar */
1301   get_main_menu(&menubar, &accel);
1302   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
1303   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1304   gtk_widget_show(menubar);
1305
1306   /* Panes for the packet list, tree, and byte view */
1307   u_pane = gtk_vpaned_new();
1308   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1309   l_pane = gtk_vpaned_new();
1310   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1311   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1312   gtk_widget_show(u_pane);
1313   gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
1314   gtk_widget_show(l_pane);
1315
1316   /* Packet list */
1317   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, col_title);
1318   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1319   packet_sw = gtk_scrolled_window_new(NULL, NULL);
1320   gtk_widget_show(packet_sw);
1321   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
1322   pl_style = gtk_style_new();
1323   gdk_font_unref(pl_style->font);
1324   pl_style->font = m_r_font;
1325   gtk_widget_set_style(packet_list, pl_style);
1326   gtk_widget_set_name(packet_list, "packet list");
1327   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1328     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1329   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1330     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1331   for (i = 0; i < cf.cinfo.num_cols; i++) {
1332     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1333       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1334
1335     /* Right-justify the packet number column. */
1336     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1337       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1338         GTK_JUSTIFY_RIGHT);
1339
1340     /* Save static column sizes to use during a "-S" capture, so that
1341        the columns don't resize during a live capture. */
1342     cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1343                                                 pl_style->font);
1344   }
1345   gtk_widget_set_usize(packet_list, -1, pl_size);
1346   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
1347   gtk_widget_show(packet_list);
1348   
1349   /* Tree view */
1350   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1351   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1352     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1353   gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
1354   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1355   gtk_widget_show(tv_scrollw);
1356   
1357   tree_view = gtk_tree_new();
1358   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
1359                   tree_view);
1360   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
1361
1362   /* XXX - what's the difference between the next two lines? */
1363   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
1364   gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
1365
1366   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
1367     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
1368   gtk_widget_show(tree_view);
1369
1370   item_style = gtk_style_new();
1371   gdk_font_unref(item_style->font);
1372   item_style->font = m_r_font;
1373
1374   /* Byte view */
1375   bv_table = gtk_table_new (2, 2, FALSE);
1376   gtk_paned_add2(GTK_PANED(l_pane), bv_table);
1377   gtk_widget_set_usize(bv_table, -1, bv_size);
1378   gtk_widget_show(bv_table);
1379
1380   byte_view = gtk_text_new(NULL, NULL);
1381   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1382   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1383   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
1384     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1385   gtk_widget_show(byte_view);
1386
1387   bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
1388   gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
1389     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1390   gtk_widget_show (bv_hscroll);
1391
1392   bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1393   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
1394     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1395   gtk_widget_show(bv_vscroll);
1396   
1397   /* Progress/filter/info box */
1398   stat_hbox = gtk_hbox_new(FALSE, 1);
1399   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1400   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1401   gtk_widget_show(stat_hbox);
1402
1403   prog_bar = gtk_progress_bar_new();  
1404   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1405   gtk_widget_show(prog_bar);
1406
1407   filter_bt = gtk_button_new_with_label("Filter:");
1408   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1409     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
1410   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1411   gtk_widget_show(filter_bt);
1412   
1413   filter_te = gtk_entry_new();
1414   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1415   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
1416   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1417     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1418   gtk_widget_show(filter_te);
1419
1420   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1421    * of any widget that ends up calling a callback which needs
1422    * that text entry pointer */
1423   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1424   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1425   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY,
1426     filter_te);
1427
1428   info_bar = gtk_statusbar_new();
1429   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1430   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1431   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1432   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1433   gtk_widget_show(info_bar);
1434
1435 /* 
1436    Hmmm should we do it here
1437 */
1438
1439   ethereal_proto_init();   /* Init anything that needs initializing */
1440
1441   gtk_widget_show(window);
1442
1443   /* If we were given the name of a capture file, read it in now;
1444      we defer it until now, so that, if we can't open it, and pop
1445      up an alert box, the alert box is more likely to come up on
1446      top of the main window - but before the preference-file-error
1447      alert box, so, if we get one of those, it's more likely to come
1448      up on top of us. */
1449   if (cf_name) {
1450     if (rfilter != NULL) {
1451       rfcode = dfilter_new();
1452       if (dfilter_compile(rfcode, rfilter) != 0) {
1453         simple_dialog(ESD_TYPE_WARN, NULL,
1454             "Unable to parse filter string \"%s\".", rfilter);
1455         dfilter_destroy(rfcode);
1456         rfilter_parse_failed = TRUE;
1457       }
1458     }
1459     if (!rfilter_parse_failed) {
1460       if ((err = open_cap_file(cf_name, &cf)) == 0) {
1461         cf.rfcode = rfcode;
1462         err = read_cap_file(&cf);
1463         s = strrchr(cf_name, '/');
1464         if (s) {
1465           last_open_dir = cf_name;
1466           *s = '\0';
1467         }
1468         set_menu_sensitivity("/File/Save As...", TRUE);
1469       }
1470     }
1471   }
1472
1473   /* If we failed to open the preferences file, pop up an alert box;
1474      we defer it until now, so that the alert box is more likely to
1475      come up on top of the main window. */
1476   if (pf_path != NULL) {
1477       simple_dialog(ESD_TYPE_WARN, NULL,
1478         "Can't open preferences file\n\"%s\": %s.", pf_path,
1479         strerror(pf_open_errno));
1480   }
1481
1482   gtk_main();
1483
1484   exit(0);
1485 }