5fbbea695870d7ff779a056e2ee05f09640886c1
[obnox/wireshark/wip.git] / ethereal.c
1 /* ethereal.c
2  *
3  * $Id: ethereal.c,v 1.107 1999/08/25 22:19:55 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 print_usage(void) {
1013
1014   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
1015           VERSION, comp_info_str);
1016   fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n",
1017           PACKAGE);
1018   fprintf(stderr, "         [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n");
1019   fprintf(stderr, "         [-P packet list height] [-r infile] [-s snaplen]\n");
1020   fprintf(stderr, "         [-t <time stamp format>] [-T tree view height] [-w savefile] \n");
1021 }
1022
1023 /* And now our feature presentation... [ fade to music ] */
1024 int
1025 main(int argc, char *argv[])
1026 {
1027   char               *command_name, *s;
1028   int                  i;
1029 #ifndef WIN32
1030   int                  opt;
1031   extern char         *optarg;
1032 #endif
1033   char                *pf_path;
1034   int                 pf_open_errno = 0;
1035   int                 err;
1036   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
1037                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
1038                       *tv_scrollw, *filter_bt, *filter_te;
1039   GtkStyle            *pl_style;
1040   GtkAccelGroup       *accel;
1041   GtkWidget           *packet_sw;
1042   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1043   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1044   dfilter             *rfcode = NULL;
1045   gboolean             rfilter_parse_failed = FALSE;
1046   e_prefs             *prefs;
1047   gchar              **col_title;
1048
1049   ethereal_path = argv[0];
1050
1051   /* If invoked as "ethereal-dump-fields", we dump out a glossary of
1052      display filter symbols; we specify that by checking the name,
1053      so that we can do so before looking at the argument list -
1054      we don't want to look at the argument list, because we don't
1055      want to call "gtk_init()", because we don't want to have to
1056      do any X stuff just to do a build. */
1057   command_name = strrchr(ethereal_path, '/');
1058   if (command_name == NULL)
1059     command_name = ethereal_path;
1060   else
1061     command_name++;
1062   if (strcmp(command_name, "ethereal-dump-fields") == 0) {
1063     ethereal_proto_init();
1064     proto_registrar_dump();
1065     exit(0);
1066   }
1067   
1068   /* Let GTK get its args */
1069   gtk_init (&argc, &argv);
1070   
1071   prefs = read_prefs(&pf_path);
1072   if (pf_path != NULL) {
1073     /* The preferences file exists, but couldn't be opened; "pf_path" is
1074        its pathname.  Remember "errno", as that says why the attempt
1075        failed. */
1076     pf_open_errno = errno;
1077   }
1078
1079   /* Initialize the capture file struct */
1080   cf.plist              = NULL;
1081   cf.plist_end          = NULL;
1082   cf.wth                = NULL;
1083   cf.fh                 = NULL;
1084   cf.rfcode             = NULL;
1085   cf.dfilter            = NULL;
1086   cf.dfcode             = dfilter_new();
1087 #ifdef HAVE_LIBPCAP
1088   cf.cfilter            = NULL;
1089 #endif
1090   cf.iface              = NULL;
1091   cf.save_file          = NULL;
1092   cf.save_file_fd       = -1;
1093   cf.user_saved         = 0;
1094   cf.snap               = WTAP_MAX_PACKET_SIZE;
1095   cf.count              = 0;
1096   cf.cinfo.num_cols     = prefs->num_cols;
1097   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1098   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1099   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1100   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1101
1102   /* Assemble the compile-time options */
1103   snprintf(comp_info_str, 256,
1104 #ifdef GTK_MAJOR_VERSION
1105     "GTK+ %d.%d.%d, %s libpcap", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1106     GTK_MICRO_VERSION,
1107 #else
1108     "GTK+ (version unknown), %s libpcap",
1109 #endif
1110
1111 #ifdef HAVE_LIBPCAP
1112    "with"
1113 #else
1114    "without"
1115 #endif
1116    );
1117
1118 #ifndef WIN32
1119   /* Now get our args */
1120   while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1121     switch (opt) {
1122       case 'b':        /* Bold font */
1123         bold_font = g_strdup(optarg);
1124         break;
1125       case 'B':        /* Byte view pane height */
1126         bv_size = atoi(optarg);
1127         break;
1128       case 'c':        /* Capture xxx packets */
1129         cf.count = atoi(optarg);
1130         break;
1131 #ifdef HAVE_LIBPCAP
1132       case 'f':
1133         cf.cfilter = g_strdup(optarg);
1134         break;
1135       case 'F':        /* Fork to capture */
1136         fork_mode = 1;
1137         break;
1138 #endif
1139       case 'h':        /* Print help and exit */
1140         print_usage();
1141         exit(0);
1142         break;
1143       case 'i':        /* Use interface xxx */
1144         cf.iface = g_strdup(optarg);
1145         break;
1146       case 'm':        /* Medium font */
1147         medium_font = g_strdup(optarg);
1148         break;
1149       case 'n':        /* No name resolution */
1150         g_resolving_actif = 0;
1151         break;
1152 #ifdef HAVE_LIBPCAP
1153       case 'k':        /* Start capture immediately */
1154         start_capture = 1;
1155         break;
1156 #endif
1157       case 'P':        /* Packet list pane height */
1158         pl_size = atoi(optarg);
1159         break;
1160 #ifdef HAVE_LIBPCAP
1161       case 'Q':        /* Quit after capture (just capture to file) */
1162         quit_after_cap = 1;
1163         start_capture = 1;  /*** -Q implies -k !! ***/
1164         break;
1165 #endif
1166       case 'r':        /* Read capture file xxx */
1167         cf_name = g_strdup(optarg);
1168         break;
1169       case 'R':        /* Read file filter */
1170         rfilter = optarg;
1171         break;
1172 #ifdef HAVE_LIBPCAP
1173       case 's':        /* Set the snapshot (capture) length */
1174         cf.snap = atoi(optarg);
1175         break;
1176       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1177         sync_mode = 1;
1178         fork_mode = 1; /* -S implies -F */
1179         break;
1180 #endif
1181       case 't':        /* Time stamp type */
1182         if (strcmp(optarg, "r") == 0)
1183           timestamp_type = RELATIVE;
1184         else if (strcmp(optarg, "a") == 0)
1185           timestamp_type = ABSOLUTE;
1186         else if (strcmp(optarg, "d") == 0)
1187           timestamp_type = DELTA;
1188         else {
1189           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1190             optarg);
1191           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1192           fprintf(stderr, "or \"d\" for delta.\n");
1193           exit(1);
1194         }
1195         break;
1196       case 'T':        /* Tree view pane height */
1197         tv_size = atoi(optarg);
1198         break;
1199       case 'v':        /* Show version and exit */
1200         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1201         exit(0);
1202         break;
1203 #ifdef HAVE_LIBPCAP
1204       case 'w':        /* Write to capture file xxx */
1205         cf.save_file = g_strdup(optarg);
1206         break;
1207       case 'W':        /* Write to capture file FD xxx */
1208         cf.save_file_fd = atoi(optarg);
1209         break;
1210 #endif
1211     }
1212   }
1213 #endif
1214
1215   if (start_capture) {
1216     if (cf.iface == NULL) {
1217       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1218       exit(1);
1219     }
1220     if (cf.save_file == NULL) {
1221       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-w\" flag\n");
1222       exit(1);
1223     }
1224 #ifdef HAVE_LIBPCAP
1225     if (fork_mode) {
1226       if (cf.save_file_fd == -1) {
1227         fprintf(stderr, "ethereal: \"-k\" flag was specified with \"-%c\" flag but without \"-W\" flag\n",
1228             (sync_mode ? 'S' : 'F'));
1229         exit(1);
1230       }
1231     }
1232 #endif
1233   }
1234
1235 #ifdef HAVE_LIBPCAP
1236   if (sync_mode)
1237     signal(SIGUSR2, sigusr2_handler);
1238 #endif
1239
1240   /* Build the column format array */  
1241   col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1242   
1243   for (i = 0; i < cf.cinfo.num_cols; i++) {
1244     cf.cinfo.col_fmt[i] = get_column_format(i);
1245     col_title[i] = g_strdup(get_column_title(i));
1246     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1247       NUM_COL_FMTS);
1248     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1249     cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1250   }
1251
1252   if (cf.snap < 1)
1253     cf.snap = WTAP_MAX_PACKET_SIZE;
1254   else if (cf.snap < MIN_PACKET_SIZE)
1255     cf.snap = MIN_PACKET_SIZE;
1256   
1257   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1258   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1259   gtk_rc_parse(rc_file);
1260
1261   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1262     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1263     exit(1);
1264   }
1265
1266   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1267     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1268     exit(1);
1269   }
1270
1271   /* Main window */  
1272   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1273   gtk_widget_set_name(window, "main window");
1274   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
1275     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1276   gtk_signal_connect(GTK_OBJECT(window), "destroy", 
1277     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1278   gtk_signal_connect(GTK_OBJECT (window), "realize",
1279     GTK_SIGNAL_FUNC(main_realize_cb), NULL);
1280   gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
1281   gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
1282   gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
1283
1284   /* Container for menu bar, paned windows and progress/info box */
1285   main_vbox = gtk_vbox_new(FALSE, 1);
1286   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1287   gtk_container_add(GTK_CONTAINER(window), main_vbox);
1288   gtk_widget_show(main_vbox);
1289
1290   /* Menu bar */
1291   get_main_menu(&menubar, &accel);
1292   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
1293   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1294   gtk_widget_show(menubar);
1295
1296   /* Panes for the packet list, tree, and byte view */
1297   u_pane = gtk_vpaned_new();
1298   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1299   l_pane = gtk_vpaned_new();
1300   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1301   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1302   gtk_widget_show(u_pane);
1303   gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
1304   gtk_widget_show(l_pane);
1305
1306   /* Packet list */
1307   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, col_title);
1308   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1309   packet_sw = gtk_scrolled_window_new(NULL, NULL);
1310   gtk_widget_show(packet_sw);
1311   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
1312   pl_style = gtk_style_new();
1313   gdk_font_unref(pl_style->font);
1314   pl_style->font = m_r_font;
1315   gtk_widget_set_style(packet_list, pl_style);
1316   gtk_widget_set_name(packet_list, "packet list");
1317   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1318     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1319   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1320     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1321   for (i = 0; i < cf.cinfo.num_cols; i++) {
1322     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1323       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1324
1325     /* Right-justify the packet number column. */
1326     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1327       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1328         GTK_JUSTIFY_RIGHT);
1329
1330     /* Save static column sizes to use during a "-S" capture, so that
1331        the columns don't resize during a live capture. */
1332     cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1333                                                 pl_style->font);
1334   }
1335   gtk_widget_set_usize(packet_list, -1, pl_size);
1336   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
1337   gtk_widget_show(packet_list);
1338   
1339   /* Tree view */
1340   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1341   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1342     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1343   gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
1344   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1345   gtk_widget_show(tv_scrollw);
1346   
1347   tree_view = gtk_tree_new();
1348   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
1349                   tree_view);
1350   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
1351
1352   /* XXX - what's the difference between the next two lines? */
1353   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
1354   gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
1355
1356   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
1357     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
1358   gtk_widget_show(tree_view);
1359
1360   item_style = gtk_style_new();
1361   gdk_font_unref(item_style->font);
1362   item_style->font = m_r_font;
1363
1364   /* Byte view */
1365   bv_table = gtk_table_new (2, 2, FALSE);
1366   gtk_paned_add2(GTK_PANED(l_pane), bv_table);
1367   gtk_widget_set_usize(bv_table, -1, bv_size);
1368   gtk_widget_show(bv_table);
1369
1370   byte_view = gtk_text_new(NULL, NULL);
1371   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1372   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1373   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
1374     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1375   gtk_widget_show(byte_view);
1376
1377   bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
1378   gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
1379     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1380   gtk_widget_show (bv_hscroll);
1381
1382   bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1383   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
1384     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1385   gtk_widget_show(bv_vscroll);
1386   
1387   /* Progress/filter/info box */
1388   stat_hbox = gtk_hbox_new(FALSE, 1);
1389   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1390   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1391   gtk_widget_show(stat_hbox);
1392
1393   prog_bar = gtk_progress_bar_new();  
1394   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1395   gtk_widget_show(prog_bar);
1396
1397   filter_bt = gtk_button_new_with_label("Filter:");
1398   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1399     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
1400   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1401   gtk_widget_show(filter_bt);
1402   
1403   filter_te = gtk_entry_new();
1404   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1405   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
1406   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1407     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1408   gtk_widget_show(filter_te);
1409
1410   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1411    * of any widget that ends up calling a callback which needs
1412    * that text entry pointer */
1413   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1414   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1415   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY,
1416     filter_te);
1417
1418   info_bar = gtk_statusbar_new();
1419   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1420   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1421   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1422   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1423   gtk_widget_show(info_bar);
1424
1425 /* 
1426    Hmmm should we do it here
1427 */
1428
1429   ethereal_proto_init();   /* Init anything that needs initializing */
1430
1431   gtk_widget_show(window);
1432
1433   colors_init(&cf);
1434
1435   /* If we were given the name of a capture file, read it in now;
1436      we defer it until now, so that, if we can't open it, and pop
1437      up an alert box, the alert box is more likely to come up on
1438      top of the main window - but before the preference-file-error
1439      alert box, so, if we get one of those, it's more likely to come
1440      up on top of us. */
1441   if (cf_name) {
1442     if (rfilter != NULL) {
1443       rfcode = dfilter_new();
1444       if (dfilter_compile(rfcode, rfilter) != 0) {
1445         simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1446         dfilter_destroy(rfcode);
1447         rfilter_parse_failed = TRUE;
1448       }
1449     }
1450     if (!rfilter_parse_failed) {
1451       if ((err = open_cap_file(cf_name, &cf)) == 0) {
1452         cf.rfcode = rfcode;
1453         err = read_cap_file(&cf);
1454         s = strrchr(cf_name, '/');
1455         if (s) {
1456           last_open_dir = cf_name;
1457           *s = '\0';
1458         }
1459         set_menu_sensitivity("/File/Save As...", TRUE);
1460       }
1461     }
1462   }
1463
1464   /* If we failed to open the preferences file, pop up an alert box;
1465      we defer it until now, so that the alert box is more likely to
1466      come up on top of the main window. */
1467   if (pf_path != NULL) {
1468       simple_dialog(ESD_TYPE_WARN, NULL,
1469         "Could not open preferences file\n\"%s\": %s.", pf_path,
1470         strerror(pf_open_errno));
1471   }
1472
1473   gtk_main();
1474
1475   exit(0);
1476 }