3 * $Id: main.c,v 1.84 2000/01/06 08:20:13 guy Exp $
5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@zing.org>
7 * Copyright 1998 Gerald Combs
9 * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10 * needed by dissect routines
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.
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.
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.
29 * - Check for end of packet in dissect_* routines.
31 * - Multiple window support
32 * - Add cut/copy/paste
33 * - Create header parsing routines
34 * - Make byte view selections more fancy?
53 #include <sys/types.h>
60 #ifdef HAVE_NETINET_IN_H
61 #include <netinet/in.h>
66 #ifdef NEED_SNPRINTF_H
72 # include "snprintf.h"
75 #if defined(HAVE_UCD_SNMP_SNMP_H)
76 #ifdef HAVE_UCD_SNMP_VERSION_H
77 #include <ucd-snmp/version.h>
78 #endif /* HAVE_UCD_SNMP_VERSION_H */
79 #elif defined(HAVE_SNMP_SNMP_H)
80 #ifdef HAVE_SNMP_VERSION_H
81 #include <snmp/version.h>
82 #endif /* HAVE_SNMP_VERSION_H */
85 #ifdef NEED_STRERROR_H
90 #include "timestamp.h"
96 #include "prefs_dlg.h"
102 #include "simple_dialog.h"
103 #include "proto_draw.h"
106 #include "gtkglobals.h"
109 FILE *data_out_file = NULL;
112 GtkWidget *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
113 *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw,
114 *bv_vscroll_left, *bv_vscroll_right;
115 GdkFont *m_r_font, *m_b_font;
116 guint main_ctx, file_ctx;
117 gchar comp_info_str[256];
118 gchar *ethereal_path = NULL;
119 gchar *medium_font = MONO_MEDIUM_FONT;
120 gchar *bold_font = MONO_BOLD_FONT;
121 gchar *last_open_dir = NULL;
123 ts_type timestamp_type = RELATIVE;
125 GtkStyle *item_style;
127 /* Specifies the field currently selected in the GUI protocol tree */
128 field_info *finfo_selected = NULL;
130 static void follow_destroy_cb(GtkWidget *win, gpointer data);
131 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
132 static void follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii);
133 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
134 static char* hfinfo_numeric_format(header_field_info *hfinfo);
136 /* About Ethereal window */
138 about_ethereal( GtkWidget *w, gpointer data ) {
139 simple_dialog(ESD_TYPE_INFO, NULL,
140 "Ethereal - Network Protocol Analyzer\n"
141 "Version %s (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
142 "Compiled with %s\n\n"
144 "Check the man page for complete documentation and\n"
145 "for the list of contributors.\n"
147 "\nSee http://ethereal.zing.org/ for more information.",
148 VERSION, comp_info_str);
151 /* Follow the TCP stream, if any, to which the last packet that we called
152 a dissection routine on belongs (this might be the most recently
153 selected packet, or it might be the last packet in the file). */
155 follow_stream_cb( GtkWidget *w, gpointer data ) {
156 char filename1[128+1];
157 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
159 GtkWidget *hbox, *close_bt, *print_bt, *button;
161 gchar *follow_filter;
163 if( pi.ipproto == 6 ) {
164 /* we got tcp so we can follow */
165 /* Create a temporary file into which to dump the reassembled data
166 from the TCP stream, and set "data_out_file" to refer to it, so
167 that the TCP code will write to it.
169 XXX - it might be nicer to just have the TCP code directly
170 append stuff to the text widget for the TCP stream window,
171 if we can arrange that said window not pop up until we're
173 tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
175 simple_dialog(ESD_TYPE_WARN, NULL,
176 "Could not create temporary file %s: %s", filename1, strerror(errno));
179 data_out_file = fdopen( tmp_fd, "w" );
180 if( data_out_file == NULL ) {
181 simple_dialog(ESD_TYPE_WARN, NULL,
182 "Could not create temporary file %s: %s", filename1, strerror(errno));
188 /* Create a new filter that matches all packets in the TCP stream,
189 and set the display filter entry accordingly */
190 reset_tcp_reassembly();
191 follow_filter = build_follow_filter( &pi );
193 /* set the display filter entry accordingly */
194 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
195 gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
197 /* Run the display filter so it goes in effect. */
198 filter_packets(&cf, follow_filter);
200 /* the data_out_file should now be full of the streams information */
201 fclose( data_out_file );
203 /* the filename1 file now has all the text that was in the session */
204 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
205 gtk_widget_set_name( streamwindow, "TCP stream window" );
207 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
208 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
209 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
210 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
212 if( incomplete_tcp_stream ) {
213 gtk_window_set_title( GTK_WINDOW(streamwindow),
214 "Contents of TCP stream (incomplete)" );
216 gtk_window_set_title( GTK_WINDOW(streamwindow),
217 "Contents of TCP stream" );
219 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
220 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
222 /* setup the container */
223 box = gtk_vbox_new( FALSE, 0 );
224 gtk_container_add( GTK_CONTAINER(streamwindow), box );
225 gtk_widget_show( box );
227 /* set up the table we attach to */
228 table = gtk_table_new( 1, 2, FALSE );
229 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
230 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
231 gtk_widget_show( table );
233 /* create a text box */
234 text = gtk_text_new( NULL, NULL );
235 gtk_text_set_editable( GTK_TEXT(text), FALSE);
236 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
237 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
238 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
239 gtk_widget_show(text);
242 hbox = gtk_hbox_new( FALSE, 1 );
243 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
244 gtk_widget_show(hbox);
246 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
248 /* Create Radio Buttons */
249 button = gtk_radio_button_new_with_label(NULL, "ASCII");
250 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
251 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, button);
252 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
253 gtk_signal_connect(GTK_OBJECT(button), "toggled",
254 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
255 GTK_OBJECT(streamwindow));
256 gtk_widget_show(button);
258 button = gtk_radio_button_new_with_label(
259 gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
261 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
262 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
263 gtk_widget_show(button);
265 /* Create Close Button */
266 close_bt = gtk_button_new_with_label("Close");
267 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
268 GTK_SIGNAL_FUNC(gtk_widget_destroy),
269 GTK_OBJECT(streamwindow));
270 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
271 gtk_widget_show( close_bt );
273 /* Create Print Button */
274 print_bt = gtk_button_new_with_label("Print");
275 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
276 GTK_SIGNAL_FUNC(follow_print_stream),
277 GTK_OBJECT(streamwindow));
278 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
279 gtk_widget_show( print_bt );
281 /* create the scrollbar */
282 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
283 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
284 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
285 gtk_widget_show( vscrollbar );
286 gtk_widget_realize( text );
288 /* Tuck away the filename and textbox into streamwindow */
289 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
290 #define E_FOLLOW_TEXT_KEY "follow_text_key"
292 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
293 g_strdup(filename1));
294 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
296 follow_load_text(text, filename1, TRUE);
298 data_out_file = NULL;
299 gtk_widget_show( streamwindow );
301 simple_dialog(ESD_TYPE_WARN, NULL,
302 "Error following stream. Please make\n"
303 "sure you have a TCP packet selected.");
307 /* The destroy call back has the responsibility of
308 * unlinking the temporary file */
310 follow_destroy_cb(GtkWidget *win, gpointer data)
314 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
315 E_FOLLOW_FILENAME_KEY);
319 gtk_widget_destroy(win);
322 /* Handles the ASCII/EBCDIC toggling */
324 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
326 gboolean show_ascii = FALSE;
327 GtkWidget *button, *text;
330 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
332 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
334 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
335 E_FOLLOW_FILENAME_KEY);
341 if (GTK_TOGGLE_BUTTON(button)->active)
344 follow_load_text(text, filename, show_ascii);
347 #define FLT_BUF_SIZE 1024
349 follow_read_stream(char *filename, gboolean show_ascii,
350 void (*print_line)(char *, int, gboolean, void *), void *arg)
354 guint32 client_addr = 0;
355 guint16 client_port = 0;
357 data_out_file = fopen( filename, "r" );
358 if( data_out_file ) {
359 char buffer[FLT_BUF_SIZE];
361 while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
362 if (client_addr == 0) {
363 client_addr = sc.src_addr;
364 client_port = sc.src_port;
367 while (sc.dlen > 0) {
368 bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
369 nchars = fread( buffer, 1, bcount, data_out_file );
374 /* If our native arch is EBCDIC, call:
375 * ASCII_TO_EBCDIC(buffer, nchars);
379 /* If our native arch is ASCII, call: */
380 EBCDIC_to_ASCII(buffer, nchars);
382 if (client_addr == sc.src_addr && client_port == sc.src_port)
383 (*print_line)( buffer, nchars, FALSE, arg );
385 (*print_line)( buffer, nchars, TRUE, arg );
388 if( ferror( data_out_file ) ) {
389 simple_dialog(ESD_TYPE_WARN, NULL,
390 "Error reading temporary file %s: %s", filename, strerror(errno));
392 fclose( data_out_file );
394 simple_dialog(ESD_TYPE_WARN, NULL,
395 "Could not open temporary file %s: %s", filename, strerror(errno));
400 * XXX - for text printing, we probably want to wrap lines at 80 characters;
401 * for PostScript printing, we probably want to wrap them at the appropriate
402 * width, and perhaps put some kind of dingbat (to use the technical term)
403 * to indicate a wrapped line, along the lines of what's done when displaying
404 * this in a window, as per Warren Young's suggestion.
406 * For now, we support only text printing.
409 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
413 fwrite(buffer, nchars, 1, fh);
417 follow_print_stream(GtkWidget *w, gpointer parent_w)
423 gboolean show_ascii = FALSE;
426 switch (prefs.pr_dest) {
428 print_dest = prefs.pr_cmd;
433 print_dest = prefs.pr_file;
436 default: /* "Can't happen" */
437 simple_dialog(ESD_TYPE_WARN, NULL,
438 "Couldn't figure out where to send the print "
439 "job. Check your preferences.");
443 fh = open_print_dest(to_file, print_dest);
447 simple_dialog(ESD_TYPE_WARN, NULL,
448 "Couldn't run print command %s.", prefs.pr_cmd);
452 simple_dialog(ESD_TYPE_WARN, NULL,
453 file_write_error_message(errno),
460 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
462 if (GTK_TOGGLE_BUTTON(button)->active)
465 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
466 E_FOLLOW_FILENAME_KEY);
468 if (filename != NULL) {
469 print_preamble(fh, PR_FMT_TEXT);
470 follow_read_stream(filename, show_ascii, follow_print_text, fh);
471 print_finale(fh, PR_FMT_TEXT);
472 close_print_dest(to_file, fh);
475 simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
480 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
482 GtkWidget *text = arg;
485 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
486 &prefs.st_server_bg, buffer, nchars );
488 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
489 &prefs.st_client_bg, buffer, nchars );
493 follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii)
497 /* Delete any info already in text box */
498 bytes_already = gtk_text_get_length(GTK_TEXT(text));
499 if (bytes_already > 0) {
500 gtk_text_set_point(GTK_TEXT(text), 0);
501 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
504 /* stop the updates while we fill the text box */
505 gtk_text_freeze( GTK_TEXT(text) );
506 follow_read_stream(filename, show_ascii, follow_add_to_gtk_text, text);
507 gtk_text_thaw( GTK_TEXT(text) );
510 /* Match selected byte pattern */
512 match_selected_cb(GtkWidget *w, gpointer data)
515 GtkWidget *filter_te;
516 char *ptr, *format, *stringified;
517 int i, dfilter_len, abbrev_len;
519 header_field_info *hfinfo;
521 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
523 if (!finfo_selected) {
524 simple_dialog(ESD_TYPE_WARN, NULL,
525 "Error determining selected bytes. Please make\n"
526 "sure you have selected a field within the tree\n"
527 "view to be matched.");
531 hfinfo = finfo_selected->hfinfo;
533 abbrev_len = strlen(hfinfo->abbrev);
535 switch(hfinfo->type) {
538 dfilter_len = abbrev_len + 2;
539 buf = g_malloc0(dfilter_len);
540 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
552 dfilter_len = abbrev_len + 20;
553 buf = g_malloc0(dfilter_len);
554 format = hfinfo_numeric_format(hfinfo);
555 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
559 dfilter_len = abbrev_len + 4 + 15 + 1;
560 buf = g_malloc0(dfilter_len);
561 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
562 ipv4_addr_str(&(finfo_selected->value.ipv4)));
566 dfilter_len = abbrev_len + 15;
567 buf = g_malloc0(dfilter_len);
568 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
569 finfo_selected->value.numeric);
573 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
574 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
575 buf = g_malloc0(dfilter_len);
576 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
581 dfilter_len = abbrev_len + 30;
582 buf = g_malloc0(dfilter_len);
583 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
584 finfo_selected->value.floating);
588 dfilter_len = abbrev_len + 22;
589 buf = g_malloc0(dfilter_len);
590 snprintf(buf, dfilter_len, "%s == %s",
592 ether_to_str(finfo_selected->value.ether));
596 case FT_ABSOLUTE_TIME:
597 case FT_RELATIVE_TIME:
598 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
599 sizeof(struct timeval));
603 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
604 fi->value.string = g_strdup(va_arg(ap, char*));
612 c = cf.pd + finfo_selected->start;
613 buf = g_malloc0(32 + finfo_selected->length * 3);
616 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
617 ptr = buf+strlen(buf);
619 if (finfo_selected->length == 1) {
620 sprintf(ptr, "0x%02x", *c++);
623 for (i=0;i<finfo_selected->length; i++) {
625 sprintf(ptr, "%02x", *c++);
628 sprintf(ptr, ":%02x", *c++);
630 ptr = buf+strlen(buf);
636 /* create a new one and set the display filter entry accordingly */
637 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
639 /* Run the display filter so it goes in effect. */
640 filter_packets(&cf, buf);
642 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
646 hfinfo_numeric_format(header_field_info *hfinfo)
650 /* Pick the proper format string */
651 switch(hfinfo->display) {
654 case BASE_OCT: /* I'm lazy */
655 case BASE_BIN: /* I'm lazy */
656 switch(hfinfo->type) {
670 g_assert_not_reached();
675 switch(hfinfo->type) {
677 format = "%s == 0x%02x";
680 format = "%s == 0x%04x";
683 format = "%s == 0x%06x";
686 format = "%s == 0x%08x";
689 g_assert_not_reached();
694 g_assert_not_reached();
701 /* Run the current display filter on the current packet set, and
704 filter_activate_cb(GtkWidget *w, gpointer data)
706 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
707 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
708 GList *li, *nl = NULL;
709 gboolean add_filter = TRUE;
711 char *s = gtk_entry_get_text(GTK_ENTRY(w));
713 /* GtkCombos don't let us get at their list contents easily, so we maintain
714 our own filter list, and feed it to gtk_combo_set_popdown_strings when
715 a new filter is added. */
716 if (filter_packets(&cf, g_strdup(s))) {
717 li = g_list_first(filter_list);
719 if (li->data && strcmp(s, li->data) == 0)
725 filter_list = g_list_append(filter_list, g_strdup(s));
726 li = g_list_first(filter_list);
728 nl = g_list_append(nl, strdup(li->data));
731 gtk_combo_set_popdown_strings(filter_cm, nl);
732 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
737 /* redisplay with no display filter */
739 filter_reset_cb(GtkWidget *w, gpointer data)
741 GtkWidget *filter_te = NULL;
743 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
744 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
747 filter_packets(&cf, NULL);
750 /* What to do when a list item is selected/unselected */
752 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
763 select_packet(&cf, row);
767 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
768 unselect_packet(&cf);
772 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
775 int tree_selected_start = -1;
776 int tree_selected_len = -1;
779 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
782 finfo_selected = finfo;
783 tree_selected_start = finfo->start;
784 tree_selected_len = finfo->length;
786 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
787 tree_selected_start, tree_selected_len, cf.current_frame->encoding);
791 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
793 finfo_selected = NULL;
794 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
795 -1, -1, cf.current_frame->encoding);
798 void collapse_all_cb(GtkWidget *widget, gpointer data) {
799 if (cf.protocol_tree)
800 collapse_all_tree(cf.protocol_tree, tree_view);
803 void expand_all_cb(GtkWidget *widget, gpointer data) {
804 if (cf.protocol_tree)
805 expand_all_tree(cf.protocol_tree, tree_view);
809 set_scrollbar_placement(int pos) /* 0=left, 1=right */
812 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
813 GTK_CORNER_TOP_LEFT );
814 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
815 GTK_CORNER_TOP_LEFT );
816 gtk_widget_hide(bv_vscroll_left);
817 gtk_widget_show(bv_vscroll_right);
820 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
821 GTK_CORNER_TOP_RIGHT );
822 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
823 GTK_CORNER_TOP_RIGHT );
824 gtk_widget_hide(bv_vscroll_right);
825 gtk_widget_show(bv_vscroll_left);
830 set_plist_sel_browse(gboolean val)
833 unselect_packet(&cf);
835 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
836 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
838 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
841 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
846 set_ptree_sel_browse(gboolean val)
848 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
849 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
851 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
854 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
859 set_ptree_line_style(gint style)
861 /* I'm using an assert here since the preferences code limits
862 * the user input, both in the GUI and when reading the preferences file.
863 * If the value is incorrect, it's a program error, not a user-initiated error.
865 g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
866 gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
870 set_ptree_expander_style(gint style)
872 /* I'm using an assert here since the preferences code limits
873 * the user input, both in the GUI and when reading the preferences file.
874 * If the value is incorrect, it's a program error, not a user-initiated error.
876 g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
877 gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
882 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
883 /* If we have a capture file open, and it's a temporary file,
885 if (cf.filename != NULL && cf.is_tempfile)
890 /* call initialization routines at program startup time */
892 ethereal_proto_init(void) {
901 ethereal_proto_cleanup(void) {
909 fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
910 VERSION, comp_info_str);
912 fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
914 fprintf(stderr, " [-f <capture filter>] [-i interface] [-m <medium font>] [-n]\n");
915 fprintf(stderr, " [-P <packet list height>] [-r infile] [-R <read filter>]\n");
916 fprintf(stderr, " [-s snaplen] [-t <time stamp format>] [-T <tree view height>]\n");
917 fprintf(stderr, " [-w savefile]\n");
919 fprintf(stderr, "%s [-vh] [-b <bold font>] [-B <byte view height>] [-m <medium font>]\n",
921 fprintf(stderr, " [-n] [-P <packet list height>] [-r infile] [-R <read filter>]\n");
922 fprintf(stderr, " [-t <time stamp format>] [-T <tree view height>]\n");
926 /* And now our feature presentation... [ fade to music ] */
928 main(int argc, char *argv[])
938 gboolean arg_error = FALSE;
941 extern char pcap_version[];
944 int pf_open_errno = 0;
947 gboolean start_capture = FALSE;
948 gchar *save_file = NULL;
950 gboolean capture_option_specified = FALSE;
952 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
953 *bv_table, *stat_hbox,
954 *filter_bt, *filter_cm, *filter_te,
956 GList *filter_list = NULL;
958 GtkAccelGroup *accel;
959 gint pl_size = 280, tv_size = 95, bv_size = 75;
960 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
961 dfilter *rfcode = NULL;
962 gboolean rfilter_parse_failed = FALSE;
965 ethereal_path = argv[0];
968 command_name = strrchr(ethereal_path, '/');
969 if (command_name == NULL)
970 command_name = ethereal_path;
973 /* Set "capture_child" to indicate whether this is going to be a child
974 process for a "-S" capture. */
975 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
978 /* If invoked with the "-G" flag, we dump out a glossary of
979 display filter symbols.
981 We must do this before calling "gtk_init()", because "gtk_init()"
982 tries to open an X display, and we don't want to have to do any X
983 stuff just to do a build.
985 Given that we call "gtk_init()" before doing the regular argument
986 list processing, so that it can handle X and GTK+ arguments and
987 remove them from the list at which we look, this means we must do
988 this before doing the regular argument list processing, as well.
992 you must give the "-G" flag as the first flag on the command line;
994 you must give it as "-G", nothing more, nothing less;
996 any arguments after the "-G" flag will not be used. */
997 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
998 ethereal_proto_init();
999 proto_registrar_dump();
1003 /* Let GTK get its args */
1004 gtk_init (&argc, &argv);
1006 prefs = read_prefs(&pf_path);
1007 if (pf_path != NULL) {
1008 /* The preferences file exists, but couldn't be opened; "pf_path" is
1009 its pathname. Remember "errno", as that says why the attempt
1011 pf_open_errno = errno;
1014 /* Initialize the capture file struct */
1016 cf.plist_end = NULL;
1020 cf.user_saved = FALSE;
1021 cf.is_tempfile = FALSE;
1026 cf.cfilter = g_strdup(EMPTY_FILTER);
1029 cf.save_file = NULL;
1030 cf.save_file_fd = -1;
1031 cf.snap = WTAP_MAX_PACKET_SIZE;
1033 cf.cinfo.num_cols = prefs->num_cols;
1034 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1035 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1036 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1037 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1038 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1040 /* Assemble the compile-time options */
1041 snprintf(comp_info_str, 256,
1042 #ifdef GTK_MAJOR_VERSION
1043 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1046 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1050 "with libpcap ", pcap_version,
1052 "without libpcap", "",
1057 "with libz ", ZLIB_VERSION,
1058 #else /* ZLIB_VERSION */
1059 "with libz ", "(version unknown)",
1060 #endif /* ZLIB_VERSION */
1061 #else /* HAVE_LIBZ */
1063 #endif /* HAVE_LIBZ */
1065 /* Oh, this is pretty */
1066 #if defined(HAVE_UCD_SNMP_SNMP_H)
1067 #ifdef HAVE_UCD_SNMP_VERSION_H
1068 "with UCD SNMP ", VersionInfo
1069 #else /* HAVE_UCD_SNMP_VERSION_H */
1070 "with UCD SNMP ", "(version unknown)"
1071 #endif /* HAVE_UCD_SNMP_VERSION_H */
1072 #elif defined(HAVE_SNMP_SNMP_H)
1073 #ifdef HAVE_SNMP_VERSION_H
1074 "with CMU SNMP ", snmp_Version()
1075 #else /* HAVE_SNMP_VERSION_H */
1076 "with CMU SNMP ", "(version unknown)"
1077 #endif /* HAVE_SNMP_VERSION_H */
1084 /* Now get our args */
1085 while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1087 case 'b': /* Bold font */
1088 bold_font = g_strdup(optarg);
1090 case 'B': /* Byte view pane height */
1091 bv_size = atoi(optarg);
1093 case 'c': /* Capture xxx packets */
1095 cf.count = atoi(optarg);
1097 capture_option_specified = TRUE;
1105 cf.cfilter = g_strdup(optarg);
1107 capture_option_specified = TRUE;
1111 case 'h': /* Print help and exit */
1115 case 'i': /* Use interface xxx */
1117 cf.iface = g_strdup(optarg);
1119 capture_option_specified = TRUE;
1123 case 'k': /* Start capture immediately */
1125 start_capture = TRUE;
1127 capture_option_specified = TRUE;
1131 case 'm': /* Medium font */
1132 medium_font = g_strdup(optarg);
1134 case 'n': /* No name resolution */
1135 g_resolving_actif = 0;
1137 case 'P': /* Packet list pane height */
1138 pl_size = atoi(optarg);
1140 case 'Q': /* Quit after capture (just capture to file) */
1143 start_capture = TRUE; /*** -Q implies -k !! ***/
1145 capture_option_specified = TRUE;
1149 case 'r': /* Read capture file xxx */
1150 /* We may set "last_open_dir" to "cf_name", and if we change
1151 "last_open_dir" later, we free the old value, so we have to
1152 set "cf_name" to something that's been allocated. */
1153 cf_name = g_strdup(optarg);
1155 case 'R': /* Read file filter */
1158 case 's': /* Set the snapshot (capture) length */
1160 cf.snap = atoi(optarg);
1162 capture_option_specified = TRUE;
1166 case 'S': /* "Sync" mode: used for following file ala tail -f */
1170 capture_option_specified = TRUE;
1174 case 't': /* Time stamp type */
1175 if (strcmp(optarg, "r") == 0)
1176 timestamp_type = RELATIVE;
1177 else if (strcmp(optarg, "a") == 0)
1178 timestamp_type = ABSOLUTE;
1179 else if (strcmp(optarg, "d") == 0)
1180 timestamp_type = DELTA;
1182 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1184 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1185 fprintf(stderr, "or \"d\" for delta.\n");
1189 case 'T': /* Tree view pane height */
1190 tv_size = atoi(optarg);
1192 case 'v': /* Show version and exit */
1193 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1196 case 'w': /* Write to capture file xxx */
1198 save_file = g_strdup(optarg);
1200 capture_option_specified = TRUE;
1204 case 'W': /* Write to capture file FD xxx */
1206 cf.save_file_fd = atoi(optarg);
1208 capture_option_specified = TRUE;
1213 case '?': /* Bad flag - print usage message */
1220 #ifndef HAVE_LIBPCAP
1221 if (capture_option_specified)
1222 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1227 if (start_capture) {
1228 if (cf.iface == NULL) {
1229 fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1233 if (capture_child) {
1234 if (cf.save_file_fd == -1) {
1235 /* XXX - send this to the standard output as something our parent
1236 should put in an error message box? */
1237 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1243 /* Build the column format array */
1244 for (i = 0; i < cf.cinfo.num_cols; i++) {
1245 cf.cinfo.col_fmt[i] = get_column_format(i);
1246 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1247 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1249 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1250 if (cf.cinfo.col_fmt[i] == COL_INFO)
1251 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1253 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1257 cf.snap = WTAP_MAX_PACKET_SIZE;
1258 else if (cf.snap < MIN_PACKET_SIZE)
1259 cf.snap = MIN_PACKET_SIZE;
1261 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1262 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1263 gtk_rc_parse(rc_file);
1265 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1266 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1270 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1271 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1276 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1277 gtk_widget_set_name(top_level, "main window");
1278 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1279 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1280 gtk_signal_connect(GTK_OBJECT(top_level), "destroy",
1281 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1282 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1283 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1284 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1286 /* Container for menu bar, paned windows and progress/info box */
1287 main_vbox = gtk_vbox_new(FALSE, 1);
1288 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1289 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1290 gtk_widget_show(main_vbox);
1293 get_main_menu(&menubar, &accel);
1294 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1295 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1296 gtk_widget_show(menubar);
1298 /* Panes for the packet list, tree, and byte view */
1299 u_pane = gtk_vpaned_new();
1300 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1301 l_pane = gtk_vpaned_new();
1302 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1303 gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
1304 gtk_widget_show(u_pane);
1305 gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
1306 gtk_widget_show(l_pane);
1309 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1310 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1311 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1312 gtk_widget_show(pkt_scrollw);
1313 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1315 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1316 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1317 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1318 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1319 pl_style = gtk_style_new();
1320 gdk_font_unref(pl_style->font);
1321 pl_style->font = m_r_font;
1322 gtk_widget_set_style(packet_list, pl_style);
1323 gtk_widget_set_name(packet_list, "packet list");
1324 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1325 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1326 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1327 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1328 for (i = 0; i < cf.cinfo.num_cols; i++) {
1329 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1330 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1332 /* Right-justify the packet number column. */
1333 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1334 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1337 /* Save static column sizes to use during a "-S" capture, so that
1338 the columns don't resize during a live capture. */
1339 cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1342 gtk_widget_set_usize(packet_list, -1, pl_size);
1343 gtk_widget_show(packet_list);
1346 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1347 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1348 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1349 gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
1350 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1351 gtk_widget_show(tv_scrollw);
1353 tree_view = gtk_ctree_new(1, 0);
1354 /* I need this next line to make the widget work correctly with hidden
1355 * column titles and GTK_SELECTION_BROWSE */
1356 gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1357 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1358 set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
1359 set_ptree_line_style(prefs->gui_ptree_line_style);
1360 set_ptree_expander_style(prefs->gui_ptree_expander_style);
1362 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1363 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1364 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1365 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1366 gtk_widget_show(tree_view);
1368 item_style = gtk_style_new();
1369 gdk_font_unref(item_style->font);
1370 item_style->font = m_r_font;
1372 /* Byte view. The table is only one row high, but 3 columns
1373 * wide. The middle column contains the GtkText with the hex dump.
1374 * The left and right columns contain vertical scrollbars. They both
1375 * do the same thing, but only one will be shown at a time, in accordance
1376 * with where the user wants the other vertical scrollbars places
1377 * (on the left or the right).
1379 bv_table = gtk_table_new (1, 3, FALSE);
1380 gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
1381 gtk_widget_set_usize(bv_table, -1, bv_size);
1382 gtk_widget_show(bv_table);
1384 byte_view = gtk_text_new(NULL, NULL);
1385 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1386 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1387 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
1388 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1389 gtk_widget_show(byte_view);
1391 /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
1392 * in the GTK+ distribution, so I removed the horizontal scroll bar
1393 * that used to be here. I tried the gtk_text widget with a
1394 * gtk_scrolled_window w/ viewport, but the vertical scrollowing
1395 * did not work well, and sometimes a few pixels were cut off on
1398 bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1399 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
1400 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1402 bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1403 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
1404 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1406 /* Now that the 3 panes are created, set the vertical scrollbar
1407 * on the left or right according to the user's preference */
1408 set_scrollbar_placement(prefs->gui_scrollbar_on_right);
1410 /* Progress/filter/info box */
1411 stat_hbox = gtk_hbox_new(FALSE, 1);
1412 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1413 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1414 gtk_widget_show(stat_hbox);
1416 prog_bar = gtk_progress_bar_new();
1417 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1418 gtk_widget_show(prog_bar);
1420 filter_bt = gtk_button_new_with_label("Filter:");
1421 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1422 GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
1423 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1424 gtk_widget_show(filter_bt);
1426 filter_cm = gtk_combo_new();
1427 filter_list = g_list_append (filter_list, "");
1428 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1429 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1430 filter_te = GTK_COMBO(filter_cm)->entry;
1431 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1432 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1433 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1434 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1435 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1436 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1437 gtk_widget_show(filter_cm);
1439 filter_reset = gtk_button_new_with_label("Reset");
1440 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1441 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1442 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1443 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1444 gtk_widget_show(filter_reset);
1446 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1447 * of any widget that ends up calling a callback which needs
1448 * that text entry pointer */
1449 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1450 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1451 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1452 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1453 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1455 info_bar = gtk_statusbar_new();
1456 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1457 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1458 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1459 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1460 gtk_widget_show(info_bar);
1463 Hmmm should we do it here
1466 ethereal_proto_init(); /* Init anything that needs initializing */
1469 /* Is this a "child" ethereal, which is only supposed to pop up a
1470 capture box to let us stop the capture, and run a capture
1471 to a file that our parent will read? */
1472 if (!capture_child) {
1474 /* No. Pop up the main window, and read in a capture file if
1477 gtk_widget_show(top_level);
1479 cf.colors = colfilter_new();
1481 /* If we were given the name of a capture file, read it in now;
1482 we defer it until now, so that, if we can't open it, and pop
1483 up an alert box, the alert box is more likely to come up on
1484 top of the main window - but before the preference-file-error
1485 alert box, so, if we get one of those, it's more likely to come
1488 if (rfilter != NULL) {
1489 if (dfilter_compile(rfilter, &rfcode) != 0) {
1490 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1491 rfilter_parse_failed = TRUE;
1494 if (!rfilter_parse_failed) {
1495 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1496 /* "open_cap_file()" succeeded, so it closed the previous
1497 capture file, and thus destroyed any previous read filter
1498 attached to "cf". */
1500 err = read_cap_file(&cf);
1501 s = strrchr(cf_name, '/');
1503 last_open_dir = cf_name;
1507 dfilter_destroy(rfcode);
1516 /* If we failed to open the preferences file, pop up an alert box;
1517 we defer it until now, so that the alert box is more likely to
1518 come up on top of the main window. */
1519 if (pf_path != NULL) {
1520 simple_dialog(ESD_TYPE_WARN, NULL,
1521 "Could not open preferences file\n\"%s\": %s.", pf_path,
1522 strerror(pf_open_errno));
1526 if (capture_child) {
1527 /* This is the child process for a sync mode or fork mode capture,
1528 so just do the low-level work of a capture - don't create
1529 a temporary file and fork off *another* child process (so don't
1530 call "do_capture()"). */
1534 /* The capture is done; there's nothing more for us to do. */
1537 if (start_capture) {
1538 /* "-k" was specified; start a capture. */
1539 do_capture(save_file);
1546 ethereal_proto_cleanup();