3 * $Id: main.c,v 1.181 2001/03/02 17:44:07 gram Exp $
5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@ethereal.com>
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>
80 #ifdef NEED_SNPRINTF_H
81 # include "snprintf.h"
84 #if defined(HAVE_UCD_SNMP_SNMP_H)
85 #ifdef HAVE_UCD_SNMP_VERSION_H
86 #include <ucd-snmp/version.h>
87 #endif /* HAVE_UCD_SNMP_VERSION_H */
88 #elif defined(HAVE_SNMP_SNMP_H)
89 #ifdef HAVE_SNMP_VERSION_H
90 #include <snmp/version.h>
91 #endif /* HAVE_SNMP_VERSION_H */
94 #ifdef NEED_STRERROR_H
102 #ifdef WIN32 /* Needed for console I/O */
110 #include "timestamp.h"
119 #include "color_utils.h"
120 #include "filter_prefs.h"
121 #include "prefs_dlg.h"
126 #include "simple_dialog.h"
127 #include "proto_draw.h"
128 #include "dfilter/dfilter.h"
130 #include "packet_win.h"
131 #include "gtkglobals.h"
138 GtkWidget *top_level, *packet_list, *tree_view, *byte_view,
139 *info_bar, *tv_scrollw, *pkt_scrollw;
140 static GtkWidget *bv_scrollw;
141 GdkFont *m_r_font, *m_b_font;
142 guint main_ctx, file_ctx, help_ctx;
143 gchar comp_info_str[256];
144 gchar *ethereal_path = NULL;
145 gchar *last_open_dir = NULL;
147 ts_type timestamp_type = RELATIVE;
149 GtkStyle *item_style;
151 /* Specifies the field currently selected in the GUI protocol tree */
152 field_info *finfo_selected = NULL;
155 static gboolean has_no_console; /* TRUE if app has no console */
156 static gboolean console_was_created; /* TRUE if console was created */
157 static void create_console(void);
158 static void destroy_console(void);
159 static void console_log_handler(const char *log_domain,
160 GLogLevelFlags log_level, const char *message, gpointer user_data);
163 static void create_main_window(gint, gint, gint, e_prefs*);
165 /* About Ethereal window */
167 about_ethereal( GtkWidget *w, gpointer data ) {
168 simple_dialog(ESD_TYPE_INFO, NULL,
169 "Ethereal - Network Protocol Analyzer\n"
170 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
171 "Compiled with %s\n\n"
173 "Check the man page for complete documentation and\n"
174 "for the list of contributors.\n"
176 "\nSee http://www.ethereal.com/ for more information.",
181 /* Match selected byte pattern */
183 match_selected_cb(GtkWidget *w, gpointer data)
186 GtkWidget *filter_te;
188 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
190 if (!finfo_selected) {
191 simple_dialog(ESD_TYPE_CRIT, NULL,
192 "Error determining selected bytes. Please make\n"
193 "sure you have selected a field within the tree\n"
194 "view to be matched.");
198 buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
200 /* create a new one and set the display filter entry accordingly */
201 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
203 /* Run the display filter so it goes in effect. */
204 filter_packets(&cfile, buf);
206 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
211 /* Run the current display filter on the current packet set, and
214 filter_activate_cb(GtkWidget *w, gpointer data)
216 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
217 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
218 GList *li, *nl = NULL;
219 gboolean add_filter = TRUE;
221 char *s = gtk_entry_get_text(GTK_ENTRY(w));
223 /* GtkCombos don't let us get at their list contents easily, so we maintain
224 our own filter list, and feed it to gtk_combo_set_popdown_strings when
225 a new filter is added. */
226 if (filter_packets(&cfile, g_strdup(s))) {
227 li = g_list_first(filter_list);
229 if (li->data && strcmp(s, li->data) == 0)
235 filter_list = g_list_append(filter_list, g_strdup(s));
236 li = g_list_first(filter_list);
238 nl = g_list_append(nl, strdup(li->data));
241 gtk_combo_set_popdown_strings(filter_cm, nl);
242 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
247 /* redisplay with no display filter */
249 filter_reset_cb(GtkWidget *w, gpointer data)
251 GtkWidget *filter_te = NULL;
253 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
254 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
257 filter_packets(&cfile, NULL);
260 /* GTKClist compare routine, overrides default to allow numeric comparison */
262 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
264 /* Get row text strings */
265 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
266 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
268 /* Attempt to convert to numbers */
269 double num1 = atof(text1);
270 double num2 = atof(text2);
272 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
274 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
275 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
276 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
277 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
278 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
279 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
280 (col_fmt == COL_PACKET_LENGTH)) {
282 /* Compare numeric column */
286 else if (num1 > num2)
294 /* Compare text column */
296 return (text1 != NULL);
301 return strcmp(text1, text2);
305 /* What to do when a column is clicked */
307 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
309 if (column == clist->sort_column) {
310 if (clist->sort_type == GTK_SORT_ASCENDING)
311 clist->sort_type = GTK_SORT_DESCENDING;
313 clist->sort_type = GTK_SORT_ASCENDING;
316 clist->sort_type = GTK_SORT_ASCENDING;
317 gtk_clist_set_sort_column(clist, column);
320 gtk_clist_sort(clist);
325 set_frame_mark(gboolean set, frame_data *frame, gint row) {
328 if (frame == NULL || row == -1) return;
329 frame->flags.marked = set;
331 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
332 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
337 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
338 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
342 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data) {
344 GdkEventButton *event_button = (GdkEventButton *)event;
347 if (w == NULL || event == NULL)
350 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
351 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
353 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
354 set_frame_mark(!fdata->flags.marked, fdata, row);
358 void mark_frame_cb(GtkWidget *w, gpointer data) {
359 if (cfile.current_frame) {
360 /* XXX hum, should better have a "cfile->current_row" here ... */
361 set_frame_mark(!cfile.current_frame->flags.marked,
363 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
364 cfile.current_frame));
368 static void mark_all_frames(gboolean set) {
370 if (cfile.plist == NULL) return;
371 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
374 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
378 void update_marked_frames(void) {
380 if (cfile.plist == NULL) return;
381 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
382 if (fdata->flags.marked)
385 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
390 void mark_all_frames_cb(GtkWidget *w, gpointer data) {
391 mark_all_frames(TRUE);
394 void unmark_all_frames_cb(GtkWidget *w, gpointer data) {
395 mark_all_frames(FALSE);
398 /* What to do when a list item is selected/unselected */
400 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
403 select_packet(&cfile, row);
407 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
408 unselect_packet(&cfile);
412 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
415 gchar *help_str = NULL;
416 gboolean has_blurb = FALSE;
420 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
423 finfo_selected = finfo;
425 set_menus_for_selected_tree_row(TRUE);
427 /*if (finfo->hfinfo && finfo->hfinfo->type != FT_TEXT_ONLY) {*/
429 if (finfo->hfinfo->blurb != NULL &&
430 finfo->hfinfo->blurb[0] != '\0') {
432 length = strlen(finfo->hfinfo->blurb);
434 length = strlen(finfo->hfinfo->name);
436 length += strlen(finfo->hfinfo->abbrev) + 10;
437 help_str = g_malloc(sizeof(gchar) * length);
438 sprintf(help_str, "%s (%s)",
439 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
440 finfo->hfinfo->abbrev);
441 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, help_str);
445 packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame,
450 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
452 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
453 finfo_selected = NULL;
454 set_menus_for_selected_tree_row(FALSE);
455 packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame,
459 void collapse_all_cb(GtkWidget *widget, gpointer data) {
460 if (cfile.protocol_tree)
461 collapse_all_tree(cfile.protocol_tree, tree_view);
464 void expand_all_cb(GtkWidget *widget, gpointer data) {
465 if (cfile.protocol_tree)
466 expand_all_tree(cfile.protocol_tree, tree_view);
469 void resolve_name_cb(GtkWidget *widget, gpointer data) {
470 if (cfile.protocol_tree) {
471 int tmp = g_resolving_actif;
472 g_resolving_actif = 1;
473 gtk_clist_clear ( GTK_CLIST(tree_view) );
474 proto_tree_draw(cfile.protocol_tree, tree_view);
475 g_resolving_actif = tmp;
479 /* Set the scrollbar placement of a scrolled window based upon pos value:
480 0 = left, 1 = right */
482 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
485 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
486 GTK_CORNER_TOP_LEFT);
488 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
489 GTK_CORNER_TOP_RIGHT);
493 /* List of all scrolled windows, so we can globally set the scrollbar
494 placement of them. */
495 static GList *scrolled_windows;
497 /* Add a scrolled window to the list of scrolled windows. */
498 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
501 remember_scrolled_window(GtkWidget *scrollw)
503 scrolled_windows = g_list_append(scrolled_windows, scrollw);
505 /* Catch the "destroy" event on the widget, so that we remove it from
506 the list when it's destroyed. */
507 gtk_signal_connect(GTK_OBJECT(scrollw), "destroy",
508 GTK_SIGNAL_FUNC(forget_scrolled_window), NULL);
511 /* Remove a scrolled window from the list of scrolled windows. */
513 forget_scrolled_window(GtkWidget *scrollw, gpointer data)
515 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
519 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
521 set_scrollbar_placement_scrollw((GtkWidget *)data,
525 /* Set the scrollbar placement of all scrolled windows based on pos value:
526 0 = left, 1 = right */
528 set_scrollbar_placement_all(int pos)
530 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
533 /* Set the selection mode of the packet list window. */
535 set_plist_sel_browse(gboolean val)
540 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
542 if (val == old_val) {
544 * The mode isn't changing, so don't do anything.
545 * In particular, don't gratuitiously unselect the
548 * XXX - why do we have to unselect the current packet
549 * ourselves? The documentation for the GtkCList at
551 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
553 * says "Note that setting the widget's selection mode to
554 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
555 * cause all the items in the GtkCList to become deselected."
561 unselect_packet(&cfile);
563 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
564 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
566 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
569 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
573 /* Set the font of the packet list window. */
575 set_plist_font(GdkFont *font)
580 style = gtk_style_new();
581 gdk_font_unref(style->font);
585 gtk_widget_set_style(packet_list, style);
587 /* Compute static column sizes to use during a "-S" capture, so that
588 the columns don't resize during a live capture. */
589 for (i = 0; i < cfile.cinfo.num_cols; i++) {
590 cfile.cinfo.col_width[i] = gdk_string_width(font,
591 get_column_longest_string(get_column_format(i)));
596 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
598 file_quit_cmd_cb(widget, data);
600 /* Say that the window should be deleted. */
605 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
607 /* XXX - should we check whether the capture file is an
608 unsaved temporary file for a live capture and, if so,
609 pop up a "do you want to exit without saving the capture
610 file?" dialog, and then just return, leaving said dialog
611 box to forcibly quit if the user clicks "OK"?
613 If so, note that this should be done in a subroutine that
614 returns TRUE if we do so, and FALSE otherwise, and that
615 "main_window_delete_event_cb()" should return its
618 /* Are we in the middle of reading a capture? */
619 if (cfile.state == FILE_READ_IN_PROGRESS) {
620 /* Yes, so we can't just close the file and quit, as
621 that may yank the rug out from under the read in
622 progress; instead, just set the state to
623 "FILE_READ_ABORTED" and return - the code doing the read
624 will check for that and, if it sees that, will clean
626 cfile.state = FILE_READ_ABORTED;
628 /* Close any capture file we have open; on some OSes, you
629 can't unlink a temporary capture file if you have it
631 "close_cap_file()" will unlink it after closing it if
632 it's a temporary file.
634 We do this here, rather than after the main loop returns,
635 as, after the main loop returns, the main window may have
636 been destroyed (if this is called due to a "destroy"
637 even on the main window rather than due to the user
638 selecting a menu item), and there may be a crash
639 or other problem when "close_cap_file()" tries to
640 clean up stuff in the main window.
642 XXX - is there a better place to put this?
643 Or should we have a routine that *just* closes the
644 capture file, and doesn't do anything with the UI,
645 which we'd call here, and another routine that
646 calls that routine and also cleans up the UI, which
647 we'd call elsewhere? */
648 close_cap_file(&cfile, info_bar);
650 /* Exit by leaving the main loop, so that any quit functions
651 we registered get called. */
659 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
662 fprintf(stderr, "%s [ -vh ] [ -kpQS ] [ -B <byte view height> ] [ -c count ]\n",
664 fprintf(stderr, "\t[ -f <capture filter> ] [ -i interface ] [ -m <medium font> ] \n");
665 fprintf(stderr, "\t[ -n ] [ -o <preference setting> ] ... [ -P <packet list height> ]\n");
666 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -s snaplen ] \n");
667 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ] [ -w savefile ]\n");
669 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ] [ -n ]\n",
671 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
672 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
673 fprintf(stderr, "\t[ -T <tree view height> ]\n");
684 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
687 /* And now our feature presentation... [ fade to music ] */
689 main(int argc, char *argv[])
698 gboolean arg_error = FALSE;
702 char pcap_version[] = "0.4a6";
704 extern char pcap_version[];
712 char *gpf_path, *pf_path, *cf_path, *df_path;
713 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
716 gboolean start_capture = FALSE;
717 gchar *save_file = NULL;
719 gchar err_str[PCAP_ERRBUF_SIZE];
720 gboolean stats_known;
721 struct pcap_stat stats;
723 gboolean capture_option_specified = FALSE;
725 gint pl_size = 280, tv_size = 95, bv_size = 75;
726 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
727 dfilter_t *rfcode = NULL;
728 gboolean rfilter_parse_failed = FALSE;
730 char *bold_font_name;
732 ethereal_path = argv[0];
735 /* Arrange that if we have no console window, and a GLib message logging
736 routine is called to log a message, we pop up a console window.
738 We do that by inserting our own handler for all messages logged
739 to the default domain; that handler pops up a console if necessary,
740 and then calls the default handler. */
741 g_log_set_handler(NULL,
743 G_LOG_LEVEL_CRITICAL|
748 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
749 console_log_handler, NULL);
753 command_name = get_basename(ethereal_path);
754 /* Set "capture_child" to indicate whether this is going to be a child
755 process for a "-S" capture. */
756 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
759 /* Register all dissectors; we must do this before checking for the
760 "-G" flag, as the "-G" flag dumps a list of fields registered
761 by the dissectors, and we must do it before we read the preferences,
762 in case any dissectors register preferences. */
763 epan_init(PLUGIN_DIR);
765 /* Now register the preferences for any non-dissector modules.
766 We must do that before we read the preferences as well. */
767 prefs_register_modules();
769 /* If invoked with the "-G" flag, we dump out a glossary of
770 display filter symbols.
772 We must do this before calling "gtk_init()", because "gtk_init()"
773 tries to open an X display, and we don't want to have to do any X
774 stuff just to do a build.
776 Given that we call "gtk_init()" before doing the regular argument
777 list processing, so that it can handle X and GTK+ arguments and
778 remove them from the list at which we look, this means we must do
779 this before doing the regular argument list processing, as well.
783 you must give the "-G" flag as the first flag on the command line;
785 you must give it as "-G", nothing more, nothing less;
787 any arguments after the "-G" flag will not be used. */
788 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
789 proto_registrar_dump();
793 /* Set the current locale according to the program environment.
794 * We haven't localized anything, but some GTK widgets are localized
795 * (the file selection dialogue, for example).
796 * This also sets the C-language locale to the native environment. */
799 /* Let GTK get its args */
800 gtk_init (&argc, &argv);
802 /* Read the preference files. */
803 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
805 /* Read the capture filter file. */
806 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
808 /* Read the display filter file. */
809 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
811 /* Initialize the capture file struct */
813 cfile.plist_end = NULL;
815 cfile.filename = NULL;
816 cfile.user_saved = FALSE;
817 cfile.is_tempfile = FALSE;
819 cfile.dfilter = NULL;
822 cfile.cfilter = g_strdup(EMPTY_FILTER);
825 cfile.save_file = NULL;
826 cfile.save_file_fd = -1;
827 cfile.snap = WTAP_MAX_PACKET_SIZE;
829 col_init(&cfile.cinfo, prefs->num_cols);
831 /* Assemble the compile-time options */
832 snprintf(comp_info_str, 256,
833 #ifdef GTK_MAJOR_VERSION
834 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
837 "GTK+ (version unknown), %s%s, %s%s, %s%s",
841 "with libpcap ", pcap_version,
843 "without libpcap", "",
848 "with libz ", ZLIB_VERSION,
849 #else /* ZLIB_VERSION */
850 "with libz ", "(version unknown)",
851 #endif /* ZLIB_VERSION */
852 #else /* HAVE_LIBZ */
854 #endif /* HAVE_LIBZ */
856 /* Oh, this is pretty */
857 #if defined(HAVE_UCD_SNMP_SNMP_H)
858 #ifdef HAVE_UCD_SNMP_VERSION_H
859 "with UCD SNMP ", VersionInfo
860 #else /* HAVE_UCD_SNMP_VERSION_H */
861 "with UCD SNMP ", "(version unknown)"
862 #endif /* HAVE_UCD_SNMP_VERSION_H */
863 #elif defined(HAVE_SNMP_SNMP_H)
864 #ifdef HAVE_SNMP_VERSION_H
865 "with CMU SNMP ", snmp_Version()
866 #else /* HAVE_SNMP_VERSION_H */
867 "with CMU SNMP ", "(version unknown)"
868 #endif /* HAVE_SNMP_VERSION_H */
874 /* Now get our args */
875 while ((opt = getopt(argc, argv, "B:c:Df:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
877 case 'B': /* Byte view pane height */
878 bv_size = atoi(optarg);
880 case 'c': /* Capture xxx packets */
882 cfile.count = atoi(optarg);
884 capture_option_specified = TRUE;
891 g_free(cfile.cfilter);
892 cfile.cfilter = g_strdup(optarg);
894 capture_option_specified = TRUE;
898 case 'h': /* Print help and exit */
902 case 'i': /* Use interface xxx */
904 cfile.iface = g_strdup(optarg);
906 capture_option_specified = TRUE;
910 case 'k': /* Start capture immediately */
912 start_capture = TRUE;
914 capture_option_specified = TRUE;
918 case 'm': /* Fixed-width font for the display */
919 if (prefs->gui_font_name != NULL)
920 g_free(prefs->gui_font_name);
921 prefs->gui_font_name = g_strdup(optarg);
923 case 'n': /* No name resolution */
924 g_resolving_actif = 0;
926 case 'o': /* Override preference from command line */
927 switch (prefs_set_pref(optarg)) {
929 case PREFS_SET_SYNTAX_ERR:
930 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
934 case PREFS_SET_NO_SUCH_PREF:
935 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
941 case 'p': /* Don't capture in promiscuous mode */
945 capture_option_specified = TRUE;
949 case 'P': /* Packet list pane height */
950 pl_size = atoi(optarg);
952 case 'Q': /* Quit after capture (just capture to file) */
955 start_capture = TRUE; /*** -Q implies -k !! ***/
957 capture_option_specified = TRUE;
961 case 'r': /* Read capture file xxx */
962 /* We may set "last_open_dir" to "cf_name", and if we change
963 "last_open_dir" later, we free the old value, so we have to
964 set "cf_name" to something that's been allocated. */
965 cf_name = g_strdup(optarg);
967 case 'R': /* Read file filter */
970 case 's': /* Set the snapshot (capture) length */
972 cfile.snap = atoi(optarg);
974 capture_option_specified = TRUE;
978 case 'S': /* "Sync" mode: used for following file ala tail -f */
982 capture_option_specified = TRUE;
986 case 't': /* Time stamp type */
987 if (strcmp(optarg, "r") == 0)
988 timestamp_type = RELATIVE;
989 else if (strcmp(optarg, "a") == 0)
990 timestamp_type = ABSOLUTE;
991 else if (strcmp(optarg, "ad") == 0)
992 timestamp_type = ABSOLUTE_WITH_DATE;
993 else if (strcmp(optarg, "d") == 0)
994 timestamp_type = DELTA;
996 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
998 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
999 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1003 case 'T': /* Tree view pane height */
1004 tv_size = atoi(optarg);
1006 case 'v': /* Show version and exit */
1009 if (console_was_created)
1014 case 'w': /* Write to capture file xxx */
1016 save_file = g_strdup(optarg);
1018 capture_option_specified = TRUE;
1022 case 'W': /* Write to capture file FD xxx */
1024 cfile.save_file_fd = atoi(optarg);
1026 capture_option_specified = TRUE;
1032 case 'Z': /* Write to pipe FD XXX */
1034 /* associate stdout with pipe */
1036 if (dup2(i, 1) < 0) {
1037 fprintf(stderr, "Unable to dup pipe handle\n");
1041 capture_option_specified = TRUE;
1043 #endif /* HAVE_LIBPCAP */
1048 case '?': /* Bad flag - print usage message */
1055 /* Start windows sockets */
1056 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1059 /* Notify all registered modules that have had any of their preferences
1060 changed either from one of the preferences file or from the command
1061 line that its preferences have changed. */
1064 #ifndef HAVE_LIBPCAP
1065 if (capture_option_specified)
1066 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1071 if (start_capture) {
1072 /* We're supposed to do a live capture; did the user specify an interface
1074 if (cfile.iface == NULL) {
1075 /* No - pick the first one from the list of interfaces. */
1076 if_list = get_interface_list(&err, err_str);
1077 if (if_list == NULL) {
1080 case CANT_GET_INTERFACE_LIST:
1081 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1085 case NO_INTERFACES_FOUND:
1086 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1091 cfile.iface = g_strdup(if_list->data); /* first interface */
1092 free_interface_list(if_list);
1095 if (capture_child) {
1096 if (cfile.save_file_fd == -1) {
1097 /* XXX - send this to the standard output as something our parent
1098 should put in an error message box? */
1099 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1105 /* Build the column format array */
1106 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1107 cfile.cinfo.col_fmt[i] = get_column_format(i);
1108 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1109 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1111 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1112 cfile.cinfo.col_data[i] = NULL;
1113 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1114 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1116 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1120 cfile.snap = WTAP_MAX_PACKET_SIZE;
1121 else if (cfile.snap < MIN_PACKET_SIZE)
1122 cfile.snap = MIN_PACKET_SIZE;
1124 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1125 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1126 gtk_rc_parse(rc_file);
1128 /* Try to load the regular and boldface fixed-width fonts */
1129 bold_font_name = boldify(prefs->gui_font_name);
1130 m_r_font = gdk_font_load(prefs->gui_font_name);
1131 m_b_font = gdk_font_load(bold_font_name);
1132 if (m_r_font == NULL || m_b_font == NULL) {
1133 /* XXX - pop this up as a dialog box? no */
1134 if (m_r_font == NULL) {
1138 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1139 prefs->gui_font_name);
1141 gdk_font_unref(m_r_font);
1143 if (m_b_font == NULL) {
1147 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1150 gdk_font_unref(m_b_font);
1152 g_free(bold_font_name);
1153 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1154 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1157 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1158 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1161 g_free(prefs->gui_font_name);
1162 prefs->gui_font_name = g_strdup("6x13");
1167 /* Is this a "child" ethereal, which is only supposed to pop up a
1168 capture box to let us stop the capture, and run a capture
1169 to a file that our parent will read? */
1170 if (!capture_child) {
1172 /* No. Pop up the main window, and read in a capture file if
1175 create_main_window(pl_size, tv_size, bv_size, prefs);
1176 set_menus_for_capture_file(FALSE);
1178 cfile.colors = colfilter_new();
1180 /* If we were given the name of a capture file, read it in now;
1181 we defer it until now, so that, if we can't open it, and pop
1182 up an alert box, the alert box is more likely to come up on
1183 top of the main window - but before the preference-file-error
1184 alert box, so, if we get one of those, it's more likely to come
1187 if (rfilter != NULL) {
1188 if (!dfilter_compile(rfilter, &rfcode)) {
1189 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1190 rfilter_parse_failed = TRUE;
1193 if (!rfilter_parse_failed) {
1194 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1195 /* "open_cap_file()" succeeded, so it closed the previous
1196 capture file, and thus destroyed any previous read filter
1197 attached to "cf". */
1198 cfile.rfcode = rfcode;
1199 switch (read_cap_file(&cfile, &err)) {
1203 /* Just because we got an error, that doesn't mean we were unable
1204 to read any of the file; we handle what we could get from the
1213 /* Save the name of the containing directory specified in the
1214 path name, if any; we can write over cf_name, which is a
1215 good thing, given that "get_dirname()" does write over its
1217 s = get_dirname(cf_name);
1222 dfilter_free(rfcode);
1223 cfile.rfcode = NULL;
1231 /* If the global preferences file exists but we failed to open it,
1232 pop up an alert box; we defer that until now, so that the alert
1233 box is more likely to come up on top of the main window. */
1234 if (gpf_path != NULL) {
1235 simple_dialog(ESD_TYPE_WARN, NULL,
1236 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1237 strerror(gpf_open_errno));
1240 /* If the user's preferences file exists but we failed to open it,
1241 pop up an alert box; we defer that until now, so that the alert
1242 box is more likely to come up on top of the main window. */
1243 if (pf_path != NULL) {
1244 simple_dialog(ESD_TYPE_WARN, NULL,
1245 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1246 strerror(pf_open_errno));
1249 /* If the user's capture filter file exists but we failed to open it,
1250 pop up an alert box; we defer that until now, so that the alert
1251 box is more likely to come up on top of the main window. */
1252 if (cf_path != NULL) {
1253 simple_dialog(ESD_TYPE_WARN, NULL,
1254 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1255 strerror(cf_open_errno));
1259 /* If the user's display filter file exists but we failed to open it,
1260 pop up an alert box; we defer that until now, so that the alert
1261 box is more likely to come up on top of the main window. */
1262 if (df_path != NULL) {
1263 simple_dialog(ESD_TYPE_WARN, NULL,
1264 "Could not open your display filter file\n\"%s\": %s.", df_path,
1265 strerror(df_open_errno));
1270 if (capture_child) {
1271 /* This is the child process for a sync mode or fork mode capture,
1272 so just do the low-level work of a capture - don't create
1273 a temporary file and fork off *another* child process (so don't
1274 call "do_capture()"). */
1276 /* XXX - hand these stats to the parent process */
1277 capture(&stats_known, &stats);
1279 /* The capture is done; there's nothing more for us to do. */
1282 if (start_capture) {
1283 /* "-k" was specified; start a capture. */
1284 do_capture(save_file);
1287 set_menus_for_capture_in_progress(FALSE);
1291 set_menus_for_capture_in_progress(FALSE);
1300 /* Shutdown windows sockets */
1303 /* For some unknown reason, the "atexit()" call in "create_console()"
1304 doesn't arrange that "destroy_console()" be called when we exit,
1305 so we call it here if a console was created. */
1306 if (console_was_created)
1312 /* This isn't reached, but we need it to keep GCC from complaining
1313 that "main()" returns without returning a value - it knows that
1314 "exit()" never returns, but it doesn't know that "gtk_exit()"
1315 doesn't, as GTK+ doesn't declare it with the attribute
1317 return 0; /* not reached */
1322 /* We build this as a GUI subsystem application on Win32, so
1323 "WinMain()", not "main()", gets called.
1325 Hack shamelessly stolen from the Win32 port of the GIMP. */
1327 #define _stdcall __attribute__((stdcall))
1331 WinMain (struct HINSTANCE__ *hInstance,
1332 struct HINSTANCE__ *hPrevInstance,
1336 has_no_console = TRUE;
1337 return main (__argc, __argv);
1341 * If this application has no console window to which its standard output
1342 * would go, create one.
1345 create_console(void)
1347 if (has_no_console) {
1348 /* We have no console to which to print the version string, so
1349 create one and make it the standard input, output, and error. */
1350 if (!AllocConsole())
1351 return; /* couldn't create console */
1352 freopen("CONIN$", "r", stdin);
1353 freopen("CONOUT$", "w", stdout);
1354 freopen("CONOUT$", "w", stderr);
1356 /* Well, we have a console now. */
1357 has_no_console = FALSE;
1358 console_was_created = TRUE;
1360 /* Now register "destroy_console()" as a routine to be called just
1361 before the application exits, so that we can destroy the console
1362 after the user has typed a key (so that the console doesn't just
1363 disappear out from under them, giving the user no chance to see
1364 the message(s) we put in there). */
1365 atexit(destroy_console);
1370 destroy_console(void)
1372 printf("\n\nPress any key to exit\n");
1377 /* This routine should not be necessary, at least as I read the GLib
1378 source code, as it looks as if GLib is, on Win32, *supposed* to
1379 create a console window into which to display its output.
1381 That doesn't happen, however. I suspect there's something completely
1382 broken about that code in GLib-for-Win32, and that it may be related
1383 to the breakage that forces us to just call "printf()" on the message
1384 rather than passing the message on to "g_log_default_handler()"
1385 (which is the routine that does the aforementioned non-functional
1386 console window creation). */
1388 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
1389 const char *message, gpointer user_data)
1392 if (console_was_created) {
1393 /* For some unknown reason, the above doesn't appear to actually cause
1394 anything to be sent to the standard output, so we'll just splat the
1395 message out directly, just to make sure it gets out. */
1396 printf("%s\n", message);
1398 g_log_default_handler(log_domain, log_level, message, user_data);
1402 /* Given a font name, construct the name of the next heavier version of
1405 #define XLFD_WEIGHT 3 /* index of the "weight" field */
1407 /* Map from a given weight to the appropriate weight for the "bold"
1409 XXX - the XLFD says these strings shouldn't be used for font matching;
1410 can we get the weight, as a number, from GDK, and ask GDK to find us
1411 a font just like the given font, but with the appropriate higher
1413 static const struct {
1417 { "ultralight", "light" },
1418 { "extralight", "semilight" },
1419 { "light", "medium" },
1420 { "semilight", "semibold" },
1421 { "medium", "bold" },
1422 { "normal", "bold" },
1423 { "semibold", "extrabold" },
1424 { "bold", "ultrabold" }
1426 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
1429 boldify(const char *font_name)
1431 char *bold_font_name;
1432 gchar **xlfd_tokens;
1435 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
1436 if (font_name[0] == '-') {
1437 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
1438 for (i = 0; i < N_WEIGHTS; i++) {
1439 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
1440 weight_map[i].light) == 0) {
1441 g_free(xlfd_tokens[XLFD_WEIGHT]);
1442 xlfd_tokens[XLFD_WEIGHT] =
1443 g_strdup(weight_map[i].heavier);
1447 bold_font_name = g_strjoinv("-", xlfd_tokens);
1448 g_strfreev(xlfd_tokens);
1450 /* Append "bold" to the name of the font. */
1451 bold_font_name = g_strconcat(font_name, "bold", NULL);
1453 return bold_font_name;
1457 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1459 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1461 *filter_bt, *filter_cm, *filter_te,
1463 GList *filter_list = NULL;
1464 GtkAccelGroup *accel;
1466 /* Display filter construct dialog has an Apply button, and "OK" not
1467 only sets our text widget, it activates it (i.e., it causes us to
1468 filter the capture). */
1469 static construct_args_t args = {
1470 "Ethereal: Display Filter",
1476 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1477 gtk_widget_set_name(top_level, "main window");
1478 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1479 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1480 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1481 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1482 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1484 /* Container for menu bar, paned windows and progress/info box */
1485 main_vbox = gtk_vbox_new(FALSE, 1);
1486 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1487 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1488 gtk_widget_show(main_vbox);
1491 get_main_menu(&menubar, &accel);
1492 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1493 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1494 gtk_widget_show(menubar);
1496 /* Panes for the packet list, tree, and byte view */
1497 u_pane = gtk_vpaned_new();
1498 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1499 l_pane = gtk_vpaned_new();
1500 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1501 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1502 gtk_widget_show(l_pane);
1503 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1504 gtk_widget_show(u_pane);
1507 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1508 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1509 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1510 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1511 remember_scrolled_window(pkt_scrollw);
1512 gtk_widget_show(pkt_scrollw);
1513 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1515 packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1516 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1518 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1519 set_plist_font(m_r_font);
1520 gtk_widget_set_name(packet_list, "packet list");
1521 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1522 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1523 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1524 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1525 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1526 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1527 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1528 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1529 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1531 /* Right-justify the packet number column. */
1532 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1533 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1536 gtk_widget_set_usize(packet_list, -1, pl_size);
1537 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1538 GTK_SIGNAL_FUNC(popup_menu_handler),
1539 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1540 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1541 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
1542 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1543 gtk_widget_show(packet_list);
1546 item_style = gtk_style_new();
1547 gdk_font_unref(item_style->font);
1548 item_style->font = m_r_font;
1549 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1550 prefs->gui_scrollbar_on_right);
1551 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1552 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1553 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1554 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1555 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
1556 GTK_SIGNAL_FUNC(popup_menu_handler),
1557 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1558 gtk_widget_show(tree_view);
1561 create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1562 prefs->gui_scrollbar_on_right);
1563 gtk_signal_connect(GTK_OBJECT(byte_view), "button_press_event",
1564 GTK_SIGNAL_FUNC(popup_menu_handler),
1565 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
1567 /* Filter/info box */
1568 stat_hbox = gtk_hbox_new(FALSE, 1);
1569 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1570 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1571 gtk_widget_show(stat_hbox);
1573 filter_bt = gtk_button_new_with_label("Filter:");
1574 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1575 GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
1576 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1577 gtk_widget_show(filter_bt);
1579 filter_cm = gtk_combo_new();
1580 filter_list = g_list_append (filter_list, "");
1581 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1582 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1583 filter_te = GTK_COMBO(filter_cm)->entry;
1584 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1585 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1586 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1587 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1588 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1589 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1590 gtk_widget_show(filter_cm);
1592 filter_reset = gtk_button_new_with_label("Reset");
1593 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1594 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1595 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1596 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1597 gtk_widget_show(filter_reset);
1599 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1600 * of any widget that ends up calling a callback which needs
1601 * that text entry pointer */
1602 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1603 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1604 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1605 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1606 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1608 info_bar = gtk_statusbar_new();
1609 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1610 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1611 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
1612 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1613 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1614 gtk_widget_show(info_bar);
1616 gtk_widget_show(top_level);