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