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