Add an include of "../menu.h" to fix a win32 build break.
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.99 2000/01/25 17:32:52 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  * - Graphs
29  * - Check for end of packet in dissect_* routines.
30  * - Playback window
31  * - Multiple window support
32  * - Add cut/copy/paste
33  * - Create header parsing routines
34  * - Make byte view selections more fancy?
35  *
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <gtk/gtk.h>
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51
52 #include <errno.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55
56 #ifdef HAVE_IO_H
57 #include <io.h> /* open/close on win32 */
58 #endif
59
60 #ifdef HAVE_DIRECT_H
61 #include <direct.h>
62 #endif
63
64 #ifdef HAVE_NETINET_IN_H
65 #include <netinet/in.h>
66 #endif
67
68 #include <signal.h>
69
70 #ifdef NEED_SNPRINTF_H
71 # ifdef HAVE_STDARG_H
72 #  include <stdarg.h>
73 # else
74 #  include <varargs.h>
75 # endif
76 # include "snprintf.h"
77 #endif
78
79 #if defined(HAVE_UCD_SNMP_SNMP_H)
80 #ifdef HAVE_UCD_SNMP_VERSION_H
81 #include <ucd-snmp/version.h>
82 #endif /* HAVE_UCD_SNMP_VERSION_H */
83 #elif defined(HAVE_SNMP_SNMP_H)
84 #ifdef HAVE_SNMP_VERSION_H
85 #include <snmp/version.h>
86 #endif /* HAVE_SNMP_VERSION_H */
87 #endif /* SNMP */
88
89 #ifdef NEED_STRERROR_H
90 #include "strerror.h"
91 #endif
92
93 #include "main.h"
94 #include "timestamp.h"
95 #include "packet.h"
96 #include "capture.h"
97 #include "summary.h"
98 #include "file.h"
99 #include "menu.h"
100 #include "../menu.h"
101 #include "prefs_dlg.h"
102 #include "column.h"
103 #include "print.h"
104 #include "resolv.h"
105 #include "follow.h"
106 #include "util.h"
107 #include "simple_dialog.h"
108 #include "proto_draw.h"
109 #include "dfilter.h"
110 #include "keys.h"
111 #include "gtkglobals.h"
112 #include "plugins.h"
113
114 FILE        *data_out_file = NULL;
115 packet_info  pi;
116 capture_file cf;
117 GtkWidget   *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
118             *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
119 static GtkWidget        *bv_vscroll_left, *bv_vscroll_right;
120 GdkFont     *m_r_font, *m_b_font;
121 guint        main_ctx, file_ctx;
122 gchar        comp_info_str[256];
123 gchar       *ethereal_path = NULL;
124 gchar       *medium_font = MONO_MEDIUM_FONT;
125 gchar       *bold_font = MONO_BOLD_FONT;
126 gchar       *last_open_dir = NULL;
127
128 ts_type timestamp_type = RELATIVE;
129
130 GtkStyle *item_style;
131
132 /* Specifies the field currently selected in the GUI protocol tree */
133 field_info *finfo_selected = NULL;
134
135 static void follow_destroy_cb(GtkWidget *win, gpointer data);
136 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
137 static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
138 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
139 static char* hfinfo_numeric_format(header_field_info *hfinfo);
140 static void create_main_window(gint, gint, gint, e_prefs*);
141
142 /* About Ethereal window */
143 void
144 about_ethereal( GtkWidget *w, gpointer data ) {
145   simple_dialog(ESD_TYPE_INFO, NULL,
146                 "Ethereal - Network Protocol Analyzer\n"
147                 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
148                 "Compiled with %s\n\n"
149
150                 "Check the man page for complete documentation and\n"
151                 "for the list of contributors.\n"
152
153                 "\nSee http://ethereal.zing.org/ for more information.",
154                  comp_info_str);
155 }
156
157 /* Follow the TCP stream, if any, to which the last packet that we called
158    a dissection routine on belongs (this might be the most recently
159    selected packet, or it might be the last packet in the file). */
160 void
161 follow_stream_cb( GtkWidget *w, gpointer data ) {
162   char      filename1[128+1];
163   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
164                 *filter_te;
165   GtkWidget *hbox, *close_bt, *print_bt;
166   GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
167   int        tmp_fd;
168   gchar     *follow_filter;
169
170   if( pi.ipproto == 6 ) {
171     /* we got tcp so we can follow */
172     /* Create a temporary file into which to dump the reassembled data
173        from the TCP stream, and set "data_out_file" to refer to it, so
174        that the TCP code will write to it.
175
176        XXX - it might be nicer to just have the TCP code directly
177        append stuff to the text widget for the TCP stream window,
178        if we can arrange that said window not pop up until we're
179        done. */
180     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
181     if (tmp_fd == -1) {
182       simple_dialog(ESD_TYPE_WARN, NULL,
183         "Could not create temporary file %s: %s", filename1, strerror(errno));
184       return;
185     }
186     data_out_file = fdopen( tmp_fd, "w" );
187     if( data_out_file == NULL ) {
188       simple_dialog(ESD_TYPE_WARN, NULL,
189         "Could not create temporary file %s: %s", filename1, strerror(errno));
190       close(tmp_fd);
191       unlink(filename1);
192       return;
193     }
194
195     /* Create a new filter that matches all packets in the TCP stream,
196        and set the display filter entry accordingly */
197     reset_tcp_reassembly();
198     follow_filter = build_follow_filter( &pi );
199
200     /* set the display filter entry accordingly */
201     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
202     gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
203
204     /* Run the display filter so it goes in effect. */
205     filter_packets(&cf, follow_filter);
206
207     /* the data_out_file should now be full of the streams information */
208     fclose( data_out_file );
209
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
214     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
215                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
216     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
217                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
218                         
219     if( incomplete_tcp_stream ) {
220       gtk_window_set_title( GTK_WINDOW(streamwindow), 
221                             "Contents of TCP stream (incomplete)" );
222     } else {
223       gtk_window_set_title( GTK_WINDOW(streamwindow),
224                             "Contents of TCP stream" );
225     }
226     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
227     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
228
229     /* setup the container */
230     box = gtk_vbox_new( FALSE, 0 );
231     gtk_container_add( GTK_CONTAINER(streamwindow), box );
232     gtk_widget_show( box );
233
234     /* set up the table we attach to */
235     table = gtk_table_new( 1, 2, FALSE );
236     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
237     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
238     gtk_widget_show( table );
239
240     /* create a text box */
241     text = gtk_text_new( NULL, NULL );
242     gtk_text_set_editable( GTK_TEXT(text), FALSE);
243     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
244                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
245                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
246     gtk_widget_show(text);
247
248     /* Create hbox */
249     hbox = gtk_hbox_new( FALSE, 1 );
250     gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
251     gtk_widget_show(hbox);
252
253 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
254 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
255 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
256
257     /* Create Radio Buttons */
258     b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
259     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
260     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
261     gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
262     gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
263                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
264                     GTK_OBJECT(streamwindow));
265     gtk_widget_show(b_ascii);
266
267     b_ebcdic = gtk_radio_button_new_with_label(
268                     gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
269                     "EBCDIC");
270     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
271     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
272     gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
273     gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
274                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
275                     GTK_OBJECT(streamwindow));
276     gtk_widget_show(b_ebcdic);
277
278     b_hexdump = gtk_radio_button_new_with_label(
279                     gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
280                     "Hex. Dump");
281     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
282     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
283     gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
284     gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
285                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
286                     GTK_OBJECT(streamwindow));
287     gtk_widget_show(b_hexdump);
288
289     /* Create Close Button */
290     close_bt = gtk_button_new_with_label("Close");
291     gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
292                     GTK_SIGNAL_FUNC(gtk_widget_destroy),
293                     GTK_OBJECT(streamwindow));
294     gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
295     gtk_widget_show( close_bt );
296
297     /* Create Print Button */
298     print_bt = gtk_button_new_with_label("Print");
299     gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
300                    GTK_SIGNAL_FUNC(follow_print_stream),
301                    GTK_OBJECT(streamwindow));
302     gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
303     gtk_widget_show( print_bt );
304
305     /* create the scrollbar */
306     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
307     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
308                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
309     gtk_widget_show( vscrollbar );
310     gtk_widget_realize( text );
311
312     /* Tuck away the filename and textbox into streamwindow */
313 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
314 #define E_FOLLOW_TEXT_KEY "follow_text_key"
315
316     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
317                     g_strdup(filename1));
318     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
319
320     follow_load_text(text, filename1, 0);
321
322     data_out_file = NULL;
323     gtk_widget_show( streamwindow );
324   } else {
325     simple_dialog(ESD_TYPE_WARN, NULL,
326       "Error following stream.  Please make\n"
327       "sure you have a TCP packet selected.");
328   }
329 }
330
331 /* The destroy call back has the responsibility of
332  * unlinking the temporary file */
333 static void
334 follow_destroy_cb(GtkWidget *win, gpointer data)
335 {
336         char    *filename;
337
338         filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
339                                                 E_FOLLOW_FILENAME_KEY);
340         g_assert(filename);
341
342         unlink(filename);
343         gtk_widget_destroy(win);
344 }
345
346 #define E_FOLLOW_ASCII_TYPE     0
347 #define E_FOLLOW_EBCDIC_TYPE    1
348 #define E_FOLLOW_HEXDUMP_TYPE   2
349
350 /* Handles the ASCII/EBCDIC toggling */
351 static void
352 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
353 {
354         guint8          show_type = E_FOLLOW_ASCII_TYPE;
355         GtkWidget       *b_ascii, *b_ebcdic, *b_hexdump, *text;
356         char            *filename;
357
358         b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
359                                                    E_FOLLOW_ASCII_KEY);
360         b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
361                                                     E_FOLLOW_EBCDIC_KEY);
362         b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
363                                                      E_FOLLOW_HEXDUMP_KEY);
364         text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
365                                                 E_FOLLOW_TEXT_KEY);
366         filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
367                                                 E_FOLLOW_FILENAME_KEY);
368
369         g_assert(b_ascii);
370         g_assert(b_ebcdic);
371         g_assert(b_hexdump);
372         g_assert(text);
373         g_assert(filename);
374
375         if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
376                 show_type = E_FOLLOW_EBCDIC_TYPE;
377         else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
378                 show_type = E_FOLLOW_HEXDUMP_TYPE;
379
380         follow_load_text(text, filename, show_type);
381 }
382
383 #define FLT_BUF_SIZE 1024
384 static void
385 follow_read_stream(char *filename, guint8 show_type,
386    void (*print_line)(char *, int, gboolean, void *), void *arg)
387 {
388   tcp_stream_chunk sc;
389   int bcount;
390   guint32 client_addr = 0;
391   guint16 client_port = 0;
392   gboolean is_server;
393   guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
394   guint16 *global_pos;
395
396   data_out_file = fopen( filename, "r" );
397   if( data_out_file ) {
398     char buffer[FLT_BUF_SIZE];
399     int nchars;
400     while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
401       if (client_addr == 0) {
402         client_addr = sc.src_addr;
403         client_port = sc.src_port;
404       }
405       if (client_addr == sc.src_addr && client_port == sc.src_port) {
406         is_server = FALSE;
407         global_pos = &global_client_pos;
408       }
409       else {
410         is_server = TRUE;
411         global_pos = &global_server_pos;
412       }
413         
414       while (sc.dlen > 0) {
415         bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
416         nchars = fread( buffer, 1, bcount, data_out_file );
417         if (nchars == 0)
418           break;
419         sc.dlen -= bcount;
420         switch (show_type) {
421         case E_FOLLOW_EBCDIC_TYPE:
422                 /* If our native arch is ASCII, call: */
423                 EBCDIC_to_ASCII(buffer, nchars);
424         case E_FOLLOW_ASCII_TYPE:
425                 /* If our native arch is EBCDIC, call:
426                  * ASCII_TO_EBCDIC(buffer, nchars);
427                  */
428                 (*print_line)( buffer, nchars, is_server, arg );
429                 break;
430         case E_FOLLOW_HEXDUMP_TYPE:
431                 current_pos = 0;
432                 while (current_pos < nchars)
433                 {
434                     gchar hexbuf[256];
435                     gchar hexchars[] = "0123456789abcdef";
436                     int i, cur;
437                     /* is_server indentation : put 63 spaces at the begenning
438                      * of the string */
439                     sprintf(hexbuf, is_server ?
440                             "                                 "
441                             "                              %08X  " :
442                             "%08X  ", *global_pos);
443                     cur = strlen(hexbuf);
444                     for (i=0; i < 16 && current_pos+i < nchars; i++) {
445                         hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
446                         hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
447                         if (i == 7) {
448                             hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
449                         }
450                         else if (i != 15)
451                             hexbuf[cur++] = ' ';
452                     }
453                     current_pos += i;
454                     (*global_pos) += i;
455                     hexbuf[cur++] = '\n';
456                     hexbuf[cur] = 0;
457                     (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
458                 }
459                 break;
460         }
461       }
462     }
463     if( ferror( data_out_file ) ) {
464       simple_dialog(ESD_TYPE_WARN, NULL,
465         "Error reading temporary file %s: %s", filename, strerror(errno));
466     }
467     fclose( data_out_file );
468   } else {
469     simple_dialog(ESD_TYPE_WARN, NULL,
470       "Could not open temporary file %s: %s", filename, strerror(errno));
471   }
472 }
473
474 /*
475  * XXX - for text printing, we probably want to wrap lines at 80 characters;
476  * for PostScript printing, we probably want to wrap them at the appropriate
477  * width, and perhaps put some kind of dingbat (to use the technical term)
478  * to indicate a wrapped line, along the lines of what's done when displaying
479  * this in a window, as per Warren Young's suggestion.
480  *
481  * For now, we support only text printing.
482  */
483 static void
484 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
485 {
486   FILE *fh = arg;
487
488   fwrite(buffer, nchars, 1, fh);
489 }
490
491 static void
492 follow_print_stream(GtkWidget *w, gpointer parent_w)
493 {
494        FILE *fh;
495        gboolean to_file;
496        char* print_dest;
497        char* filename;
498        guint8 show_type = E_FOLLOW_ASCII_TYPE;
499        GtkWidget *button;
500
501        switch (prefs.pr_dest) {
502                case PR_DEST_CMD:
503                        print_dest = prefs.pr_cmd;
504                        to_file = FALSE;
505                        break;
506
507                case PR_DEST_FILE:
508                        print_dest = prefs.pr_file;
509                        to_file = TRUE;
510                        break;
511                default: /* "Can't happen" */
512                        simple_dialog(ESD_TYPE_WARN, NULL,
513                                "Couldn't figure out where to send the print "
514                                "job. Check your preferences.");
515                        return;
516        }
517
518        fh = open_print_dest(to_file, print_dest);
519        if (fh == NULL) {
520                switch (to_file) {
521                        case FALSE:
522                                simple_dialog(ESD_TYPE_WARN, NULL,
523                                                "Couldn't run print command %s.", prefs.pr_cmd);
524                                break;
525
526                        case TRUE:
527                                simple_dialog(ESD_TYPE_WARN, NULL, 
528                                                file_write_error_message(errno),
529                                                prefs.pr_file);
530                                break;
531                }
532                return;
533        }
534
535        button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
536                        E_FOLLOW_EBCDIC_KEY);
537        if (GTK_TOGGLE_BUTTON(button)->active)
538                show_type = E_FOLLOW_EBCDIC_TYPE;
539        button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
540                        E_FOLLOW_HEXDUMP_KEY);
541        if (GTK_TOGGLE_BUTTON(button)->active)
542                show_type = E_FOLLOW_HEXDUMP_TYPE;
543
544        filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
545                        E_FOLLOW_FILENAME_KEY);
546
547        if (filename != NULL) {
548                print_preamble(fh, PR_FMT_TEXT);
549                follow_read_stream(filename, show_type, follow_print_text, fh);
550                print_finale(fh, PR_FMT_TEXT);
551                close_print_dest(to_file, fh);
552        }
553        else {
554                simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
555        }
556 }
557
558 static void
559 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
560 {
561   GtkWidget *text = arg;
562
563   if (is_server)
564     gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
565             &prefs.st_server_bg, buffer, nchars );
566   else
567     gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
568             &prefs.st_client_bg, buffer, nchars );
569 }
570
571 static void
572 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
573 {
574   int bytes_already;
575
576   /* Delete any info already in text box */
577   bytes_already = gtk_text_get_length(GTK_TEXT(text));
578   if (bytes_already > 0) {
579     gtk_text_set_point(GTK_TEXT(text), 0);
580     gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
581   }
582
583   /* stop the updates while we fill the text box */
584   gtk_text_freeze( GTK_TEXT(text) );
585   follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
586   gtk_text_thaw( GTK_TEXT(text) );
587 }
588
589 /* Match selected byte pattern */
590 void
591 match_selected_cb(GtkWidget *w, gpointer data)
592 {
593     char                *buf;
594     GtkWidget           *filter_te;
595     char                *ptr, *format, *stringified;
596     int                 i, dfilter_len, abbrev_len;
597     guint8              *c;
598     header_field_info   *hfinfo;
599
600     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
601
602     if (!finfo_selected) {
603         simple_dialog(ESD_TYPE_WARN, NULL,
604                       "Error determining selected bytes.  Please make\n"
605                       "sure you have selected a field within the tree\n"
606                       "view to be matched.");
607         return;
608     }
609
610     hfinfo = finfo_selected->hfinfo;
611     g_assert(hfinfo);
612     abbrev_len = strlen(hfinfo->abbrev);
613
614         switch(hfinfo->type) {
615
616                 case FT_BOOLEAN:
617                         dfilter_len = abbrev_len + 2;
618                         buf = g_malloc0(dfilter_len);
619                         snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
620                                         hfinfo->abbrev);
621                         break;
622
623                 case FT_UINT8:
624                 case FT_UINT16:
625                 case FT_UINT24:
626                 case FT_UINT32:
627                 case FT_INT8:
628                 case FT_INT16:
629                 case FT_INT24:
630                 case FT_INT32:
631                         dfilter_len = abbrev_len + 20;
632                         buf = g_malloc0(dfilter_len);
633                         format = hfinfo_numeric_format(hfinfo);
634                         snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
635                         break;
636
637                 case FT_IPv4:
638                         dfilter_len = abbrev_len + 4 + 15 + 1;
639                         buf = g_malloc0(dfilter_len);
640                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
641                                         ipv4_addr_str(&(finfo_selected->value.ipv4)));
642                         break;
643
644                 case FT_IPXNET:
645                         dfilter_len = abbrev_len + 15;
646                         buf = g_malloc0(dfilter_len);
647                         snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
648                                         finfo_selected->value.numeric);
649                         break;
650
651                 case FT_IPv6:
652                         stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
653                         dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
654                         buf = g_malloc0(dfilter_len);
655                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
656                                         stringified);
657                         break;
658
659                 case FT_DOUBLE:
660                         dfilter_len = abbrev_len + 30;
661                         buf = g_malloc0(dfilter_len);
662                         snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
663                                         finfo_selected->value.floating);
664                         break;
665
666                 case FT_ETHER:
667                         dfilter_len = abbrev_len + 22;
668                         buf = g_malloc0(dfilter_len);
669                         snprintf(buf, dfilter_len, "%s == %s",
670                                         hfinfo->abbrev,
671                                         ether_to_str(finfo_selected->value.ether));
672                         break;
673 #if 0
674
675                 case FT_ABSOLUTE_TIME:
676                 case FT_RELATIVE_TIME:
677                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
678                                 sizeof(struct timeval));
679                         break;
680
681                 case FT_STRING:
682                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
683                         fi->value.string = g_strdup(va_arg(ap, char*));
684                         break;
685
686                 case FT_TEXT_ONLY:
687                         ; /* nothing */
688                         break;
689 #endif
690                 default:
691                     c = cf.pd + finfo_selected->start;
692                     buf = g_malloc0(32 + finfo_selected->length * 3);
693                     ptr = buf;
694
695                     sprintf(ptr, "frame[%d] == ", finfo_selected->start);
696                     ptr = buf+strlen(buf);
697
698                     if (finfo_selected->length == 1) {
699                         sprintf(ptr, "0x%02x", *c++);
700                     }
701                     else {
702                             for (i=0;i<finfo_selected->length; i++) {
703                                 if (i == 0 ) {
704                                         sprintf(ptr, "%02x", *c++);
705                                 }
706                                 else {
707                                         sprintf(ptr, ":%02x", *c++);
708                                 }
709                                 ptr = buf+strlen(buf);
710                             }
711                     }
712                     break;
713         }
714
715     /* create a new one and set the display filter entry accordingly */
716     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
717
718     /* Run the display filter so it goes in effect. */
719     filter_packets(&cf, buf);
720
721     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
722 }
723
724 static char*
725 hfinfo_numeric_format(header_field_info *hfinfo)
726 {
727         char *format = NULL;
728
729         /* Pick the proper format string */
730         switch(hfinfo->display) {
731                 case BASE_DEC:
732                 case BASE_NONE:
733                 case BASE_OCT: /* I'm lazy */
734                 case BASE_BIN: /* I'm lazy */
735                         switch(hfinfo->type) {
736                                 case FT_UINT8:
737                                 case FT_UINT16:
738                                 case FT_UINT24:
739                                 case FT_UINT32:
740                                         format = "%s == %u";
741                                         break;
742                                 case FT_INT8:
743                                 case FT_INT16:
744                                 case FT_INT24:
745                                 case FT_INT32:
746                                         format = "%s == %d";
747                                         break;
748                                 default:
749                                         g_assert_not_reached();
750                                         ;
751                         }
752                         break;
753                 case BASE_HEX:
754                         switch(hfinfo->type) {
755                                 case FT_UINT8:
756                                         format = "%s == 0x%02x";
757                                         break;
758                                 case FT_UINT16:
759                                         format = "%s == 0x%04x";
760                                         break;
761                                 case FT_UINT24:
762                                         format = "%s == 0x%06x";
763                                         break;
764                                 case FT_UINT32:
765                                         format = "%s == 0x%08x";
766                                         break;
767                                 default:
768                                         g_assert_not_reached();
769                                         ;
770                         }
771                         break;
772                 default:
773                         g_assert_not_reached();
774                         ;
775         }
776         return format;
777 }
778
779
780 /* Run the current display filter on the current packet set, and
781    redisplay. */
782 static void
783 filter_activate_cb(GtkWidget *w, gpointer data)
784 {
785   GtkCombo  *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
786   GList     *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
787   GList     *li, *nl = NULL;
788   gboolean   add_filter = TRUE;
789   
790   char *s = gtk_entry_get_text(GTK_ENTRY(w));
791   
792   /* GtkCombos don't let us get at their list contents easily, so we maintain
793      our own filter list, and feed it to gtk_combo_set_popdown_strings when
794      a new filter is added. */
795   if (filter_packets(&cf, g_strdup(s))) {
796     li = g_list_first(filter_list);
797     while (li) {
798       if (li->data && strcmp(s, li->data) == 0)
799         add_filter = FALSE;
800       li = li->next;
801     }
802
803     if (add_filter) {
804       filter_list = g_list_append(filter_list, g_strdup(s));
805       li = g_list_first(filter_list);
806       while (li) {
807         nl = g_list_append(nl, strdup(li->data));
808         li = li->next;
809       }
810       gtk_combo_set_popdown_strings(filter_cm, nl);
811       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
812     }
813   }
814 }
815
816 /* redisplay with no display filter */
817 static void
818 filter_reset_cb(GtkWidget *w, gpointer data)
819 {
820   GtkWidget *filter_te = NULL;
821
822   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
823     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
824   }
825
826   filter_packets(&cf, NULL);
827 }
828
829 /* What to do when a list item is selected/unselected */
830 static void
831 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
832
833 #ifdef HAVE_LIBPCAP
834   if (!sync_mode) {
835 #endif
836     if (cf.wth)
837       return; 
838 #ifdef HAVE_LIBPCAP
839   }
840 #endif
841   blank_packetinfo();
842   select_packet(&cf, row);
843 }
844
845 static void
846 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
847   unselect_packet(&cf);
848 }
849
850 static void
851 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
852 {
853         field_info      *finfo;
854         int             tree_selected_start = -1;
855         int             tree_selected_len = -1;
856
857         g_assert(node);
858         finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
859         if (!finfo) return;
860
861         finfo_selected = finfo;
862         tree_selected_start = finfo->start;
863         tree_selected_len   = finfo->length;
864
865         packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
866                 tree_selected_start, tree_selected_len, cf.current_frame->encoding);
867 }
868
869 static void
870 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
871 {
872         finfo_selected = NULL;
873         packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
874                 -1, -1, cf.current_frame->encoding);
875 }
876
877 void collapse_all_cb(GtkWidget *widget, gpointer data) {
878   if (cf.protocol_tree)
879     collapse_all_tree(cf.protocol_tree, tree_view);
880 }
881
882 void expand_all_cb(GtkWidget *widget, gpointer data) {
883   if (cf.protocol_tree)
884     expand_all_tree(cf.protocol_tree, tree_view);
885 }
886
887 void
888 set_scrollbar_placement(int pos) /* 0=left, 1=right */
889 {
890         if (pos) {
891                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
892                                 GTK_CORNER_TOP_LEFT );
893                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
894                                 GTK_CORNER_TOP_LEFT );
895                 gtk_widget_hide(bv_vscroll_left);
896                 gtk_widget_show(bv_vscroll_right);
897         }
898         else {
899                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
900                                 GTK_CORNER_TOP_RIGHT );
901                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
902                                 GTK_CORNER_TOP_RIGHT );
903                 gtk_widget_hide(bv_vscroll_right);
904                 gtk_widget_show(bv_vscroll_left);
905         }
906 }
907
908 void
909 set_plist_sel_browse(gboolean val)
910 {
911         if (finfo_selected)
912                 unselect_packet(&cf);
913
914         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
915          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
916         if (val) {
917                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
918         }
919         else {
920                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
921         }
922 }
923
924 void
925 set_ptree_sel_browse(gboolean val)
926 {
927         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
928          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
929         if (val) {
930                 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
931         }
932         else {
933                 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
934         }
935 }
936
937 void
938 set_ptree_line_style(gint style)
939 {
940         /* I'm using an assert here since the preferences code limits
941          * the user input, both in the GUI and when reading the preferences file.
942          * If the value is incorrect, it's a program error, not a user-initiated error.
943          */
944         g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
945         gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
946 }
947
948 void
949 set_ptree_expander_style(gint style)
950 {
951         /* I'm using an assert here since the preferences code limits
952          * the user input, both in the GUI and when reading the preferences file.
953          * If the value is incorrect, it's a program error, not a user-initiated error.
954          */
955         g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
956         gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
957 }
958         
959
960 void
961 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
962   /* If we have a capture file open, and it's a temporary file,
963      unlink it. */
964   if (cf.filename != NULL && cf.is_tempfile)
965         unlink(cf.filename);
966   gtk_exit(0);
967 }
968
969 /* call initialization routines at program startup time */
970 static void
971 ethereal_proto_init(void) {
972   init_dissect_rpc();
973   proto_init();
974   init_dissect_udp();
975   dfilter_init();
976 #ifdef HAVE_PLUGINS
977   init_plugins();
978 #endif
979 }
980
981 static void
982 ethereal_proto_cleanup(void) {
983         proto_cleanup();
984         dfilter_cleanup();
985 }
986
987 static void 
988 print_usage(void) {
989
990   fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
991           comp_info_str);
992 #ifdef HAVE_LIBPCAP
993   fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
994           PACKAGE);
995   fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
996   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
997   fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
998   fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
999 #else
1000   fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1001           PACKAGE);
1002   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1003   fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1004   fprintf(stderr, "\t[ -T <tree view height> ]\n");
1005 #endif
1006 }
1007
1008 /* And now our feature presentation... [ fade to music ] */
1009 int
1010 main(int argc, char *argv[])
1011 {
1012 #ifdef HAVE_LIBPCAP
1013   char                *command_name;
1014 #endif
1015   char                *s;
1016   int                  i;
1017 #ifndef WIN32
1018   int                  opt;
1019   extern char         *optarg;
1020   gboolean             arg_error = FALSE;
1021 #endif
1022 #ifdef HAVE_LIBPCAP
1023   extern char          pcap_version[];
1024 #endif
1025   char                *pf_path;
1026   int                  pf_open_errno = 0;
1027   int                  err;
1028 #ifdef HAVE_LIBPCAP
1029   gboolean             start_capture = FALSE;
1030   gchar               *save_file = NULL;
1031   GList               *if_list;
1032   gchar                err_str[PCAP_ERRBUF_SIZE];
1033 #else
1034   gboolean             capture_option_specified = FALSE;
1035 #endif
1036   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1037   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1038   dfilter             *rfcode = NULL;
1039   gboolean             rfilter_parse_failed = FALSE;
1040   e_prefs             *prefs;
1041
1042   ethereal_path = argv[0];
1043
1044 #ifdef HAVE_LIBPCAP
1045   command_name = get_basename(ethereal_path);
1046   /* Set "capture_child" to indicate whether this is going to be a child
1047      process for a "-S" capture. */
1048   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1049 #endif
1050
1051   /* If invoked with the "-G" flag, we dump out a glossary of
1052      display filter symbols.
1053
1054      We must do this before calling "gtk_init()", because "gtk_init()"
1055      tries to open an X display, and we don't want to have to do any X
1056      stuff just to do a build.
1057
1058      Given that we call "gtk_init()" before doing the regular argument
1059      list processing, so that it can handle X and GTK+ arguments and
1060      remove them from the list at which we look, this means we must do
1061      this before doing the regular argument list processing, as well.
1062
1063      This means that:
1064
1065         you must give the "-G" flag as the first flag on the command line;
1066
1067         you must give it as "-G", nothing more, nothing less;
1068
1069         any arguments after the "-G" flag will not be used. */
1070   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1071     ethereal_proto_init();
1072     proto_registrar_dump();
1073     exit(0);
1074   }
1075
1076   /* Let GTK get its args */
1077   gtk_init (&argc, &argv);
1078   
1079   prefs = read_prefs(&pf_path);
1080   if (pf_path != NULL) {
1081     /* The preferences file exists, but couldn't be opened; "pf_path" is
1082        its pathname.  Remember "errno", as that says why the attempt
1083        failed. */
1084     pf_open_errno = errno;
1085   }
1086
1087   /* Initialize the capture file struct */
1088   cf.plist              = NULL;
1089   cf.plist_end          = NULL;
1090   cf.wth                = NULL;
1091   cf.fh                 = NULL;
1092   cf.filename           = NULL;
1093   cf.user_saved         = FALSE;
1094   cf.is_tempfile        = FALSE;
1095   cf.rfcode             = NULL;
1096   cf.dfilter            = NULL;
1097   cf.dfcode             = NULL;
1098 #ifdef HAVE_LIBPCAP
1099   cf.cfilter            = g_strdup(EMPTY_FILTER);
1100 #endif
1101   cf.iface              = NULL;
1102   cf.save_file          = NULL;
1103   cf.save_file_fd       = -1;
1104   cf.snap               = WTAP_MAX_PACKET_SIZE;
1105   cf.count              = 0;
1106   cf.cinfo.num_cols     = prefs->num_cols;
1107   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1108   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1109   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1110   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1111   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1112
1113   /* Assemble the compile-time options */
1114   snprintf(comp_info_str, 256,
1115 #ifdef GTK_MAJOR_VERSION
1116     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1117     GTK_MICRO_VERSION,
1118 #else
1119     "GTK+ (version unknown), %s%s, %s%s, %s%s",
1120 #endif
1121
1122 #ifdef HAVE_LIBPCAP
1123    "with libpcap ", pcap_version,
1124 #else
1125    "without libpcap", "",
1126 #endif
1127
1128 #ifdef HAVE_LIBZ
1129 #ifdef ZLIB_VERSION
1130    "with libz ", ZLIB_VERSION,
1131 #else /* ZLIB_VERSION */
1132    "with libz ", "(version unknown)",
1133 #endif /* ZLIB_VERSION */
1134 #else /* HAVE_LIBZ */
1135    "without libz", "",
1136 #endif /* HAVE_LIBZ */
1137
1138 /* Oh, this is pretty */
1139 #if defined(HAVE_UCD_SNMP_SNMP_H)
1140 #ifdef HAVE_UCD_SNMP_VERSION_H
1141    "with UCD SNMP ", VersionInfo
1142 #else /* HAVE_UCD_SNMP_VERSION_H */
1143    "with UCD SNMP ", "(version unknown)"
1144 #endif /* HAVE_UCD_SNMP_VERSION_H */
1145 #elif defined(HAVE_SNMP_SNMP_H)
1146 #ifdef HAVE_SNMP_VERSION_H
1147    "with CMU SNMP ", snmp_Version()
1148 #else /* HAVE_SNMP_VERSION_H */
1149    "with CMU SNMP ", "(version unknown)"
1150 #endif /* HAVE_SNMP_VERSION_H */
1151 #else /* no SNMP */
1152    "without SNMP", ""
1153 #endif
1154    );
1155
1156 #ifndef WIN32
1157   /* Now get our args */
1158   while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1159     switch (opt) {
1160       case 'b':        /* Bold font */
1161         bold_font = g_strdup(optarg);
1162         break;
1163       case 'B':        /* Byte view pane height */
1164         bv_size = atoi(optarg);
1165         break;
1166       case 'c':        /* Capture xxx packets */
1167 #ifdef HAVE_LIBPCAP
1168         cf.count = atoi(optarg);
1169 #else
1170         capture_option_specified = TRUE;
1171         arg_error = TRUE;
1172 #endif
1173         break;
1174       case 'D':        /* Turn off DSCP printing */
1175         g_ip_dscp_actif = FALSE;
1176         break;
1177       case 'f':
1178 #ifdef HAVE_LIBPCAP
1179         if (cf.cfilter)
1180                 g_free(cf.cfilter);
1181         cf.cfilter = g_strdup(optarg);
1182 #else
1183         capture_option_specified = TRUE;
1184         arg_error = TRUE;
1185 #endif
1186         break;
1187       case 'h':        /* Print help and exit */
1188         print_usage();
1189         exit(0);
1190         break;
1191       case 'i':        /* Use interface xxx */
1192 #ifdef HAVE_LIBPCAP
1193         cf.iface = g_strdup(optarg);
1194 #else
1195         capture_option_specified = TRUE;
1196         arg_error = TRUE;
1197 #endif
1198         break;
1199       case 'k':        /* Start capture immediately */
1200 #ifdef HAVE_LIBPCAP
1201         start_capture = TRUE;
1202 #else
1203         capture_option_specified = TRUE;
1204         arg_error = TRUE;
1205 #endif
1206         break;
1207       case 'm':        /* Medium font */
1208         medium_font = g_strdup(optarg);
1209         break;
1210       case 'n':        /* No name resolution */
1211         g_resolving_actif = 0;
1212         break;
1213       case 'P':        /* Packet list pane height */
1214         pl_size = atoi(optarg);
1215         break;
1216       case 'Q':        /* Quit after capture (just capture to file) */
1217 #ifdef HAVE_LIBPCAP
1218         quit_after_cap = 1;
1219         start_capture = TRUE;  /*** -Q implies -k !! ***/
1220 #else
1221         capture_option_specified = TRUE;
1222         arg_error = TRUE;
1223 #endif
1224         break;
1225       case 'r':        /* Read capture file xxx */
1226         /* We may set "last_open_dir" to "cf_name", and if we change
1227            "last_open_dir" later, we free the old value, so we have to
1228            set "cf_name" to something that's been allocated. */
1229         cf_name = g_strdup(optarg);
1230         break;
1231       case 'R':        /* Read file filter */
1232         rfilter = optarg;
1233         break;
1234       case 's':        /* Set the snapshot (capture) length */
1235 #ifdef HAVE_LIBPCAP
1236         cf.snap = atoi(optarg);
1237 #else
1238         capture_option_specified = TRUE;
1239         arg_error = TRUE;
1240 #endif
1241         break;
1242       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1243 #ifdef HAVE_LIBPCAP
1244         sync_mode = TRUE;
1245 #else
1246         capture_option_specified = TRUE;
1247         arg_error = TRUE;
1248 #endif
1249         break;
1250       case 't':        /* Time stamp type */
1251         if (strcmp(optarg, "r") == 0)
1252           timestamp_type = RELATIVE;
1253         else if (strcmp(optarg, "a") == 0)
1254           timestamp_type = ABSOLUTE;
1255         else if (strcmp(optarg, "d") == 0)
1256           timestamp_type = DELTA;
1257         else {
1258           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1259             optarg);
1260           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1261           fprintf(stderr, "or \"d\" for delta.\n");
1262           exit(1);
1263         }
1264         break;
1265       case 'T':        /* Tree view pane height */
1266         tv_size = atoi(optarg);
1267         break;
1268       case 'v':        /* Show version and exit */
1269         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1270         exit(0);
1271         break;
1272       case 'w':        /* Write to capture file xxx */
1273 #ifdef HAVE_LIBPCAP
1274         save_file = g_strdup(optarg);
1275 #else
1276         capture_option_specified = TRUE;
1277         arg_error = TRUE;
1278 #endif
1279         break;
1280       case 'W':        /* Write to capture file FD xxx */
1281 #ifdef HAVE_LIBPCAP
1282         cf.save_file_fd = atoi(optarg);
1283 #else
1284         capture_option_specified = TRUE;
1285         arg_error = TRUE;
1286 #endif
1287         break;
1288       default:
1289       case '?':        /* Bad flag - print usage message */
1290         arg_error = TRUE;
1291         break;
1292     }
1293   }
1294 #endif
1295
1296 #ifndef HAVE_LIBPCAP
1297   if (capture_option_specified)
1298     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1299 #endif
1300 #ifndef WIN32
1301   if (arg_error)
1302     print_usage();
1303 #endif
1304 #ifdef HAVE_LIBPCAP
1305   if (start_capture) {
1306     /* We're supposed to do a live capture; did the user specify an interface
1307        to use? */
1308     if (cf.iface == NULL) {
1309       /* No - pick the first one from the list of interfaces. */
1310       if_list = get_interface_list(&err, err_str);
1311       if (if_list == NULL) {
1312         switch (err) {
1313
1314         case CANT_GET_INTERFACE_LIST:
1315             fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1316                         err_str);
1317             break;
1318
1319         case NO_INTERFACES_FOUND:
1320             fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1321             break;
1322         }
1323         exit(2);
1324       }
1325       cf.iface = g_strdup(if_list->data);       /* first interface */
1326       free_interface_list(if_list);
1327     }
1328   }
1329   if (capture_child) {
1330     if (cf.save_file_fd == -1) {
1331       /* XXX - send this to the standard output as something our parent
1332          should put in an error message box? */
1333       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1334       exit(1);
1335     }
1336   }
1337 #endif
1338
1339   /* Build the column format array */  
1340   for (i = 0; i < cf.cinfo.num_cols; i++) {
1341     cf.cinfo.col_fmt[i] = get_column_format(i);
1342     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1343     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1344       NUM_COL_FMTS);
1345     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1346     if (cf.cinfo.col_fmt[i] == COL_INFO)
1347       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1348     else
1349       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1350   }
1351
1352   if (cf.snap < 1)
1353     cf.snap = WTAP_MAX_PACKET_SIZE;
1354   else if (cf.snap < MIN_PACKET_SIZE)
1355     cf.snap = MIN_PACKET_SIZE;
1356   
1357   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1358   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1359   gtk_rc_parse(rc_file);
1360
1361   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1362     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1363     exit(1);
1364   }
1365
1366   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1367     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1368     exit(1);
1369   }
1370
1371   create_main_window(pl_size, tv_size, bv_size, prefs);
1372
1373 /* 
1374    Hmmm should we do it here
1375 */
1376
1377   ethereal_proto_init();   /* Init anything that needs initializing */
1378
1379 #ifdef HAVE_LIBPCAP
1380   /* Is this a "child" ethereal, which is only supposed to pop up a
1381      capture box to let us stop the capture, and run a capture
1382      to a file that our parent will read? */
1383   if (!capture_child) {
1384 #endif
1385     /* No.  Pop up the main window, and read in a capture file if
1386        we were told to. */
1387
1388     gtk_widget_show(top_level);
1389     set_menus_for_capture_file(FALSE);
1390
1391     cf.colors = colfilter_new();
1392
1393     /* If we were given the name of a capture file, read it in now;
1394        we defer it until now, so that, if we can't open it, and pop
1395        up an alert box, the alert box is more likely to come up on
1396        top of the main window - but before the preference-file-error
1397        alert box, so, if we get one of those, it's more likely to come
1398        up on top of us. */
1399     if (cf_name) {
1400       if (rfilter != NULL) {
1401         if (dfilter_compile(rfilter, &rfcode) != 0) {
1402           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1403           rfilter_parse_failed = TRUE;
1404         }
1405       }
1406       if (!rfilter_parse_failed) {
1407         if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1408           /* "open_cap_file()" succeeded, so it closed the previous
1409              capture file, and thus destroyed any previous read filter
1410              attached to "cf". */
1411           cf.rfcode = rfcode;
1412           err = read_cap_file(&cf);
1413           /* Save the name of the containing directory specified in the
1414              path name, if any; we can write over cf_name, which is a
1415              good thing, given that "get_dirname()" does write over its
1416              argument. */
1417           s = get_dirname(cf_name);
1418           if (s != NULL)
1419             last_open_dir = s;
1420         } else {
1421           dfilter_destroy(rfcode);
1422           cf.rfcode = NULL;
1423         }
1424       }
1425     }
1426 #ifdef HAVE_LIBPCAP
1427   }
1428 #endif
1429
1430   /* If we failed to open the preferences file, pop up an alert box;
1431      we defer it until now, so that the alert box is more likely to
1432      come up on top of the main window. */
1433   if (pf_path != NULL) {
1434       simple_dialog(ESD_TYPE_WARN, NULL,
1435         "Could not open preferences file\n\"%s\": %s.", pf_path,
1436         strerror(pf_open_errno));
1437   }
1438
1439 #ifdef HAVE_LIBPCAP
1440   if (capture_child) {
1441     /* This is the child process for a sync mode or fork mode capture,
1442        so just do the low-level work of a capture - don't create
1443        a temporary file and fork off *another* child process (so don't
1444        call "do_capture()"). */
1445
1446        capture();
1447
1448        /* The capture is done; there's nothing more for us to do. */
1449        gtk_exit(0);
1450   } else {
1451     if (start_capture) {
1452       /* "-k" was specified; start a capture. */
1453       do_capture(save_file);
1454     }
1455     else {
1456             set_menus_for_capture_in_progress(FALSE);
1457     }
1458   }
1459 #endif
1460
1461   gtk_main();
1462
1463   ethereal_proto_cleanup();
1464   g_free(rc_file);
1465
1466   exit(0);
1467 }
1468
1469 static void
1470 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1471 {
1472   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
1473                       *bv_table, *stat_hbox,
1474                       *filter_bt, *filter_cm, *filter_te,
1475                       *filter_reset;
1476   GList               *filter_list = NULL;
1477   GtkStyle            *pl_style;
1478   GtkAccelGroup       *accel;
1479   int                   i;
1480
1481   /* Main window */  
1482   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1483   gtk_widget_set_name(top_level, "main window");
1484   gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1485     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1486   gtk_signal_connect(GTK_OBJECT(top_level), "destroy", 
1487     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1488   gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1489   gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1490   gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1491
1492   /* Container for menu bar, paned windows and progress/info box */
1493   main_vbox = gtk_vbox_new(FALSE, 1);
1494   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1495   gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1496   gtk_widget_show(main_vbox);
1497
1498   /* Menu bar */
1499   get_main_menu(&menubar, &accel);
1500   gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1501   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1502   gtk_widget_show(menubar);
1503
1504   /* Panes for the packet list, tree, and byte view */
1505   u_pane = gtk_vpaned_new();
1506   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1507   l_pane = gtk_vpaned_new();
1508   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1509   gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
1510   gtk_widget_show(u_pane);
1511   gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
1512   gtk_widget_show(l_pane);
1513
1514   /* Packet list */
1515   pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1516   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1517     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1518   gtk_widget_show(pkt_scrollw);
1519   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1520
1521   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1522   gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1523   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1524   set_plist_sel_browse(prefs->gui_plist_sel_browse);
1525   pl_style = gtk_style_new();
1526   gdk_font_unref(pl_style->font);
1527   pl_style->font = m_r_font;
1528   gtk_widget_set_style(packet_list, pl_style);
1529   gtk_widget_set_name(packet_list, "packet list");
1530   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1531     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1532   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1533     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1534   for (i = 0; i < cf.cinfo.num_cols; i++) {
1535     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1536       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1537
1538     /* Right-justify the packet number column. */
1539     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1540       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1541         GTK_JUSTIFY_RIGHT);
1542
1543     /* Save static column sizes to use during a "-S" capture, so that
1544        the columns don't resize during a live capture. */
1545     cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1546                                 get_column_longest_string(get_column_format(i)));
1547   }
1548   gtk_widget_set_usize(packet_list, -1, pl_size);
1549   gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1550     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1551   gtk_widget_show(packet_list);
1552   
1553   /* Tree view */
1554   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1555   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1556     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1557   gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
1558   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1559   gtk_widget_show(tv_scrollw);
1560   
1561   tree_view = gtk_ctree_new(1, 0);
1562   /* I need this next line to make the widget work correctly with hidden
1563    * column titles and GTK_SELECTION_BROWSE */
1564   gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1565   gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1566   set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
1567   set_ptree_line_style(prefs->gui_ptree_line_style);
1568   set_ptree_expander_style(prefs->gui_ptree_expander_style);
1569
1570   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1571     GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1572   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1573     GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1574   gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1575     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1576   gtk_widget_show(tree_view);
1577
1578   item_style = gtk_style_new();
1579   gdk_font_unref(item_style->font);
1580   item_style->font = m_r_font;
1581
1582   /* Byte view. The table is only one row high, but 3 columns
1583    * wide. The middle column contains the GtkText with the hex dump.
1584    * The left and right columns contain vertical scrollbars. They both
1585    * do the same thing, but only one will be shown at a time, in accordance
1586    * with where the user wants the other vertical scrollbars places
1587    * (on the left or the right).
1588    */
1589   bv_table = gtk_table_new (1, 3, FALSE);
1590   gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
1591   gtk_widget_set_usize(bv_table, -1, bv_size);
1592   gtk_widget_show(bv_table);
1593
1594   byte_view = gtk_text_new(NULL, NULL);
1595   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1596   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1597   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
1598     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1599   gtk_widget_show(byte_view);
1600
1601   /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
1602    * in the GTK+ distribution, so I removed the horizontal scroll bar
1603    * that used to be here. I tried the gtk_text widget with a 
1604    * gtk_scrolled_window w/ viewport, but the vertical scrollowing
1605    * did not work well, and sometimes a few pixels were cut off on
1606    * the bottom. */
1607
1608   bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1609   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
1610     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1611
1612   bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1613   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
1614     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1615  
1616   /* Now that the 3 panes are created, set the vertical scrollbar
1617    * on the left or right according to the user's preference */
1618   set_scrollbar_placement(prefs->gui_scrollbar_on_right);
1619
1620   /* Progress/filter/info box */
1621   stat_hbox = gtk_hbox_new(FALSE, 1);
1622   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1623   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1624   gtk_widget_show(stat_hbox);
1625
1626   prog_bar = gtk_progress_bar_new();
1627   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1628   gtk_widget_show(prog_bar);
1629
1630   filter_bt = gtk_button_new_with_label("Filter:");
1631   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1632     GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
1633   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1634   gtk_widget_show(filter_bt);
1635   
1636   filter_cm = gtk_combo_new();
1637   filter_list = g_list_append (filter_list, "");
1638   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1639   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1640   filter_te = GTK_COMBO(filter_cm)->entry;
1641   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1642   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1643   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1644   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1645   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1646     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1647   gtk_widget_show(filter_cm);
1648
1649   filter_reset = gtk_button_new_with_label("Reset");
1650   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1651   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1652                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1653   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1654   gtk_widget_show(filter_reset);
1655
1656   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1657    * of any widget that ends up calling a callback which needs
1658    * that text entry pointer */
1659   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1660   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1661   set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1662   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1663   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1664
1665   info_bar = gtk_statusbar_new();
1666   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1667   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1668   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1669   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1670   gtk_widget_show(info_bar);
1671 }