Don't pop up the "Can't open preferences file" dialog until *after*
[obnox/wireshark/wip.git] / ethereal.c
1 /* ethereal.c
2  *
3  * $Id: ethereal.c,v 1.37 1999/06/12 07:04:34 guy 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  * - Fix progress/status bar glitches?  (GTK+ bug?)
36  * - Create header parsing routines
37  * - Check fopens, freads, fwrites
38  * - Make byte view scrollbars automatic?
39  * - Make byte view selections more fancy?
40  *
41  */
42
43 #ifdef HAVE_CONFIG_H
44 # include "config.h"
45 #endif
46
47 #include <gtk/gtk.h>
48 #include <pcap.h> /* needed for capture.h */
49
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <errno.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <netinet/in.h>
59 #include <signal.h>
60
61 #ifdef NEED_SNPRINTF_H
62 # ifdef HAVE_STDARG_H
63 #  include <stdarg.h>
64 # else
65 #  include <varargs.h>
66 # endif
67 # include "snprintf.h"
68 #endif
69
70 #include "ethereal.h"
71 #include "packet.h"
72 #include "capture.h"
73 #include "file.h"
74 #include "menu.h"
75 #include "etypes.h"
76 #include "prefs.h"
77 #include "column.h"
78 #include "print.h"
79 #include "resolv.h"
80 #include "follow.h"
81 #include "util.h"
82 #include "gtkpacket.h"
83
84 static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
85 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
86
87 FILE        *data_out_file = NULL;
88 packet_info  pi;
89 capture_file cf;
90 GtkWidget   *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
91             *info_bar;
92 GdkFont     *m_r_font, *m_b_font;
93 guint        main_ctx, file_ctx;
94 frame_data  *fd;
95 gint         start_capture = 0;
96 gchar        comp_info_str[256];
97 gchar       *ethereal_path = NULL;
98 gchar       *medium_font = MONO_MEDIUM_FONT;
99 gchar       *bold_font = MONO_BOLD_FONT;
100
101 ts_type timestamp_type = RELATIVE;
102
103 GtkStyle *item_style;
104
105 int sync_mode;  /* allow sync */
106 int sync_pipe[2]; /* used to sync father */
107 int fork_mode;  /* fork a child to do the capture */
108 int sigusr2_received = 0;
109 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
110
111 #define E_DFILTER_TE_KEY "display_filter_te"
112
113 /* About Ethereal window */
114 void
115 about_ethereal( GtkWidget *w, gpointer data ) {
116   simple_dialog(ESD_TYPE_INFO, NULL,
117                 "GNU Ethereal - network protocol analyzer\n"
118                 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
119                 "Compiled with %s\n\n"
120                 "Contributors:\n"
121
122                 "Gilbert Ramirez          <gramirez@tivoli.com>\n"
123                 "Hannes R. Boehm          <hannes@boehm.org>\n"
124                 "Mike Hall                <mlh@io.com>\n"
125                 "Bobo Rajec               <bobo@bsp-consulting.sk>\n"
126                 "Laurent Deniel           <deniel@worldnet.fr>\n"
127                 "Don Lafontaine           <lafont02@cn.ca>\n"
128                 "Guy Harris               <guy@netapp.com>\n"
129                 "Simon Wilkinson          <sxw@dcs.ed.ac.uk>\n"
130                 "Joerg Mayer              <jmayer@telemation.de>\n"
131                 "Martin Maciaszek         <fastjack@i-s-o.net>\n"
132                 "Didier Jorand            <Didier.Jorand@alcatel.fr>\n"
133                 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
134                 "Richard Sharpe           <sharpe@ns.aus.com>\n"
135                 "John McDermott           <jjm@jkintl.com>\n"
136                 "Jeff Jahr                <jjahr@shastanets.com>\n"
137                 "Brad Robel-Forrest       <bradr@watchguard.com>\n"
138                 "Ashok Narayanan          <ashokn@cisco.com>\n"
139
140                 "\nSee http://ethereal.zing.org for more information",
141                 VERSION, comp_info_str);
142 }
143
144 /* Things to do when the OK button is pressed */
145 void
146 file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
147   gchar     *cf_name;
148   int        err;
149
150   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
151   gtk_widget_hide(GTK_WIDGET (fs));
152   gtk_widget_destroy(GTK_WIDGET (fs));
153
154   /* this depends upon load_cap_file removing the filename from
155    * cf_name, leaving only the path to the directory. */
156   if ((err = load_cap_file(cf_name, &cf)) == 0)
157     chdir(cf_name);
158   g_free(cf_name);
159 #ifdef USE_ITEM
160     set_menu_sensitivity("/File/Save", FALSE);
161     set_menu_sensitivity("/File/Save as", TRUE);
162 #else
163     set_menu_sensitivity("<Main>/File/Save", FALSE);
164     set_menu_sensitivity("<Main>/File/Save as", TRUE);
165 #endif
166 }
167
168 /* Update the progress bar */
169 gint
170 file_progress_cb(gpointer p) {
171   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
172     (gfloat) ftell(cf.fh) / (gfloat) cf.f_len);
173   return TRUE;
174 }
175
176 /* Follow a TCP stream */
177 void
178 follow_stream_cb( GtkWidget *w, gpointer data ) {
179   char filename1[128];
180   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
181   GtkWidget *filter_te = NULL;
182
183   if (w)
184         filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
185
186   if( pi.ipproto == 6 ) {
187     /* we got tcp so we can follow */
188     /* check to see if we are using a filter */
189     if( cf.dfilter != NULL ) {
190       /* get rid of this one */
191       g_free( cf.dfilter );
192       cf.dfilter = NULL;
193     }
194     /* create a new one and set the display filter entry accordingly */
195     cf.dfilter = build_follow_filter( &pi );
196     if (filter_te)
197             gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
198     /* reload so it goes in effect. Also we set data_out_file which 
199        tells the tcp code to output the data */
200     close_cap_file( &cf, info_bar, file_ctx);
201     strcpy( filename1, tmpnam(NULL) );
202     data_out_file = fopen( filename1, "a" );
203     if( data_out_file == NULL ) {
204       fprintf( stderr, "Could not open tmp file %s\n", filename1 );
205     }
206     reset_tcp_reassembly();
207     load_cap_file( cf.filename, &cf );
208     /* the data_out_file should now be full of the streams information */
209     fclose( data_out_file );
210     /* the filename1 file now has all the text that was in the session */
211     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
212     gtk_widget_set_name( streamwindow, "TCP stream window" );
213     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
214                         NULL, "WM destroy" );
215     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
216                         NULL, "WM destroy" );
217     if( incomplete_tcp_stream ) {
218       gtk_window_set_title( GTK_WINDOW(streamwindow), 
219                             "Contents of TCP stream (incomplete)" );
220     } else {
221       gtk_window_set_title( GTK_WINDOW(streamwindow),
222                             "Contents of TCP stream" );
223     }
224     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
225     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
226     /* setup the container */
227     box = gtk_vbox_new( FALSE, 0 );
228     gtk_container_add( GTK_CONTAINER(streamwindow), box );
229     gtk_widget_show( box );
230     /* set up the table we attach to */
231     table = gtk_table_new( 1, 2, FALSE );
232     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
233     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
234     gtk_widget_show( table );
235     /* create a text box */
236     text = gtk_text_new( NULL, NULL );
237     gtk_text_set_editable( GTK_TEXT(text), FALSE);
238     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
239                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
240                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
241     gtk_widget_show(text);
242     /* create the scrollbar */
243     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
244     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
245                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
246     gtk_widget_show( vscrollbar );
247     gtk_widget_realize( text );
248     /* stop the updates while we fill the text box */
249     gtk_text_freeze( GTK_TEXT(text) );
250     data_out_file = NULL;
251     data_out_file = fopen( filename1, "r" );
252     if( data_out_file ) {
253       char buffer[1024];
254       int nchars;
255       while( 1 ) {
256         nchars = fread( buffer, 1, 1024, data_out_file );
257         gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
258         if( nchars < 1024 ) {
259           break;
260         }
261       }
262       fclose( data_out_file );
263       unlink( filename1 );
264     }
265     gtk_text_thaw( GTK_TEXT(text) );
266     data_out_file = NULL;
267     gtk_widget_show( streamwindow );
268     if( cf.dfilter != NULL ) {
269       g_free( cf.dfilter );
270       cf.dfilter = NULL;
271     }
272   } else {
273     simple_dialog(ESD_TYPE_WARN, NULL,
274       "Error following stream.  Please make\n"
275       "sure you have a TCP packet selected.");
276   }
277 }
278
279 /* Open a file */
280 void
281 file_open_cmd_cb(GtkWidget *w, gpointer data) {
282   file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
283   
284   /* Connect the ok_button to file_ok_sel_cb function and pass along the
285      pointer to the filter entry */
286   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
287     "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel );
288
289   /* Gilbert --- I added this if statement. Is this right? */
290   if (w)
291   gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
292     E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
293
294   /* Connect the cancel_button to destroy the widget */
295   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
296     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
297     gtk_widget_destroy, GTK_OBJECT (file_sel));
298
299   if( fork_mode && (cf.save_file != NULL) )
300     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
301   else
302     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
303
304   gtk_widget_show(file_sel);
305 }
306
307 /* Close a file */
308 void
309 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
310   close_cap_file(&cf, info_bar, file_ctx);
311 #ifdef USE_ITEM
312   set_menu_sensitivity("/File/Close", FALSE);
313   set_menu_sensitivity("/File/Reload", FALSE);
314 #else
315   set_menu_sensitivity("<Main>/File/Close", FALSE);
316   set_menu_sensitivity("<Main>/File/Reload", FALSE);
317 #endif
318 }
319
320 void
321 file_save_cmd_cb(GtkWidget *w, gpointer data) {
322   file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
323   
324   /* Connect the ok_button to file_ok_sel_cb function and pass along the
325      pointer to the filter entry */
326   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
327     "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
328
329   /* Connect the cancel_button to destroy the widget */
330   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
331     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
332     gtk_widget_destroy, GTK_OBJECT (file_sel));
333
334   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
335
336   gtk_widget_show(file_sel);
337 }
338
339 void
340 file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
341   file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as");
342
343   /* Connect the ok_button to file_ok_sel_cb function and pass along the
344      pointer to the filter entry */
345   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
346     "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
347
348   /* Connect the cancel_button to destroy the widget */
349   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
350     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
351     gtk_widget_destroy, GTK_OBJECT (file_sel));
352
353   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
354   gtk_widget_show(file_sel);
355 }
356
357 static void
358 file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
359         gchar   *cf_name;
360
361         cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
362         gtk_widget_hide(GTK_WIDGET (fs));
363         gtk_widget_destroy(GTK_WIDGET (fs));
364
365         if (!file_mv(cf.save_file, cf_name))
366                 return;
367         g_free(cf.save_file);
368         cf.save_file = g_strdup(cf_name);
369         cf.user_saved = 1;
370         load_cap_file(cf_name, &cf);
371
372 #ifdef USE_ITEM
373         set_menu_sensitivity("/File/Save", FALSE);
374         set_menu_sensitivity("/File/Save as", TRUE);
375 #else
376         set_menu_sensitivity("<Main>/File/Save", FALSE);
377         set_menu_sensitivity("<Main>/File/Save as", TRUE);
378 #endif
379 }
380
381 static void
382 file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
383         gchar   *cf_name;
384
385         cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
386         gtk_widget_hide(GTK_WIDGET (fs));
387         gtk_widget_destroy(GTK_WIDGET (fs));
388
389         if (!file_cp(cf.save_file, cf_name))
390                 return;
391         g_free(cf.save_file);
392         cf.save_file = g_strdup(cf_name);
393         cf.user_saved = 1;
394         load_cap_file(cf_name, &cf);
395
396 #ifdef USE_ITEM
397         set_menu_sensitivity("/File/Save", FALSE);
398         set_menu_sensitivity("/File/Save as", TRUE);
399 #else
400         set_menu_sensitivity("<Main>/File/Save", FALSE);
401         set_menu_sensitivity("<Main>/File/Save as", TRUE);
402 #endif
403 }
404
405 /* Reload a file using the current display filter */
406 void
407 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
408   /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
409   GtkWidget *filter_te;
410
411   filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
412
413   if (cf.dfilter) g_free(cf.dfilter);
414   cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
415   load_cap_file(cf.filename, &cf);
416 }
417
418 /* Print a packet */
419 void
420 file_print_cmd_cb(GtkWidget *widget, gpointer data) {
421     print_tree(cf.pd, fd, GTK_TREE(tree_view));
422 }
423
424 /* What to do when a list item is selected/unselected */
425 void
426 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
427   GList      *l;
428
429   if (!sync_mode) {
430 #ifdef WITH_WIRETAP
431   if (cf.wth) return; 
432 #else
433   if (cf.pfh) return;
434 #endif
435   }
436   blank_packetinfo();
437   gtk_text_freeze(GTK_TEXT(byte_view));
438   gtk_text_set_point(GTK_TEXT(byte_view), 0);
439   gtk_text_forward_delete(GTK_TEXT(byte_view),
440     gtk_text_get_length(GTK_TEXT(byte_view)));
441   l = g_list_nth(cf.plist_first, row);
442   if (l) {
443     fd = (frame_data *) l->data;
444     fseek(cf.fh, fd->file_off, SEEK_SET);
445     fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh);
446     dissect_packet(cf.pd, fd, (proto_tree*)tree_view);
447     packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1);
448   }
449   gtk_text_thaw(GTK_TEXT(byte_view));
450 }
451
452 void
453 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
454   gtk_text_freeze(GTK_TEXT(byte_view));
455   gtk_text_set_point(GTK_TEXT(byte_view), 0);
456   gtk_text_forward_delete(GTK_TEXT(byte_view),
457     gtk_text_get_length(GTK_TEXT(byte_view)));
458   gtk_text_thaw(GTK_TEXT(byte_view));
459   gtk_tree_clear_items(GTK_TREE(tree_view), 0,
460     g_list_length(GTK_TREE(tree_view)->children));
461 }
462
463 void
464 tree_view_cb(GtkWidget *w) {
465   gint       start = -1, len = -1;
466
467   if (GTK_TREE(w)->selection) {
468     start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
469       E_TREEINFO_START_KEY);
470     len   = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
471       E_TREEINFO_LEN_KEY);
472   }
473
474   gtk_text_freeze(GTK_TEXT(byte_view));
475   gtk_text_set_point(GTK_TEXT(byte_view), 0);
476   gtk_text_forward_delete(GTK_TEXT(byte_view),
477     gtk_text_get_length(GTK_TEXT(byte_view)));
478   packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, start, len);
479   gtk_text_thaw(GTK_TEXT(byte_view));
480 }
481
482 void
483 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
484   if (cf.save_file && !cf.user_saved) {
485         unlink(cf.save_file);
486   }
487   gtk_exit(0);
488 }
489
490 void blank_packetinfo() {
491   pi.srcip    = 0;
492   pi.destip   = 0;
493   pi.ipproto  = 0;
494   pi.srcport  = 0;
495   pi.destport = 0;
496 }
497
498 /* Things to do when the OK button is pressed */
499 void
500 main_realize_cb(GtkWidget *w, gpointer data) {
501   gchar  *cf_name = (gchar *) data;
502   int     err;
503   
504   if (cf_name) {
505     err = load_cap_file(cf_name, &cf);
506     cf_name[0] = '\0';
507 #ifdef USE_ITEM
508     set_menu_sensitivity("/File/Save as", TRUE);
509 #else
510     set_menu_sensitivity("<Main>/File/Save as", TRUE);
511 #endif
512   }
513   if (start_capture) {
514     capture();
515     start_capture = 0;
516   }
517 }
518
519 static void 
520 sigusr2_handler(int sig) {
521   sigusr2_received = 1;
522   signal(SIGUSR2, sigusr2_handler);
523 }
524
525 static void
526 ethereal_proto_init(void) {
527
528   init_dissect_udp();
529
530 }
531
532 void 
533 print_usage(void) {
534
535   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
536           VERSION, comp_info_str);
537   fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n",
538           PACKAGE);
539   fprintf(stderr, "         [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n");
540   fprintf(stderr, "         [-P packet list height] [-r infile] [-s snaplen]\n");
541   fprintf(stderr, "         [-t <time stamp format>] [-T tree view height] [-w savefile] \n");
542 }
543
544 /* And now our feature presentation... [ fade to music ] */
545 int
546 main(int argc, char *argv[])
547 {
548   int                  opt, i;
549   extern char         *optarg;
550   char                *pf_path;
551   int                 pf_open_errno = 0;
552   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
553                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
554                       *tv_scrollw, *filter_bt, *filter_te;
555   GtkStyle            *pl_style;
556 #ifdef GTK_HAVE_FEATURES_1_1_0
557   GtkAccelGroup *accel;
558 #else
559   GtkAcceleratorTable *accel;
560 #endif
561
562 #ifdef GTK_HAVE_FEATURES_1_1_4
563   GtkWidget     *packet_sw;
564 #endif
565   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
566   gchar               *rc_file, *cf_name = NULL;
567   e_prefs             *prefs;
568   gint                *col_fmt;
569   gchar              **col_title;
570
571   ethereal_path = argv[0];
572
573   /* Let GTK get its args */
574   gtk_init (&argc, &argv);
575   
576
577   prefs = read_prefs(&pf_path);
578   if (pf_path != NULL) {
579     /* The preferences file exists, but couldn't be opened; "pf_path" is
580        its pathname.  Remember "errno", as that says why the attempt
581        failed. */
582     pf_open_errno = errno;
583   }
584     
585   /* Initialize the capture file struct */
586   cf.plist              = NULL;
587   cf.plist_first        = NULL;
588 #ifdef WITH_WIRETAP
589   cf.wth                = NULL;
590 #else
591   cf.pfh                = NULL;
592 #endif
593   cf.fh                 = NULL;
594   cf.dfilter            = NULL;
595   cf.cfilter            = NULL;
596   cf.iface              = NULL;
597   cf.save_file          = NULL;
598   cf.user_saved         = 0;
599   cf.snap               = MAX_PACKET_SIZE;
600   cf.count              = 0;
601   cf.cinfo.num_cols     = prefs->num_cols;
602   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
603   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
604
605   /* Assemble the compile-time options */
606   snprintf(comp_info_str, 256,
607 #ifdef GTK_MAJOR_VERSION
608     "GTK+ %d.%d.%d and %s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
609     GTK_MICRO_VERSION,
610 #else
611     "GTK+ (version unknown) and %s",
612 #endif
613 #ifdef WITH_WIRETAP
614     "wiretap");
615 #else
616     "libpcap");
617 #endif
618
619   /* Now get our args */
620   while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:Ss:t:T:w:v")) != EOF) {
621     switch (opt) {
622       case 'b':        /* Bold font */
623         bold_font = g_strdup(optarg);
624         break;
625       case 'B':        /* Byte view pane height */
626         bv_size = atoi(optarg);
627         break;
628       case 'c':        /* Capture xxx packets */
629         cf.count = atoi(optarg);
630         break;
631       case 'f':
632         cf.cfilter = g_strdup(optarg);
633         break;
634       case 'F':        /* Fork to capture */
635         fork_mode = 1;
636         break;
637       case 'h':        /* Print help and exit */
638         print_usage();
639         exit(0);
640         break;
641       case 'i':        /* Use interface xxx */
642         cf.iface = g_strdup(optarg);
643         break;
644       case 'm':        /* Medium font */
645         medium_font = g_strdup(optarg);
646         break;
647       case 'n':        /* No name resolution */
648         g_resolving_actif = 0;
649         break;
650       case 'k':        /* Start capture immediately */
651         start_capture = 1;
652         break;
653       case 'P':        /* Packet list pane height */
654         pl_size = atoi(optarg);
655         break;
656       case 'Q':        /* Quit after capture (just capture to file) */
657         quit_after_cap = 1;
658         start_capture = 1;  /*** -Q implies -k !! ***/
659         break;
660       case 'r':        /* Read capture file xxx */
661         cf_name = g_strdup(optarg);
662         break;
663       case 's':        /* Set the snapshot (capture) length */
664         cf.snap = atoi(optarg);
665         break;
666       case 'S':        /* "Sync" mode: used for following file ala tail -f */
667         sync_mode = 1;
668         fork_mode = 1; /* -S implies -F */
669         break;
670       case 't':        /* Time stamp type */
671         if (strcmp(optarg, "r") == 0)
672           timestamp_type = RELATIVE;
673         else if (strcmp(optarg, "a") == 0)
674           timestamp_type = ABSOLUTE;
675         else if (strcmp(optarg, "d") == 0)
676           timestamp_type = DELTA;
677         else {
678           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
679             optarg);
680           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
681           fprintf(stderr, "or \"d\" for delta.\n");
682           exit(1);
683         }
684         break;
685       case 'T':        /* Tree view pane height */
686         tv_size = atoi(optarg);
687         break;
688       case 'v':        /* Show version and exit */
689         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
690         exit(0);
691         break;
692       case 'w':        /* Write capture file xxx */
693         cf.save_file = g_strdup(optarg);
694         break;
695     }
696   }
697
698   if (sync_mode)
699     signal(SIGUSR2, sigusr2_handler);
700
701   /* Build the column format array */  
702   col_fmt   = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
703   col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
704   
705   for (i = 0; i < cf.cinfo.num_cols; i++) {
706     col_fmt[i]   = get_column_format(i);
707     col_title[i] = g_strdup(get_column_title(i));
708     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
709       NUM_COL_FMTS);
710     get_column_format_matches(cf.cinfo.fmt_matx[i], col_fmt[i]);
711     cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
712   }
713
714   if (cf.snap < 1)
715     cf.snap = MAX_PACKET_SIZE;
716   else if (cf.snap < MIN_PACKET_SIZE)
717     cf.snap = MIN_PACKET_SIZE;
718   
719   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
720   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
721   gtk_rc_parse(rc_file);
722
723   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
724     fprintf(stderr, "Error font %s not found (use -m option)\n", medium_font);
725     exit(1);
726   }
727
728   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
729     fprintf(stderr, "Error font %s not found (use -b option)\n", bold_font);
730     exit(1);
731   }
732
733   /* Main window */  
734   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
735   gtk_widget_set_name(window, "main window");
736   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
737     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
738   gtk_signal_connect(GTK_OBJECT(window), "destroy", 
739     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
740   gtk_signal_connect(GTK_OBJECT (window), "realize",
741     GTK_SIGNAL_FUNC(main_realize_cb), cf_name);
742   gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
743   gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
744   gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
745
746   /* Container for menu bar, paned windows and progress/info box */
747   main_vbox = gtk_vbox_new(FALSE, 1);
748   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
749   gtk_container_add(GTK_CONTAINER(window), main_vbox);
750   gtk_widget_show(main_vbox);
751
752   /* Menu bar */
753   get_main_menu(&menubar, &accel);
754 #ifdef GTK_HAVE_FEATURES_1_1_0
755   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
756 #else
757   gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
758 #endif
759   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
760   gtk_widget_show(menubar);
761
762   /* Panes for the packet list, tree, and byte view */
763   u_pane = gtk_vpaned_new();
764   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
765   l_pane = gtk_vpaned_new();
766   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
767   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
768   gtk_widget_show(u_pane);
769   gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
770   gtk_widget_show(l_pane);
771
772   /* Packet list */
773   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, col_title);
774   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
775 #ifdef GTK_HAVE_FEATURES_1_1_4
776   packet_sw = gtk_scrolled_window_new(NULL, NULL);
777   gtk_widget_show(packet_sw);
778   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
779 #endif
780   pl_style = gtk_style_new();
781   gdk_font_unref(pl_style->font);
782   pl_style->font = m_r_font;
783   gtk_widget_set_style(packet_list, pl_style);
784   gtk_widget_set_name(packet_list, "packet list");
785   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
786     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
787   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
788     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
789   for (i = 0; i < cf.cinfo.num_cols; i++) {
790     gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
791       get_column_width(get_column_format(i), pl_style->font));
792     if (col_fmt[i] == COL_NUMBER)
793       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
794         GTK_JUSTIFY_RIGHT);
795   }
796   gtk_widget_set_usize(packet_list, -1, pl_size);
797 #ifdef GTK_HAVE_FEATURES_1_1_4
798   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
799 #else
800   gtk_paned_add1(GTK_PANED(u_pane), packet_list);
801 #endif
802   gtk_widget_show(packet_list);
803   
804   /* Tree view */
805   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
806   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
807     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
808   gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
809   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
810   gtk_widget_show(tv_scrollw);
811   
812   tree_view = gtk_tree_new();
813 #ifdef GTK_HAVE_FEATURES_1_1_4
814   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
815                   tree_view);
816 #else
817   gtk_container_add(GTK_CONTAINER(tv_scrollw), tree_view);
818 #endif
819   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
820   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
821   gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE);
822   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
823     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
824   gtk_widget_show(tree_view);
825
826   item_style = gtk_style_new();
827   gdk_font_unref(item_style->font);
828   item_style->font = m_r_font;
829
830   /* Byte view */
831   bv_table = gtk_table_new (2, 2, FALSE);
832   gtk_paned_add2(GTK_PANED(l_pane), bv_table);
833   gtk_widget_set_usize(bv_table, -1, bv_size);
834   gtk_widget_show(bv_table);
835
836   byte_view = gtk_text_new(NULL, NULL);
837   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
838   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
839   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
840     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
841   gtk_widget_show(byte_view);
842
843   bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
844   gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
845     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
846   gtk_widget_show (bv_hscroll);
847
848   bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
849   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
850     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
851   gtk_widget_show(bv_vscroll);
852   
853   /* Progress/filter/info box */
854   stat_hbox = gtk_hbox_new(FALSE, 1);
855   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
856   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
857   gtk_widget_show(stat_hbox);
858
859   prog_bar = gtk_progress_bar_new();  
860   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
861   gtk_widget_show(prog_bar);
862
863   filter_bt = gtk_button_new_with_label("Filter:");
864   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
865     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
866   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
867   gtk_widget_show(filter_bt);
868   
869   filter_te = gtk_entry_new();
870   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
871   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
872   gtk_widget_show(filter_te);
873
874 #ifdef USE_ITEM
875   set_menu_object_data("/File/Open", E_DFILTER_TE_KEY, filter_te);
876   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
877   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
878     filter_te);
879 #else
880   set_menu_object_data("<Main>/File/Open", E_DFILTER_TE_KEY, filter_te);
881   set_menu_object_data("<Main>/File/Reload", E_DFILTER_TE_KEY, filter_te);
882   set_menu_object_data("<Main>/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
883     filter_te);
884 #endif
885   info_bar = gtk_statusbar_new();
886   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
887   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
888   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
889   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
890   gtk_widget_show(info_bar);
891
892 /* 
893    Hmmm should we do it here
894 */
895
896   ethereal_proto_init();   /* Init anything that needs initializing */
897
898   gtk_widget_show(window);
899
900   /* If we failed to open the preferences file, pop up an alert box;
901      we defer it until now, so that the alert box is more likely to
902      come up on top of the main window. */
903   if (pf_path != NULL) {
904       simple_dialog(ESD_TYPE_WARN, NULL,
905         "Can't open preferences file\n\"%s\": %s.", pf_path,
906         strerror(pf_open_errno));
907   }
908
909   gtk_main();
910
911   exit(0);
912 }