3 * $Id: main.c,v 1.160 2000/10/16 23:18:05 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?
54 #ifdef HAVE_SYS_TYPES_H
55 #include <sys/types.h>
58 #ifdef HAVE_SYS_STAT_H
63 #include <io.h> /* open/close on win32 */
70 #ifdef HAVE_NETINET_IN_H
71 #include <netinet/in.h>
76 #ifdef NEED_SNPRINTF_H
77 # include "snprintf.h"
80 #if defined(HAVE_UCD_SNMP_SNMP_H)
81 #ifdef HAVE_UCD_SNMP_VERSION_H
82 #include <ucd-snmp/version.h>
83 #endif /* HAVE_UCD_SNMP_VERSION_H */
84 #elif defined(HAVE_SNMP_SNMP_H)
85 #ifdef HAVE_SNMP_VERSION_H
86 #include <snmp/version.h>
87 #endif /* HAVE_SNMP_VERSION_H */
90 #ifdef NEED_STRERROR_H
101 #include "timestamp.h"
108 #include "filter_prefs.h"
109 #include "prefs_dlg.h"
114 #include "simple_dialog.h"
115 #include "proto_draw.h"
118 #include "packet_win.h"
119 #include "gtkglobals.h"
124 GtkWidget *top_level, *packet_list, *tree_view, *byte_view,
125 *info_bar, *tv_scrollw, *pkt_scrollw;
126 static GtkWidget *bv_scrollw;
127 GdkFont *m_r_font, *m_b_font;
128 guint main_ctx, file_ctx, help_ctx;
129 gchar comp_info_str[256];
130 gchar *ethereal_path = NULL;
131 gchar *last_open_dir = NULL;
133 ts_type timestamp_type = RELATIVE;
135 GtkStyle *item_style;
137 /* Specifies the field currently selected in the GUI protocol tree */
138 field_info *finfo_selected = NULL;
140 static char* hfinfo_numeric_format(header_field_info *hfinfo);
141 static void create_main_window(gint, gint, gint, e_prefs*);
143 /* About Ethereal window */
145 about_ethereal( GtkWidget *w, gpointer data ) {
146 simple_dialog(ESD_TYPE_INFO, NULL,
147 "Ethereal - Network Protocol Analyzer\n"
148 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
149 "Compiled with %s\n\n"
151 "Check the man page for complete documentation and\n"
152 "for the list of contributors.\n"
154 "\nSee http://ethereal.zing.org/ for more information.",
159 /* Match selected byte pattern */
161 match_selected_cb(GtkWidget *w, gpointer data)
164 GtkWidget *filter_te;
165 char *ptr, *format, *stringified;
166 int i, dfilter_len, abbrev_len;
168 header_field_info *hfinfo;
170 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
172 if (!finfo_selected) {
173 simple_dialog(ESD_TYPE_CRIT, NULL,
174 "Error determining selected bytes. Please make\n"
175 "sure you have selected a field within the tree\n"
176 "view to be matched.");
180 hfinfo = finfo_selected->hfinfo;
182 abbrev_len = strlen(hfinfo->abbrev);
184 switch(hfinfo->type) {
187 dfilter_len = abbrev_len + 2;
188 buf = g_malloc0(dfilter_len);
189 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
201 dfilter_len = abbrev_len + 20;
202 buf = g_malloc0(dfilter_len);
203 format = hfinfo_numeric_format(hfinfo);
204 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
208 dfilter_len = abbrev_len + 4 + 15 + 1;
209 buf = g_malloc0(dfilter_len);
210 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
211 ipv4_addr_str(&(finfo_selected->value.ipv4)));
215 dfilter_len = abbrev_len + 15;
216 buf = g_malloc0(dfilter_len);
217 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
218 finfo_selected->value.numeric);
222 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
223 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
224 buf = g_malloc0(dfilter_len);
225 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
230 dfilter_len = abbrev_len + 30;
231 buf = g_malloc0(dfilter_len);
232 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
233 finfo_selected->value.floating);
237 dfilter_len = abbrev_len + 22;
238 buf = g_malloc0(dfilter_len);
239 snprintf(buf, dfilter_len, "%s == %s",
241 ether_to_str(finfo_selected->value.ether));
245 case FT_ABSOLUTE_TIME:
246 case FT_RELATIVE_TIME:
247 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
248 sizeof(struct timeval));
252 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
253 fi->value.string = g_strdup(va_arg(ap, char*));
261 c = cfile.pd + finfo_selected->start;
262 buf = g_malloc0(32 + finfo_selected->length * 3);
265 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
266 ptr = buf+strlen(buf);
268 if (finfo_selected->length == 1) {
269 sprintf(ptr, "0x%02x", *c++);
272 for (i=0;i<finfo_selected->length; i++) {
274 sprintf(ptr, "%02x", *c++);
277 sprintf(ptr, ":%02x", *c++);
279 ptr = buf+strlen(buf);
285 /* create a new one and set the display filter entry accordingly */
286 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
288 /* Run the display filter so it goes in effect. */
289 filter_packets(&cfile, buf);
291 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
295 hfinfo_numeric_format(header_field_info *hfinfo)
299 /* Pick the proper format string */
300 switch(hfinfo->display) {
303 case BASE_OCT: /* I'm lazy */
304 case BASE_BIN: /* I'm lazy */
305 switch(hfinfo->type) {
319 g_assert_not_reached();
324 switch(hfinfo->type) {
326 format = "%s == 0x%02x";
329 format = "%s == 0x%04x";
332 format = "%s == 0x%06x";
335 format = "%s == 0x%08x";
338 g_assert_not_reached();
343 g_assert_not_reached();
350 /* Run the current display filter on the current packet set, and
353 filter_activate_cb(GtkWidget *w, gpointer data)
355 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
356 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
357 GList *li, *nl = NULL;
358 gboolean add_filter = TRUE;
360 char *s = gtk_entry_get_text(GTK_ENTRY(w));
362 /* GtkCombos don't let us get at their list contents easily, so we maintain
363 our own filter list, and feed it to gtk_combo_set_popdown_strings when
364 a new filter is added. */
365 if (filter_packets(&cfile, g_strdup(s))) {
366 li = g_list_first(filter_list);
368 if (li->data && strcmp(s, li->data) == 0)
374 filter_list = g_list_append(filter_list, g_strdup(s));
375 li = g_list_first(filter_list);
377 nl = g_list_append(nl, strdup(li->data));
380 gtk_combo_set_popdown_strings(filter_cm, nl);
381 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
386 /* redisplay with no display filter */
388 filter_reset_cb(GtkWidget *w, gpointer data)
390 GtkWidget *filter_te = NULL;
392 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
393 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
396 filter_packets(&cfile, NULL);
399 /* GTKClist compare routine, overrides default to allow numeric comparison */
401 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
403 /* Get row text strings */
404 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
405 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
407 /* Attempt to convert to numbers */
408 double num1 = atof(text1);
409 double num2 = atof(text2);
411 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
413 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
414 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
415 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
416 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
417 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
418 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
419 (col_fmt == COL_PACKET_LENGTH)) {
421 /* Compare numeric column */
425 else if (num1 > num2)
433 /* Compare text column */
435 return (text1 != NULL);
440 return strcmp(text1, text2);
444 /* What to do when a column is clicked */
446 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
448 if (column == clist->sort_column) {
449 if (clist->sort_type == GTK_SORT_ASCENDING)
450 clist->sort_type = GTK_SORT_DESCENDING;
452 clist->sort_type = GTK_SORT_ASCENDING;
455 clist->sort_type = GTK_SORT_ASCENDING;
456 gtk_clist_set_sort_column(clist, column);
459 gtk_clist_sort(clist);
464 set_frame_mark(gboolean set, frame_data *frame, gint row) {
465 if (frame == NULL || row == -1) return;
466 frame->flags.marked = set;
467 gtk_clist_set_background(GTK_CLIST(packet_list), row,
468 (set) ? &prefs.gui_marked_bg : &WHITE);
469 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
470 (set) ? &prefs.gui_marked_fg : &BLACK);
474 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data) {
476 GdkEventButton *event_button = (GdkEventButton *)event;
479 if (w == NULL || event == NULL)
482 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
483 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
485 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
486 set_frame_mark(!fdata->flags.marked, fdata, row);
490 void mark_frame_cb(GtkWidget *w, gpointer data) {
491 if (cfile.current_frame) {
492 /* XXX hum, should better have a "cfile->current_row" here ... */
493 set_frame_mark(!cfile.current_frame->flags.marked,
495 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
496 cfile.current_frame));
500 static void mark_all_frames(gboolean set) {
502 if (cfile.plist == NULL) return;
503 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
506 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
510 void update_marked_frames(void) {
512 if (cfile.plist == NULL) return;
513 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
514 if (fdata->flags.marked)
517 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
522 void mark_all_frames_cb(GtkWidget *w, gpointer data) {
523 mark_all_frames(TRUE);
526 void unmark_all_frames_cb(GtkWidget *w, gpointer data) {
527 mark_all_frames(FALSE);
530 /* What to do when a list item is selected/unselected */
532 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
535 select_packet(&cfile, row);
539 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
540 unselect_packet(&cfile);
544 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
547 gchar *help_str = NULL;
548 gboolean has_blurb = FALSE;
552 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
555 finfo_selected = finfo;
557 set_menus_for_selected_tree_row(TRUE);
559 if (finfo->hfinfo && finfo->hfinfo->type != FT_TEXT_ONLY) {
560 if (finfo->hfinfo->blurb != NULL &&
561 finfo->hfinfo->blurb[0] != '\0') {
563 length = strlen(finfo->hfinfo->blurb);
565 length = strlen(finfo->hfinfo->name);
567 length += strlen(finfo->hfinfo->abbrev) + 10;
568 help_str = g_malloc(sizeof(gchar) * length);
569 sprintf(help_str, "%s (%s)",
570 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
571 finfo->hfinfo->abbrev);
572 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, help_str);
576 packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame,
581 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
583 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
584 finfo_selected = NULL;
585 set_menus_for_selected_tree_row(FALSE);
586 packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame,
590 void collapse_all_cb(GtkWidget *widget, gpointer data) {
591 if (cfile.protocol_tree)
592 collapse_all_tree(cfile.protocol_tree, tree_view);
595 void expand_all_cb(GtkWidget *widget, gpointer data) {
596 if (cfile.protocol_tree)
597 expand_all_tree(cfile.protocol_tree, tree_view);
600 void resolve_name_cb(GtkWidget *widget, gpointer data) {
601 if (cfile.protocol_tree) {
602 int tmp = g_resolving_actif;
603 g_resolving_actif = 1;
604 gtk_clist_clear ( GTK_CLIST(tree_view) );
605 proto_tree_draw(cfile.protocol_tree, tree_view);
606 g_resolving_actif = tmp;
610 /* Set the scrollbar placement of a scrolled window based upon pos value:
611 0 = left, 1 = right */
613 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
616 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
617 GTK_CORNER_TOP_LEFT);
619 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
620 GTK_CORNER_TOP_RIGHT);
624 /* List of all scrolled windows, so we can globally set the scrollbar
625 placement of them. */
626 static GList *scrolled_windows;
628 /* Add a scrolled window to the list of scrolled windows. */
629 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
632 remember_scrolled_window(GtkWidget *scrollw)
634 scrolled_windows = g_list_append(scrolled_windows, scrollw);
636 /* Catch the "destroy" event on the widget, so that we remove it from
637 the list when it's destroyed. */
638 gtk_signal_connect(GTK_OBJECT(scrollw), "destroy",
639 GTK_SIGNAL_FUNC(forget_scrolled_window), NULL);
642 /* Remove a scrolled window from the list of scrolled windows. */
644 forget_scrolled_window(GtkWidget *scrollw, gpointer data)
646 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
650 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
652 set_scrollbar_placement_scrollw((GtkWidget *)data,
656 /* Set the scrollbar placement of all scrolled windows based on pos value:
657 0 = left, 1 = right */
659 set_scrollbar_placement_all(int pos)
661 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
664 /* Set the selection mode of the packet list window. */
666 set_plist_sel_browse(gboolean val)
671 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
673 if (val == old_val) {
675 * The mode isn't changing, so don't do anything.
676 * In particular, don't gratuitiously unselect the
679 * XXX - why do we have to unselect the current packet
680 * ourselves? The documentation for the GtkCList at
682 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
684 * says "Note that setting the widget's selection mode to
685 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
686 * cause all the items in the GtkCList to become deselected."
692 unselect_packet(&cfile);
694 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
695 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
697 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
700 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
704 /* Set the font of the packet list window. */
706 set_plist_font(GdkFont *font)
711 style = gtk_style_new();
712 gdk_font_unref(style->font);
716 gtk_widget_set_style(packet_list, style);
718 /* Compute static column sizes to use during a "-S" capture, so that
719 the columns don't resize during a live capture. */
720 for (i = 0; i < cfile.cinfo.num_cols; i++) {
721 cfile.cinfo.col_width[i] = gdk_string_width(font,
722 get_column_longest_string(get_column_format(i)));
727 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
729 file_quit_cmd_cb(widget, data);
731 /* Say that the window should be deleted. */
736 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
738 /* XXX - should we check whether the capture file is an
739 unsaved temporary file for a live capture and, if so,
740 pop up a "do you want to exit without saving the capture
741 file?" dialog, and then just return, leaving said dialog
742 box to forcibly quit if the user clicks "OK"?
744 If so, note that this should be done in a subroutine that
745 returns TRUE if we do so, and FALSE otherwise, and that
746 "main_window_delete_event_cb()" should return its
749 /* Are we in the middle of reading a capture? */
750 if (cfile.state == FILE_READ_IN_PROGRESS) {
751 /* Yes, so we can't just close the file and quit, as
752 that may yank the rug out from under the read in
753 progress; instead, just set the state to
754 "FILE_READ_ABORTED" and return - the code doing the read
755 will check for that and, if it sees that, will clean
757 cfile.state = FILE_READ_ABORTED;
759 /* Close any capture file we have open; on some OSes, you
760 can't unlink a temporary capture file if you have it
762 "close_cap_file()" will unlink it after closing it if
763 it's a temporary file.
765 We do this here, rather than after the main loop returns,
766 as, after the main loop returns, the main window may have
767 been destroyed (if this is called due to a "destroy"
768 even on the main window rather than due to the user
769 selecting a menu item), and there may be a crash
770 or other problem when "close_cap_file()" tries to
771 clean up stuff in the main window.
773 XXX - is there a better place to put this?
774 Or should we have a routine that *just* closes the
775 capture file, and doesn't do anything with the UI,
776 which we'd call here, and another routine that
777 calls that routine and also cleans up the UI, which
778 we'd call elsewhere? */
779 close_cap_file(&cfile, info_bar);
781 /* Exit by leaving the main loop, so that any quit functions
782 we registered get called. */
790 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
793 fprintf(stderr, "%s [ -vh ] [ -kpQS ] [ -B <byte view height> ] [ -c count ]\n",
795 fprintf(stderr, "\t[ -f <capture filter> ] [ -i interface ] [ -m <medium font> ] \n");
796 fprintf(stderr, "\t[ -n ] [ -o <preference setting> ] ... [ -P <packet list height> ]\n");
797 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -s snaplen ] \n");
798 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ] [ -w savefile ]\n");
800 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ] [ -n ]\n",
802 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
803 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
804 fprintf(stderr, "\t[ -T <tree view height> ]\n");
808 /* And now our feature presentation... [ fade to music ] */
810 main(int argc, char *argv[])
819 gboolean arg_error = FALSE;
822 char pcap_version[] = "0.4a6";
825 extern char pcap_version[];
828 char *gpf_path, *pf_path;
829 int gpf_open_errno, pf_open_errno;
832 gboolean start_capture = FALSE;
833 gchar *save_file = NULL;
835 gchar err_str[PCAP_ERRBUF_SIZE];
837 gboolean capture_option_specified = FALSE;
839 gint pl_size = 280, tv_size = 95, bv_size = 75;
840 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
841 dfilter *rfcode = NULL;
842 gboolean rfilter_parse_failed = FALSE;
844 char *bold_font_name;
846 ethereal_path = argv[0];
849 command_name = get_basename(ethereal_path);
850 /* Set "capture_child" to indicate whether this is going to be a child
851 process for a "-S" capture. */
852 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
855 /* Register all dissectors; we must do this before checking for the
856 "-G" flag, as the "-G" flag dumps a list of fields registered
857 by the dissectors, and we must do it before we read the preferences,
858 in case any dissectors register preferences. */
859 epan_init(PLUGIN_DIR);
861 /* Now register the preferences for any non-dissector modules.
862 We must do that before we read the preferences as well. */
863 prefs_register_modules();
865 /* If invoked with the "-G" flag, we dump out a glossary of
866 display filter symbols.
868 We must do this before calling "gtk_init()", because "gtk_init()"
869 tries to open an X display, and we don't want to have to do any X
870 stuff just to do a build.
872 Given that we call "gtk_init()" before doing the regular argument
873 list processing, so that it can handle X and GTK+ arguments and
874 remove them from the list at which we look, this means we must do
875 this before doing the regular argument list processing, as well.
879 you must give the "-G" flag as the first flag on the command line;
881 you must give it as "-G", nothing more, nothing less;
883 any arguments after the "-G" flag will not be used. */
884 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
885 proto_registrar_dump();
889 /* Set the current locale according to the program environment.
890 * We haven't localized anything, but some GTK widgets are localized
891 * (the file selection dialogue, for example).
892 * This also sets the C-language locale to the native environment. */
895 /* Let GTK get its args */
896 gtk_init (&argc, &argv);
898 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
900 /* Initialize the capture file struct */
902 cfile.plist_end = NULL;
904 cfile.filename = NULL;
905 cfile.user_saved = FALSE;
906 cfile.is_tempfile = FALSE;
908 cfile.dfilter = NULL;
911 cfile.cfilter = g_strdup(EMPTY_FILTER);
914 cfile.save_file = NULL;
915 cfile.save_file_fd = -1;
916 cfile.snap = WTAP_MAX_PACKET_SIZE;
918 cfile.cinfo.num_cols = prefs->num_cols;
919 cfile.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
920 cfile.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cfile.cinfo.num_cols);
921 cfile.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
922 cfile.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
923 cfile.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
925 /* Assemble the compile-time options */
926 snprintf(comp_info_str, 256,
927 #ifdef GTK_MAJOR_VERSION
928 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
931 "GTK+ (version unknown), %s%s, %s%s, %s%s",
935 "with libpcap ", pcap_version,
937 "without libpcap", "",
942 "with libz ", ZLIB_VERSION,
943 #else /* ZLIB_VERSION */
944 "with libz ", "(version unknown)",
945 #endif /* ZLIB_VERSION */
946 #else /* HAVE_LIBZ */
948 #endif /* HAVE_LIBZ */
950 /* Oh, this is pretty */
951 #if defined(HAVE_UCD_SNMP_SNMP_H)
952 #ifdef HAVE_UCD_SNMP_VERSION_H
953 "with UCD SNMP ", VersionInfo
954 #else /* HAVE_UCD_SNMP_VERSION_H */
955 "with UCD SNMP ", "(version unknown)"
956 #endif /* HAVE_UCD_SNMP_VERSION_H */
957 #elif defined(HAVE_SNMP_SNMP_H)
958 #ifdef HAVE_SNMP_VERSION_H
959 "with CMU SNMP ", snmp_Version()
960 #else /* HAVE_SNMP_VERSION_H */
961 "with CMU SNMP ", "(version unknown)"
962 #endif /* HAVE_SNMP_VERSION_H */
968 /* Now get our args */
969 while ((opt = getopt(argc, argv, "B:c:Df:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
971 case 'B': /* Byte view pane height */
972 bv_size = atoi(optarg);
974 case 'c': /* Capture xxx packets */
976 cfile.count = atoi(optarg);
978 capture_option_specified = TRUE;
985 g_free(cfile.cfilter);
986 cfile.cfilter = g_strdup(optarg);
988 capture_option_specified = TRUE;
992 case 'h': /* Print help and exit */
996 case 'i': /* Use interface xxx */
998 cfile.iface = g_strdup(optarg);
1000 capture_option_specified = TRUE;
1004 case 'k': /* Start capture immediately */
1006 start_capture = TRUE;
1008 capture_option_specified = TRUE;
1012 case 'm': /* Fixed-width font for the display */
1013 if (prefs->gui_font_name != NULL)
1014 g_free(prefs->gui_font_name);
1015 prefs->gui_font_name = g_strdup(optarg);
1017 case 'n': /* No name resolution */
1018 g_resolving_actif = 0;
1020 case 'o': /* Override preference from command line */
1021 switch (prefs_set_pref(optarg)) {
1023 case PREFS_SET_SYNTAX_ERR:
1024 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1028 case PREFS_SET_NO_SUCH_PREF:
1029 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1035 case 'p': /* Don't capture in promiscuous mode */
1039 capture_option_specified = TRUE;
1043 case 'P': /* Packet list pane height */
1044 pl_size = atoi(optarg);
1046 case 'Q': /* Quit after capture (just capture to file) */
1049 start_capture = TRUE; /*** -Q implies -k !! ***/
1051 capture_option_specified = TRUE;
1055 case 'r': /* Read capture file xxx */
1056 /* We may set "last_open_dir" to "cf_name", and if we change
1057 "last_open_dir" later, we free the old value, so we have to
1058 set "cf_name" to something that's been allocated. */
1059 cf_name = g_strdup(optarg);
1061 case 'R': /* Read file filter */
1064 case 's': /* Set the snapshot (capture) length */
1066 cfile.snap = atoi(optarg);
1068 capture_option_specified = TRUE;
1072 case 'S': /* "Sync" mode: used for following file ala tail -f */
1076 capture_option_specified = TRUE;
1080 case 't': /* Time stamp type */
1081 if (strcmp(optarg, "r") == 0)
1082 timestamp_type = RELATIVE;
1083 else if (strcmp(optarg, "a") == 0)
1084 timestamp_type = ABSOLUTE;
1085 else if (strcmp(optarg, "d") == 0)
1086 timestamp_type = DELTA;
1088 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1090 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1091 fprintf(stderr, "or \"d\" for delta.\n");
1095 case 'T': /* Tree view pane height */
1096 tv_size = atoi(optarg);
1098 case 'v': /* Show version and exit */
1099 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1102 case 'w': /* Write to capture file xxx */
1104 save_file = g_strdup(optarg);
1106 capture_option_specified = TRUE;
1110 case 'W': /* Write to capture file FD xxx */
1112 cfile.save_file_fd = atoi(optarg);
1114 capture_option_specified = TRUE;
1120 case 'Z': /* Write to pipe FD XXX */
1122 /* associate stdout with pipe */
1124 if (dup2(i, 1) < 0) {
1125 fprintf(stderr, "Unable to dup pipe handle\n");
1129 capture_option_specified = TRUE;
1131 #endif /* HAVE_LIBPCAP */
1136 case '?': /* Bad flag - print usage message */
1143 /* Start windows sockets */
1144 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1147 /* Notify all registered modules that have had any of their preferences
1148 changed either from one of the preferences file or from the command
1149 line that its preferences have changed. */
1152 #ifndef HAVE_LIBPCAP
1153 if (capture_option_specified)
1154 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1159 if (start_capture) {
1160 /* We're supposed to do a live capture; did the user specify an interface
1162 if (cfile.iface == NULL) {
1163 /* No - pick the first one from the list of interfaces. */
1164 if_list = get_interface_list(&err, err_str);
1165 if (if_list == NULL) {
1168 case CANT_GET_INTERFACE_LIST:
1169 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1173 case NO_INTERFACES_FOUND:
1174 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1179 cfile.iface = g_strdup(if_list->data); /* first interface */
1180 free_interface_list(if_list);
1183 if (capture_child) {
1184 if (cfile.save_file_fd == -1) {
1185 /* XXX - send this to the standard output as something our parent
1186 should put in an error message box? */
1187 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1193 /* Build the column format array */
1194 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1195 cfile.cinfo.col_fmt[i] = get_column_format(i);
1196 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1197 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1199 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1200 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1201 cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1203 cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1207 cfile.snap = WTAP_MAX_PACKET_SIZE;
1208 else if (cfile.snap < MIN_PACKET_SIZE)
1209 cfile.snap = MIN_PACKET_SIZE;
1211 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1212 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1213 gtk_rc_parse(rc_file);
1215 /* Try to load the regular and boldface fixed-width fonts */
1216 bold_font_name = boldify(prefs->gui_font_name);
1217 m_r_font = gdk_font_load(prefs->gui_font_name);
1218 m_b_font = gdk_font_load(bold_font_name);
1219 if (m_r_font == NULL || m_b_font == NULL) {
1220 /* XXX - pop this up as a dialog box? no */
1221 if (m_r_font == NULL) {
1225 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1226 prefs->gui_font_name);
1228 gdk_font_unref(m_r_font);
1230 if (m_b_font == NULL) {
1234 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1237 gdk_font_unref(m_b_font);
1239 g_free(bold_font_name);
1240 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1241 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1244 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1245 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1248 g_free(prefs->gui_font_name);
1249 prefs->gui_font_name = g_strdup("6x13");
1252 create_main_window(pl_size, tv_size, bv_size, prefs);
1255 /* Is this a "child" ethereal, which is only supposed to pop up a
1256 capture box to let us stop the capture, and run a capture
1257 to a file that our parent will read? */
1258 if (!capture_child) {
1260 /* No. Pop up the main window, and read in a capture file if
1263 gtk_widget_show(top_level);
1264 set_menus_for_capture_file(FALSE);
1266 cfile.colors = colfilter_new();
1268 /* If we were given the name of a capture file, read it in now;
1269 we defer it until now, so that, if we can't open it, and pop
1270 up an alert box, the alert box is more likely to come up on
1271 top of the main window - but before the preference-file-error
1272 alert box, so, if we get one of those, it's more likely to come
1275 if (rfilter != NULL) {
1276 if (dfilter_compile(rfilter, &rfcode) != 0) {
1277 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1278 rfilter_parse_failed = TRUE;
1281 if (!rfilter_parse_failed) {
1282 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1283 /* "open_cap_file()" succeeded, so it closed the previous
1284 capture file, and thus destroyed any previous read filter
1285 attached to "cf". */
1286 cfile.rfcode = rfcode;
1287 switch (read_cap_file(&cfile, &err)) {
1291 /* Just because we got an error, that doesn't mean we were unable
1292 to read any of the file; we handle what we could get from the
1301 /* Save the name of the containing directory specified in the
1302 path name, if any; we can write over cf_name, which is a
1303 good thing, given that "get_dirname()" does write over its
1305 s = get_dirname(cf_name);
1309 dfilter_destroy(rfcode);
1310 cfile.rfcode = NULL;
1318 /* If the global preferences file exists but we failed to open it,
1319 pop up an alert box; we defer that until now, so that the alert
1320 box is more likely to come up on top of the main window. */
1321 if (gpf_path != NULL) {
1322 simple_dialog(ESD_TYPE_WARN, NULL,
1323 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1324 strerror(gpf_open_errno));
1327 /* If the user's preferences file exists but we failed to open it,
1328 pop up an alert box; we defer that until now, so that the alert
1329 box is more likely to come up on top of the main window. */
1330 if (pf_path != NULL) {
1331 simple_dialog(ESD_TYPE_WARN, NULL,
1332 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1333 strerror(pf_open_errno));
1337 if (capture_child) {
1338 /* This is the child process for a sync mode or fork mode capture,
1339 so just do the low-level work of a capture - don't create
1340 a temporary file and fork off *another* child process (so don't
1341 call "do_capture()"). */
1345 /* The capture is done; there's nothing more for us to do. */
1348 if (start_capture) {
1349 /* "-k" was specified; start a capture. */
1350 do_capture(save_file);
1353 set_menus_for_capture_in_progress(FALSE);
1357 set_menus_for_capture_in_progress(FALSE);
1366 /* Shutdown windows sockets */
1372 /* This isn't reached, but we need it to keep GCC from complaining
1373 that "main()" returns without returning a value - it knows that
1374 "exit()" never returns, but it doesn't know that "gtk_exit()"
1375 doesn't, as GTK+ doesn't declare it with the attribute
1377 return 0; /* not reached */
1382 /* We build this as a GUI subsystem application on Win32, so
1383 "WinMain()", not "main()", gets called.
1385 Hack shamelessly stolen from the Win32 port of the GIMP. */
1387 #define _stdcall __attribute__((stdcall))
1391 WinMain (struct HINSTANCE__ *hInstance,
1392 struct HINSTANCE__ *hPrevInstance,
1396 return main (__argc, __argv);
1401 /* Given a font name, construct the name of the next heavier version of
1404 #define XLFD_WEIGHT 3 /* index of the "weight" field */
1406 /* Map from a given weight to the appropriate weight for the "bold"
1408 XXX - the XLFD says these strings shouldn't be used for font matching;
1409 can we get the weight, as a number, from GDK, and ask GDK to find us
1410 a font just like the given font, but with the appropriate higher
1412 static const struct {
1416 { "ultralight", "light" },
1417 { "extralight", "semilight" },
1418 { "light", "medium" },
1419 { "semilight", "semibold" },
1420 { "medium", "bold" },
1421 { "normal", "bold" },
1422 { "semibold", "extrabold" },
1423 { "bold", "ultrabold" }
1425 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
1428 boldify(const char *font_name)
1430 char *bold_font_name;
1431 gchar **xlfd_tokens;
1434 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
1435 if (font_name[0] == '-') {
1436 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
1437 for (i = 0; i < N_WEIGHTS; i++) {
1438 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
1439 weight_map[i].light) == 0) {
1440 g_free(xlfd_tokens[XLFD_WEIGHT]);
1441 xlfd_tokens[XLFD_WEIGHT] =
1442 g_strdup(weight_map[i].heavier);
1446 bold_font_name = g_strjoinv("-", xlfd_tokens);
1447 g_strfreev(xlfd_tokens);
1449 /* Append "bold" to the name of the font. */
1450 bold_font_name = g_strconcat(font_name, "bold", NULL);
1452 return bold_font_name;
1456 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1458 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1460 *filter_bt, *filter_cm, *filter_te,
1462 GList *filter_list = NULL;
1463 GtkAccelGroup *accel;
1467 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1468 gtk_widget_set_name(top_level, "main window");
1469 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1470 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1471 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1472 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1473 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1475 /* Container for menu bar, paned windows and progress/info box */
1476 main_vbox = gtk_vbox_new(FALSE, 1);
1477 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1478 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1479 gtk_widget_show(main_vbox);
1482 get_main_menu(&menubar, &accel);
1483 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1484 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1485 gtk_widget_show(menubar);
1487 /* Panes for the packet list, tree, and byte view */
1488 u_pane = gtk_vpaned_new();
1489 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1490 l_pane = gtk_vpaned_new();
1491 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1492 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1493 gtk_widget_show(l_pane);
1494 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1495 gtk_widget_show(u_pane);
1498 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1499 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1500 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1501 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1502 remember_scrolled_window(pkt_scrollw);
1503 gtk_widget_show(pkt_scrollw);
1504 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1506 packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1507 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1509 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1510 set_plist_font(m_r_font);
1511 gtk_widget_set_name(packet_list, "packet list");
1512 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1513 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1514 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1515 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1516 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1517 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1518 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1519 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1520 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1522 /* Right-justify the packet number column. */
1523 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1524 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1527 gtk_widget_set_usize(packet_list, -1, pl_size);
1528 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1529 GTK_SIGNAL_FUNC(popup_menu_handler),
1530 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1531 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1532 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
1533 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1534 gtk_widget_show(packet_list);
1537 item_style = gtk_style_new();
1538 gdk_font_unref(item_style->font);
1539 item_style->font = m_r_font;
1540 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1541 prefs->gui_scrollbar_on_right);
1542 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1543 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1544 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1545 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1546 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
1547 GTK_SIGNAL_FUNC(popup_menu_handler),
1548 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1549 gtk_widget_show(tree_view);
1552 create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1553 prefs->gui_scrollbar_on_right);
1554 gtk_signal_connect(GTK_OBJECT(byte_view), "button_press_event",
1555 GTK_SIGNAL_FUNC(popup_menu_handler),
1556 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
1558 /* Filter/info box */
1559 stat_hbox = gtk_hbox_new(FALSE, 1);
1560 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1561 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1562 gtk_widget_show(stat_hbox);
1564 filter_bt = gtk_button_new_with_label("Filter:");
1565 /* A non-null pointer passed to "filter_browse_cb()" causes it to
1566 give the dialog box it pops up an "Apply" button. */
1567 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1568 GTK_SIGNAL_FUNC(filter_browse_cb), "");
1569 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1570 gtk_widget_show(filter_bt);
1572 filter_cm = gtk_combo_new();
1573 filter_list = g_list_append (filter_list, "");
1574 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1575 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1576 filter_te = GTK_COMBO(filter_cm)->entry;
1577 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1578 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1579 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1580 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1581 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1582 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1583 gtk_widget_show(filter_cm);
1585 filter_reset = gtk_button_new_with_label("Reset");
1586 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1587 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1588 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1589 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1590 gtk_widget_show(filter_reset);
1592 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1593 * of any widget that ends up calling a callback which needs
1594 * that text entry pointer */
1595 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1596 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1597 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1598 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1599 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1601 info_bar = gtk_statusbar_new();
1602 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1603 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1604 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
1605 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1606 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1607 gtk_widget_show(info_bar);