3 * $Id: main.c,v 1.183 2001/03/23 14:44:04 jfoster 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
11 * Jeff Foster, 2001/03/12, added support tabbed hex display windowss
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 * - Check for end of packet in dissect_* routines.
33 * - Multiple window support
34 * - Add cut/copy/paste
35 * - Create header parsing routines
36 * - Make byte view selections more fancy?
56 #ifdef HAVE_SYS_TYPES_H
57 #include <sys/types.h>
60 #ifdef HAVE_SYS_STAT_H
65 #include <io.h> /* open/close on win32 */
72 #ifdef HAVE_NETINET_IN_H
73 #include <netinet/in.h>
82 #ifdef NEED_SNPRINTF_H
83 # include "snprintf.h"
86 #if defined(HAVE_UCD_SNMP_SNMP_H)
87 #ifdef HAVE_UCD_SNMP_VERSION_H
88 #include <ucd-snmp/version.h>
89 #endif /* HAVE_UCD_SNMP_VERSION_H */
90 #elif defined(HAVE_SNMP_SNMP_H)
91 #ifdef HAVE_SNMP_VERSION_H
92 #include <snmp/version.h>
93 #endif /* HAVE_SNMP_VERSION_H */
96 #ifdef NEED_STRERROR_H
104 #ifdef WIN32 /* Needed for console I/O */
112 #include "timestamp.h"
121 #include "color_utils.h"
122 #include "filter_prefs.h"
123 #include "prefs_dlg.h"
128 #include "simple_dialog.h"
129 #include "proto_draw.h"
130 #include "dfilter/dfilter.h"
132 #include "packet_win.h"
133 #include "gtkglobals.h"
140 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
141 *info_bar, *tv_scrollw, *pkt_scrollw;
142 static GtkWidget *bv_scrollw;
143 GdkFont *m_r_font, *m_b_font;
144 guint m_font_height, m_font_width;
145 guint main_ctx, file_ctx, help_ctx;
146 gchar comp_info_str[256];
147 gchar *ethereal_path = NULL;
148 gchar *last_open_dir = NULL;
150 ts_type timestamp_type = RELATIVE;
152 GtkStyle *item_style;
154 /* Specifies the field currently selected in the GUI protocol tree */
155 field_info *finfo_selected = NULL;
158 static gboolean has_no_console; /* TRUE if app has no console */
159 static gboolean console_was_created; /* TRUE if console was created */
160 static void create_console(void);
161 static void destroy_console(void);
162 static void console_log_handler(const char *log_domain,
163 GLogLevelFlags log_level, const char *message, gpointer user_data);
166 static void create_main_window(gint, gint, gint, e_prefs*);
168 /* About Ethereal window */
170 about_ethereal( GtkWidget *w, gpointer data ) {
171 simple_dialog(ESD_TYPE_INFO, NULL,
172 "Ethereal - Network Protocol Analyzer\n"
173 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
174 "Compiled with %s\n\n"
176 "Check the man page for complete documentation and\n"
177 "for the list of contributors.\n"
179 "\nSee http://www.ethereal.com/ for more information.",
184 set_fonts(GdkFont *regular, GdkFont *bold)
186 /* Yes, assert. The code that loads the font should check
187 * for NULL and provide its own error message. */
188 g_assert(m_r_font && m_b_font);
192 m_font_height = m_r_font->ascent + m_r_font->descent;
193 m_font_width = gdk_string_width(m_r_font, "0");
197 /* Match selected byte pattern */
199 match_selected_cb(GtkWidget *w, gpointer data)
202 GtkWidget *filter_te;
204 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
206 if (!finfo_selected) {
207 simple_dialog(ESD_TYPE_CRIT, NULL,
208 "Error determining selected bytes. Please make\n"
209 "sure you have selected a field within the tree\n"
210 "view to be matched.");
214 buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
216 /* create a new one and set the display filter entry accordingly */
217 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
219 /* Run the display filter so it goes in effect. */
220 filter_packets(&cfile, buf);
222 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
227 /* Run the current display filter on the current packet set, and
230 filter_activate_cb(GtkWidget *w, gpointer data)
232 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
233 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
234 GList *li, *nl = NULL;
235 gboolean add_filter = TRUE;
237 char *s = gtk_entry_get_text(GTK_ENTRY(w));
239 /* GtkCombos don't let us get at their list contents easily, so we maintain
240 our own filter list, and feed it to gtk_combo_set_popdown_strings when
241 a new filter is added. */
242 if (filter_packets(&cfile, g_strdup(s))) {
243 li = g_list_first(filter_list);
245 if (li->data && strcmp(s, li->data) == 0)
251 filter_list = g_list_append(filter_list, g_strdup(s));
252 li = g_list_first(filter_list);
254 nl = g_list_append(nl, strdup(li->data));
257 gtk_combo_set_popdown_strings(filter_cm, nl);
258 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
263 /* redisplay with no display filter */
265 filter_reset_cb(GtkWidget *w, gpointer data)
267 GtkWidget *filter_te = NULL;
269 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
270 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
273 filter_packets(&cfile, NULL);
276 /* GTKClist compare routine, overrides default to allow numeric comparison */
278 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
280 /* Get row text strings */
281 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
282 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
284 /* Attempt to convert to numbers */
285 double num1 = atof(text1);
286 double num2 = atof(text2);
288 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
290 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
291 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
292 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
293 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
294 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
295 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
296 (col_fmt == COL_PACKET_LENGTH)) {
298 /* Compare numeric column */
302 else if (num1 > num2)
310 /* Compare text column */
312 return (text1 != NULL);
317 return strcmp(text1, text2);
321 /* What to do when a column is clicked */
323 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
325 if (column == clist->sort_column) {
326 if (clist->sort_type == GTK_SORT_ASCENDING)
327 clist->sort_type = GTK_SORT_DESCENDING;
329 clist->sort_type = GTK_SORT_ASCENDING;
332 clist->sort_type = GTK_SORT_ASCENDING;
333 gtk_clist_set_sort_column(clist, column);
336 gtk_clist_sort(clist);
341 set_frame_mark(gboolean set, frame_data *frame, gint row) {
344 if (frame == NULL || row == -1) return;
345 frame->flags.marked = set;
347 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
348 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
353 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
354 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
358 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data) {
360 GdkEventButton *event_button = (GdkEventButton *)event;
363 if (w == NULL || event == NULL)
366 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
367 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
369 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
370 set_frame_mark(!fdata->flags.marked, fdata, row);
374 void mark_frame_cb(GtkWidget *w, gpointer data) {
375 if (cfile.current_frame) {
376 /* XXX hum, should better have a "cfile->current_row" here ... */
377 set_frame_mark(!cfile.current_frame->flags.marked,
379 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
380 cfile.current_frame));
384 static void mark_all_frames(gboolean set) {
386 if (cfile.plist == NULL) return;
387 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
390 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
394 void update_marked_frames(void) {
396 if (cfile.plist == NULL) return;
397 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
398 if (fdata->flags.marked)
401 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
406 void mark_all_frames_cb(GtkWidget *w, gpointer data) {
407 mark_all_frames(TRUE);
410 void unmark_all_frames_cb(GtkWidget *w, gpointer data) {
411 mark_all_frames(FALSE);
414 /* What to do when a list item is selected/unselected */
416 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
420 /* Remove the hex display tabbed pages */
421 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
422 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
424 select_packet(&cfile, row);
429 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
431 unselect_packet(&cfile);
436 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
439 gchar *help_str = NULL;
440 gboolean has_blurb = FALSE;
441 guint length = 0, byte_len;
442 GtkWidget *byte_view;
446 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
449 set_notebook_page( byte_nb_ptr, find_notebook_page( byte_nb_ptr, finfo->ds_name));
451 byte_view = gtk_object_get_data(GTK_OBJECT(byte_nb_ptr), E_BYTE_VIEW_TEXT_INFO_KEY);
452 byte_data = gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_PTR_KEY);
453 byte_len = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_LEN_KEY));
457 finfo_selected = finfo;
459 set_menus_for_selected_tree_row(TRUE);
461 /*if (finfo->hfinfo && finfo->hfinfo->type != FT_TEXT_ONLY) {*/
463 if (finfo->hfinfo->blurb != NULL &&
464 finfo->hfinfo->blurb[0] != '\0') {
466 length = strlen(finfo->hfinfo->blurb);
468 length = strlen(finfo->hfinfo->name);
470 length += strlen(finfo->hfinfo->abbrev) + 10;
471 help_str = g_malloc(sizeof(gchar) * length);
472 sprintf(help_str, "%s (%s)",
473 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
474 finfo->hfinfo->abbrev);
475 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, help_str);
479 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
484 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
486 GtkWidget *byte_view;
491 fi = (field_info*)user_data;
493 len = get_byte_view_and_data( byte_nb_ptr, &byte_view, &data);
495 if ( len < 0) return;
496 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
497 finfo_selected = NULL;
498 set_menus_for_selected_tree_row(FALSE);
499 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
503 void collapse_all_cb(GtkWidget *widget, gpointer data) {
504 if (cfile.protocol_tree)
505 collapse_all_tree(cfile.protocol_tree, tree_view);
508 void expand_all_cb(GtkWidget *widget, gpointer data) {
509 if (cfile.protocol_tree)
510 expand_all_tree(cfile.protocol_tree, tree_view);
513 void resolve_name_cb(GtkWidget *widget, gpointer data) {
514 if (cfile.protocol_tree) {
515 int tmp = g_resolving_actif;
516 g_resolving_actif = 1;
517 gtk_clist_clear ( GTK_CLIST(tree_view) );
518 proto_tree_draw(cfile.protocol_tree, tree_view);
519 g_resolving_actif = tmp;
523 /* Set the scrollbar placement of a scrolled window based upon pos value:
524 0 = left, 1 = right */
526 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
529 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
530 GTK_CORNER_TOP_LEFT);
532 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
533 GTK_CORNER_TOP_RIGHT);
537 /* List of all scrolled windows, so we can globally set the scrollbar
538 placement of them. */
539 static GList *scrolled_windows;
541 /* Add a scrolled window to the list of scrolled windows. */
542 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
545 remember_scrolled_window(GtkWidget *scrollw)
547 scrolled_windows = g_list_append(scrolled_windows, scrollw);
549 /* Catch the "destroy" event on the widget, so that we remove it from
550 the list when it's destroyed. */
551 gtk_signal_connect(GTK_OBJECT(scrollw), "destroy",
552 GTK_SIGNAL_FUNC(forget_scrolled_window), NULL);
555 /* Remove a scrolled window from the list of scrolled windows. */
557 forget_scrolled_window(GtkWidget *scrollw, gpointer data)
559 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
563 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
565 set_scrollbar_placement_scrollw((GtkWidget *)data,
569 /* Set the scrollbar placement of all scrolled windows based on pos value:
570 0 = left, 1 = right */
572 set_scrollbar_placement_all(int pos)
574 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
577 /* Set the selection mode of the packet list window. */
579 set_plist_sel_browse(gboolean val)
584 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
586 if (val == old_val) {
588 * The mode isn't changing, so don't do anything.
589 * In particular, don't gratuitiously unselect the
592 * XXX - why do we have to unselect the current packet
593 * ourselves? The documentation for the GtkCList at
595 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
597 * says "Note that setting the widget's selection mode to
598 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
599 * cause all the items in the GtkCList to become deselected."
605 unselect_packet(&cfile);
607 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
608 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
610 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
613 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
617 /* Set the font of the packet list window. */
619 set_plist_font(GdkFont *font)
624 style = gtk_style_new();
625 gdk_font_unref(style->font);
629 gtk_widget_set_style(packet_list, style);
631 /* Compute static column sizes to use during a "-S" capture, so that
632 the columns don't resize during a live capture. */
633 for (i = 0; i < cfile.cinfo.num_cols; i++) {
634 cfile.cinfo.col_width[i] = gdk_string_width(font,
635 get_column_longest_string(get_column_format(i)));
640 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
642 file_quit_cmd_cb(widget, data);
644 /* Say that the window should be deleted. */
649 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
651 /* XXX - should we check whether the capture file is an
652 unsaved temporary file for a live capture and, if so,
653 pop up a "do you want to exit without saving the capture
654 file?" dialog, and then just return, leaving said dialog
655 box to forcibly quit if the user clicks "OK"?
657 If so, note that this should be done in a subroutine that
658 returns TRUE if we do so, and FALSE otherwise, and that
659 "main_window_delete_event_cb()" should return its
662 /* Are we in the middle of reading a capture? */
663 if (cfile.state == FILE_READ_IN_PROGRESS) {
664 /* Yes, so we can't just close the file and quit, as
665 that may yank the rug out from under the read in
666 progress; instead, just set the state to
667 "FILE_READ_ABORTED" and return - the code doing the read
668 will check for that and, if it sees that, will clean
670 cfile.state = FILE_READ_ABORTED;
672 /* Close any capture file we have open; on some OSes, you
673 can't unlink a temporary capture file if you have it
675 "close_cap_file()" will unlink it after closing it if
676 it's a temporary file.
678 We do this here, rather than after the main loop returns,
679 as, after the main loop returns, the main window may have
680 been destroyed (if this is called due to a "destroy"
681 even on the main window rather than due to the user
682 selecting a menu item), and there may be a crash
683 or other problem when "close_cap_file()" tries to
684 clean up stuff in the main window.
686 XXX - is there a better place to put this?
687 Or should we have a routine that *just* closes the
688 capture file, and doesn't do anything with the UI,
689 which we'd call here, and another routine that
690 calls that routine and also cleans up the UI, which
691 we'd call elsewhere? */
692 close_cap_file(&cfile, info_bar);
694 /* Exit by leaving the main loop, so that any quit functions
695 we registered get called. */
703 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
706 fprintf(stderr, "%s [ -vh ] [ -kpQS ] [ -B <byte view height> ] [ -c count ]\n",
708 fprintf(stderr, "\t[ -f <capture filter> ] [ -i interface ] [ -m <medium font> ] \n");
709 fprintf(stderr, "\t[ -n ] [ -o <preference setting> ] ... [ -P <packet list height> ]\n");
710 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -s snaplen ] \n");
711 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ] [ -w savefile ]\n");
713 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ] [ -n ]\n",
715 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
716 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
717 fprintf(stderr, "\t[ -T <tree view height> ]\n");
728 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
731 /* And now our feature presentation... [ fade to music ] */
733 main(int argc, char *argv[])
742 gboolean arg_error = FALSE;
746 char pcap_version[] = "0.4a6";
748 extern char pcap_version[];
756 char *gpf_path, *pf_path, *cf_path, *df_path;
757 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
760 gboolean start_capture = FALSE;
761 gchar *save_file = NULL;
763 gchar err_str[PCAP_ERRBUF_SIZE];
764 gboolean stats_known;
765 struct pcap_stat stats;
767 gboolean capture_option_specified = FALSE;
769 gint pl_size = 280, tv_size = 95, bv_size = 75;
770 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
771 dfilter_t *rfcode = NULL;
772 gboolean rfilter_parse_failed = FALSE;
774 char *bold_font_name;
776 ethereal_path = argv[0];
779 /* Arrange that if we have no console window, and a GLib message logging
780 routine is called to log a message, we pop up a console window.
782 We do that by inserting our own handler for all messages logged
783 to the default domain; that handler pops up a console if necessary,
784 and then calls the default handler. */
785 g_log_set_handler(NULL,
787 G_LOG_LEVEL_CRITICAL|
792 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
793 console_log_handler, NULL);
797 command_name = get_basename(ethereal_path);
798 /* Set "capture_child" to indicate whether this is going to be a child
799 process for a "-S" capture. */
800 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
803 /* Register all dissectors; we must do this before checking for the
804 "-G" flag, as the "-G" flag dumps a list of fields registered
805 by the dissectors, and we must do it before we read the preferences,
806 in case any dissectors register preferences. */
807 epan_init(PLUGIN_DIR);
809 /* Now register the preferences for any non-dissector modules.
810 We must do that before we read the preferences as well. */
811 prefs_register_modules();
813 /* If invoked with the "-G" flag, we dump out a glossary of
814 display filter symbols.
816 We must do this before calling "gtk_init()", because "gtk_init()"
817 tries to open an X display, and we don't want to have to do any X
818 stuff just to do a build.
820 Given that we call "gtk_init()" before doing the regular argument
821 list processing, so that it can handle X and GTK+ arguments and
822 remove them from the list at which we look, this means we must do
823 this before doing the regular argument list processing, as well.
827 you must give the "-G" flag as the first flag on the command line;
829 you must give it as "-G", nothing more, nothing less;
831 any arguments after the "-G" flag will not be used. */
832 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
833 proto_registrar_dump();
837 /* Set the current locale according to the program environment.
838 * We haven't localized anything, but some GTK widgets are localized
839 * (the file selection dialogue, for example).
840 * This also sets the C-language locale to the native environment. */
843 /* Let GTK get its args */
844 gtk_init (&argc, &argv);
846 /* Read the preference files. */
847 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
849 /* Read the capture filter file. */
850 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
852 /* Read the display filter file. */
853 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
855 /* Initialize the capture file struct */
857 cfile.plist_end = NULL;
859 cfile.filename = NULL;
860 cfile.user_saved = FALSE;
861 cfile.is_tempfile = FALSE;
863 cfile.dfilter = NULL;
866 cfile.cfilter = g_strdup(EMPTY_FILTER);
869 cfile.save_file = NULL;
870 cfile.save_file_fd = -1;
871 cfile.snap = WTAP_MAX_PACKET_SIZE;
873 col_init(&cfile.cinfo, prefs->num_cols);
875 /* Assemble the compile-time options */
876 snprintf(comp_info_str, 256,
877 #ifdef GTK_MAJOR_VERSION
878 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
881 "GTK+ (version unknown), %s%s, %s%s, %s%s",
885 "with libpcap ", pcap_version,
887 "without libpcap", "",
892 "with libz ", ZLIB_VERSION,
893 #else /* ZLIB_VERSION */
894 "with libz ", "(version unknown)",
895 #endif /* ZLIB_VERSION */
896 #else /* HAVE_LIBZ */
898 #endif /* HAVE_LIBZ */
900 /* Oh, this is pretty */
901 #if defined(HAVE_UCD_SNMP_SNMP_H)
902 #ifdef HAVE_UCD_SNMP_VERSION_H
903 "with UCD SNMP ", VersionInfo
904 #else /* HAVE_UCD_SNMP_VERSION_H */
905 "with UCD SNMP ", "(version unknown)"
906 #endif /* HAVE_UCD_SNMP_VERSION_H */
907 #elif defined(HAVE_SNMP_SNMP_H)
908 #ifdef HAVE_SNMP_VERSION_H
909 "with CMU SNMP ", snmp_Version()
910 #else /* HAVE_SNMP_VERSION_H */
911 "with CMU SNMP ", "(version unknown)"
912 #endif /* HAVE_SNMP_VERSION_H */
918 /* Now get our args */
919 while ((opt = getopt(argc, argv, "B:c:Df:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
921 case 'B': /* Byte view pane height */
922 bv_size = atoi(optarg);
924 case 'c': /* Capture xxx packets */
926 cfile.count = atoi(optarg);
928 capture_option_specified = TRUE;
935 g_free(cfile.cfilter);
936 cfile.cfilter = g_strdup(optarg);
938 capture_option_specified = TRUE;
942 case 'h': /* Print help and exit */
946 case 'i': /* Use interface xxx */
948 cfile.iface = g_strdup(optarg);
950 capture_option_specified = TRUE;
954 case 'k': /* Start capture immediately */
956 start_capture = TRUE;
958 capture_option_specified = TRUE;
962 case 'm': /* Fixed-width font for the display */
963 if (prefs->gui_font_name != NULL)
964 g_free(prefs->gui_font_name);
965 prefs->gui_font_name = g_strdup(optarg);
967 case 'n': /* No name resolution */
968 g_resolving_actif = 0;
970 case 'o': /* Override preference from command line */
971 switch (prefs_set_pref(optarg)) {
973 case PREFS_SET_SYNTAX_ERR:
974 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
978 case PREFS_SET_NO_SUCH_PREF:
979 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
985 case 'p': /* Don't capture in promiscuous mode */
989 capture_option_specified = TRUE;
993 case 'P': /* Packet list pane height */
994 pl_size = atoi(optarg);
996 case 'Q': /* Quit after capture (just capture to file) */
999 start_capture = TRUE; /*** -Q implies -k !! ***/
1001 capture_option_specified = TRUE;
1005 case 'r': /* Read capture file xxx */
1006 /* We may set "last_open_dir" to "cf_name", and if we change
1007 "last_open_dir" later, we free the old value, so we have to
1008 set "cf_name" to something that's been allocated. */
1009 cf_name = g_strdup(optarg);
1011 case 'R': /* Read file filter */
1014 case 's': /* Set the snapshot (capture) length */
1016 cfile.snap = atoi(optarg);
1018 capture_option_specified = TRUE;
1022 case 'S': /* "Sync" mode: used for following file ala tail -f */
1026 capture_option_specified = TRUE;
1030 case 't': /* Time stamp type */
1031 if (strcmp(optarg, "r") == 0)
1032 timestamp_type = RELATIVE;
1033 else if (strcmp(optarg, "a") == 0)
1034 timestamp_type = ABSOLUTE;
1035 else if (strcmp(optarg, "ad") == 0)
1036 timestamp_type = ABSOLUTE_WITH_DATE;
1037 else if (strcmp(optarg, "d") == 0)
1038 timestamp_type = DELTA;
1040 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1042 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1043 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1047 case 'T': /* Tree view pane height */
1048 tv_size = atoi(optarg);
1050 case 'v': /* Show version and exit */
1053 if (console_was_created)
1058 case 'w': /* Write to capture file xxx */
1060 save_file = g_strdup(optarg);
1062 capture_option_specified = TRUE;
1066 case 'W': /* Write to capture file FD xxx */
1068 cfile.save_file_fd = atoi(optarg);
1070 capture_option_specified = TRUE;
1076 case 'Z': /* Write to pipe FD XXX */
1078 /* associate stdout with pipe */
1080 if (dup2(i, 1) < 0) {
1081 fprintf(stderr, "Unable to dup pipe handle\n");
1085 capture_option_specified = TRUE;
1087 #endif /* HAVE_LIBPCAP */
1092 case '?': /* Bad flag - print usage message */
1099 /* Start windows sockets */
1100 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1103 /* Notify all registered modules that have had any of their preferences
1104 changed either from one of the preferences file or from the command
1105 line that its preferences have changed. */
1108 #ifndef HAVE_LIBPCAP
1109 if (capture_option_specified)
1110 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1115 if (start_capture) {
1116 /* We're supposed to do a live capture; did the user specify an interface
1118 if (cfile.iface == NULL) {
1119 /* No - pick the first one from the list of interfaces. */
1120 if_list = get_interface_list(&err, err_str);
1121 if (if_list == NULL) {
1124 case CANT_GET_INTERFACE_LIST:
1125 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1129 case NO_INTERFACES_FOUND:
1130 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1135 cfile.iface = g_strdup(if_list->data); /* first interface */
1136 free_interface_list(if_list);
1139 if (capture_child) {
1140 if (cfile.save_file_fd == -1) {
1141 /* XXX - send this to the standard output as something our parent
1142 should put in an error message box? */
1143 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1149 /* Build the column format array */
1150 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1151 cfile.cinfo.col_fmt[i] = get_column_format(i);
1152 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1153 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1155 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1156 cfile.cinfo.col_data[i] = NULL;
1157 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1158 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1160 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1164 cfile.snap = WTAP_MAX_PACKET_SIZE;
1165 else if (cfile.snap < MIN_PACKET_SIZE)
1166 cfile.snap = MIN_PACKET_SIZE;
1168 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1169 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1170 gtk_rc_parse(rc_file);
1172 /* Try to load the regular and boldface fixed-width fonts */
1173 bold_font_name = boldify(prefs->gui_font_name);
1174 m_r_font = gdk_font_load(prefs->gui_font_name);
1175 m_b_font = gdk_font_load(bold_font_name);
1176 if (m_r_font == NULL || m_b_font == NULL) {
1177 /* XXX - pop this up as a dialog box? no */
1178 if (m_r_font == NULL) {
1182 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1183 prefs->gui_font_name);
1185 gdk_font_unref(m_r_font);
1187 if (m_b_font == NULL) {
1191 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1194 gdk_font_unref(m_b_font);
1196 g_free(bold_font_name);
1197 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1198 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1201 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1202 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1205 g_free(prefs->gui_font_name);
1206 prefs->gui_font_name = g_strdup("6x13");
1209 /* Call this for the side-effects that set_fonts() produces */
1210 set_fonts(m_r_font, m_b_font);
1214 /* Is this a "child" ethereal, which is only supposed to pop up a
1215 capture box to let us stop the capture, and run a capture
1216 to a file that our parent will read? */
1217 if (!capture_child) {
1219 /* No. Pop up the main window, and read in a capture file if
1222 create_main_window(pl_size, tv_size, bv_size, prefs);
1223 set_menus_for_capture_file(FALSE);
1225 cfile.colors = colfilter_new();
1227 /* If we were given the name of a capture file, read it in now;
1228 we defer it until now, so that, if we can't open it, and pop
1229 up an alert box, the alert box is more likely to come up on
1230 top of the main window - but before the preference-file-error
1231 alert box, so, if we get one of those, it's more likely to come
1234 if (rfilter != NULL) {
1235 if (!dfilter_compile(rfilter, &rfcode)) {
1236 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1237 rfilter_parse_failed = TRUE;
1240 if (!rfilter_parse_failed) {
1241 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1242 /* "open_cap_file()" succeeded, so it closed the previous
1243 capture file, and thus destroyed any previous read filter
1244 attached to "cf". */
1245 cfile.rfcode = rfcode;
1246 switch (read_cap_file(&cfile, &err)) {
1250 /* Just because we got an error, that doesn't mean we were unable
1251 to read any of the file; we handle what we could get from the
1260 /* Save the name of the containing directory specified in the
1261 path name, if any; we can write over cf_name, which is a
1262 good thing, given that "get_dirname()" does write over its
1264 s = get_dirname(cf_name);
1269 dfilter_free(rfcode);
1270 cfile.rfcode = NULL;
1278 /* If the global preferences file exists but we failed to open it,
1279 pop up an alert box; we defer that until now, so that the alert
1280 box is more likely to come up on top of the main window. */
1281 if (gpf_path != NULL) {
1282 simple_dialog(ESD_TYPE_WARN, NULL,
1283 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1284 strerror(gpf_open_errno));
1287 /* If the user's preferences file exists but we failed to open it,
1288 pop up an alert box; we defer that until now, so that the alert
1289 box is more likely to come up on top of the main window. */
1290 if (pf_path != NULL) {
1291 simple_dialog(ESD_TYPE_WARN, NULL,
1292 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1293 strerror(pf_open_errno));
1296 /* If the user's capture filter file exists but we failed to open it,
1297 pop up an alert box; we defer that until now, so that the alert
1298 box is more likely to come up on top of the main window. */
1299 if (cf_path != NULL) {
1300 simple_dialog(ESD_TYPE_WARN, NULL,
1301 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1302 strerror(cf_open_errno));
1306 /* If the user's display filter file exists but we failed to open it,
1307 pop up an alert box; we defer that until now, so that the alert
1308 box is more likely to come up on top of the main window. */
1309 if (df_path != NULL) {
1310 simple_dialog(ESD_TYPE_WARN, NULL,
1311 "Could not open your display filter file\n\"%s\": %s.", df_path,
1312 strerror(df_open_errno));
1317 if (capture_child) {
1318 /* This is the child process for a sync mode or fork mode capture,
1319 so just do the low-level work of a capture - don't create
1320 a temporary file and fork off *another* child process (so don't
1321 call "do_capture()"). */
1323 /* XXX - hand these stats to the parent process */
1324 capture(&stats_known, &stats);
1326 /* The capture is done; there's nothing more for us to do. */
1329 if (start_capture) {
1330 /* "-k" was specified; start a capture. */
1331 do_capture(save_file);
1334 set_menus_for_capture_in_progress(FALSE);
1338 set_menus_for_capture_in_progress(FALSE);
1347 /* Shutdown windows sockets */
1350 /* For some unknown reason, the "atexit()" call in "create_console()"
1351 doesn't arrange that "destroy_console()" be called when we exit,
1352 so we call it here if a console was created. */
1353 if (console_was_created)
1359 /* This isn't reached, but we need it to keep GCC from complaining
1360 that "main()" returns without returning a value - it knows that
1361 "exit()" never returns, but it doesn't know that "gtk_exit()"
1362 doesn't, as GTK+ doesn't declare it with the attribute
1364 return 0; /* not reached */
1369 /* We build this as a GUI subsystem application on Win32, so
1370 "WinMain()", not "main()", gets called.
1372 Hack shamelessly stolen from the Win32 port of the GIMP. */
1374 #define _stdcall __attribute__((stdcall))
1378 WinMain (struct HINSTANCE__ *hInstance,
1379 struct HINSTANCE__ *hPrevInstance,
1383 has_no_console = TRUE;
1384 return main (__argc, __argv);
1388 * If this application has no console window to which its standard output
1389 * would go, create one.
1392 create_console(void)
1394 if (has_no_console) {
1395 /* We have no console to which to print the version string, so
1396 create one and make it the standard input, output, and error. */
1397 if (!AllocConsole())
1398 return; /* couldn't create console */
1399 freopen("CONIN$", "r", stdin);
1400 freopen("CONOUT$", "w", stdout);
1401 freopen("CONOUT$", "w", stderr);
1403 /* Well, we have a console now. */
1404 has_no_console = FALSE;
1405 console_was_created = TRUE;
1407 /* Now register "destroy_console()" as a routine to be called just
1408 before the application exits, so that we can destroy the console
1409 after the user has typed a key (so that the console doesn't just
1410 disappear out from under them, giving the user no chance to see
1411 the message(s) we put in there). */
1412 atexit(destroy_console);
1417 destroy_console(void)
1419 printf("\n\nPress any key to exit\n");
1424 /* This routine should not be necessary, at least as I read the GLib
1425 source code, as it looks as if GLib is, on Win32, *supposed* to
1426 create a console window into which to display its output.
1428 That doesn't happen, however. I suspect there's something completely
1429 broken about that code in GLib-for-Win32, and that it may be related
1430 to the breakage that forces us to just call "printf()" on the message
1431 rather than passing the message on to "g_log_default_handler()"
1432 (which is the routine that does the aforementioned non-functional
1433 console window creation). */
1435 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
1436 const char *message, gpointer user_data)
1439 if (console_was_created) {
1440 /* For some unknown reason, the above doesn't appear to actually cause
1441 anything to be sent to the standard output, so we'll just splat the
1442 message out directly, just to make sure it gets out. */
1443 printf("%s\n", message);
1445 g_log_default_handler(log_domain, log_level, message, user_data);
1449 /* Given a font name, construct the name of the next heavier version of
1452 #define XLFD_WEIGHT 3 /* index of the "weight" field */
1454 /* Map from a given weight to the appropriate weight for the "bold"
1456 XXX - the XLFD says these strings shouldn't be used for font matching;
1457 can we get the weight, as a number, from GDK, and ask GDK to find us
1458 a font just like the given font, but with the appropriate higher
1460 static const struct {
1464 { "ultralight", "light" },
1465 { "extralight", "semilight" },
1466 { "light", "medium" },
1467 { "semilight", "semibold" },
1468 { "medium", "bold" },
1469 { "normal", "bold" },
1470 { "semibold", "extrabold" },
1471 { "bold", "ultrabold" }
1473 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
1476 boldify(const char *font_name)
1478 char *bold_font_name;
1479 gchar **xlfd_tokens;
1482 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
1483 if (font_name[0] == '-') {
1484 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
1485 for (i = 0; i < N_WEIGHTS; i++) {
1486 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
1487 weight_map[i].light) == 0) {
1488 g_free(xlfd_tokens[XLFD_WEIGHT]);
1489 xlfd_tokens[XLFD_WEIGHT] =
1490 g_strdup(weight_map[i].heavier);
1494 bold_font_name = g_strjoinv("-", xlfd_tokens);
1495 g_strfreev(xlfd_tokens);
1497 /* Append "bold" to the name of the font. */
1498 bold_font_name = g_strconcat(font_name, "bold", NULL);
1500 return bold_font_name;
1505 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1507 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1509 *filter_bt, *filter_cm, *filter_te,
1511 GList *filter_list = NULL;
1512 GtkAccelGroup *accel;
1514 /* Display filter construct dialog has an Apply button, and "OK" not
1515 only sets our text widget, it activates it (i.e., it causes us to
1516 filter the capture). */
1517 static construct_args_t args = {
1518 "Ethereal: Display Filter",
1524 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1525 gtk_widget_set_name(top_level, "main window");
1526 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1527 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1528 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1529 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1530 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1532 /* Container for menu bar, paned windows and progress/info box */
1533 main_vbox = gtk_vbox_new(FALSE, 1);
1534 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1535 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1536 gtk_widget_show(main_vbox);
1539 get_main_menu(&menubar, &accel);
1540 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1541 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1542 gtk_widget_show(menubar);
1544 /* Panes for the packet list, tree, and byte view */
1545 u_pane = gtk_vpaned_new();
1546 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1547 l_pane = gtk_vpaned_new();
1548 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1549 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1550 gtk_widget_show(l_pane);
1551 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1552 gtk_widget_show(u_pane);
1555 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1556 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1557 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1558 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1559 remember_scrolled_window(pkt_scrollw);
1560 gtk_widget_show(pkt_scrollw);
1561 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1563 packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1564 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1566 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1567 set_plist_font(m_r_font);
1568 gtk_widget_set_name(packet_list, "packet list");
1569 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1570 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1571 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1572 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1573 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1574 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1575 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1576 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1577 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1579 /* Right-justify the packet number column. */
1580 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1581 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1584 gtk_widget_set_usize(packet_list, -1, pl_size);
1585 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1586 GTK_SIGNAL_FUNC(popup_menu_handler),
1587 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1588 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1589 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
1590 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1591 gtk_widget_show(packet_list);
1594 item_style = gtk_style_new();
1595 gdk_font_unref(item_style->font);
1596 item_style->font = m_r_font;
1597 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1598 prefs->gui_scrollbar_on_right);
1599 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1600 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1601 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1602 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1603 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
1604 GTK_SIGNAL_FUNC(popup_menu_handler),
1605 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1606 gtk_widget_show(tree_view);
1609 create_byte_view(bv_size, l_pane, &byte_nb_ptr, &bv_scrollw,
1610 prefs->gui_scrollbar_on_right);
1612 gtk_signal_connect(GTK_OBJECT(byte_nb_ptr), "button_press_event",
1613 GTK_SIGNAL_FUNC(popup_menu_handler),
1614 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
1616 /* Filter/info box */
1617 stat_hbox = gtk_hbox_new(FALSE, 1);
1618 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1619 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1620 gtk_widget_show(stat_hbox);
1622 filter_bt = gtk_button_new_with_label("Filter:");
1623 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1624 GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
1625 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1626 gtk_widget_show(filter_bt);
1628 filter_cm = gtk_combo_new();
1629 filter_list = g_list_append (filter_list, "");
1630 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1631 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1632 filter_te = GTK_COMBO(filter_cm)->entry;
1633 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1634 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1635 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1636 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1637 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1638 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1639 gtk_widget_show(filter_cm);
1641 filter_reset = gtk_button_new_with_label("Reset");
1642 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1643 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1644 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1645 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1646 gtk_widget_show(filter_reset);
1648 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1649 * of any widget that ends up calling a callback which needs
1650 * that text entry pointer */
1651 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1652 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1653 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1654 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1655 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1657 info_bar = gtk_statusbar_new();
1658 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1659 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1660 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
1661 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1662 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1663 gtk_widget_show(info_bar);
1665 gtk_widget_show(top_level);