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