3 * $Id: main.c,v 1.191 2001/04/10 12:07:39 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
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 */
110 #include <epan/filesystem.h>
113 #include "timestamp.h"
122 #include "color_utils.h"
123 #include "filter_prefs.h"
124 #include "prefs_dlg.h"
129 #include "simple_dialog.h"
130 #include "proto_draw.h"
131 #include "dfilter/dfilter.h"
133 #include "packet_win.h"
134 #include "gtkglobals.h"
138 #include "register.h"
141 #include "capture-wpcap.h"
147 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
148 *info_bar, *tv_scrollw, *pkt_scrollw;
149 static GtkWidget *bv_scrollw;
150 GdkFont *m_r_font, *m_b_font;
151 guint m_font_height, m_font_width;
152 guint main_ctx, file_ctx, help_ctx;
153 static GString *comp_info_str;
154 gchar *ethereal_path = NULL;
155 gchar *last_open_dir = NULL;
157 ts_type timestamp_type = RELATIVE;
159 GtkStyle *item_style;
161 /* Specifies the field currently selected in the GUI protocol tree */
162 field_info *finfo_selected = NULL;
165 static gboolean has_no_console; /* TRUE if app has no console */
166 static gboolean console_was_created; /* TRUE if console was created */
167 static void create_console(void);
168 static void destroy_console(void);
169 static void console_log_handler(const char *log_domain,
170 GLogLevelFlags log_level, const char *message, gpointer user_data);
173 static void create_main_window(gint, gint, gint, e_prefs*);
175 /* About Ethereal window */
177 about_ethereal( GtkWidget *w, gpointer data ) {
178 simple_dialog(ESD_TYPE_INFO, NULL,
179 "Ethereal - Network Protocol Analyzer\n"
180 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
183 "Check the man page for complete documentation and\n"
184 "for the list of contributors.\n"
186 "\nSee http://www.ethereal.com/ for more information.",
191 set_fonts(GdkFont *regular, GdkFont *bold)
193 /* Yes, assert. The code that loads the font should check
194 * for NULL and provide its own error message. */
195 g_assert(m_r_font && m_b_font);
199 m_font_height = m_r_font->ascent + m_r_font->descent;
200 m_font_width = gdk_string_width(m_r_font, "0");
204 /* Match selected byte pattern */
206 match_selected_cb(GtkWidget *w, gpointer data)
209 GtkWidget *filter_te;
211 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
213 if (!finfo_selected) {
214 simple_dialog(ESD_TYPE_CRIT, NULL,
215 "Error determining selected bytes. Please make\n"
216 "sure you have selected a field within the tree\n"
217 "view to be matched.");
221 buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
223 /* create a new one and set the display filter entry accordingly */
224 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
226 /* Run the display filter so it goes in effect. */
227 filter_packets(&cfile, buf);
229 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
234 /* Run the current display filter on the current packet set, and
237 filter_activate_cb(GtkWidget *w, gpointer data)
239 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
240 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
241 GList *li, *nl = NULL;
242 gboolean add_filter = TRUE;
244 char *s = gtk_entry_get_text(GTK_ENTRY(w));
246 /* GtkCombos don't let us get at their list contents easily, so we maintain
247 our own filter list, and feed it to gtk_combo_set_popdown_strings when
248 a new filter is added. */
249 if (filter_packets(&cfile, g_strdup(s))) {
250 li = g_list_first(filter_list);
252 if (li->data && strcmp(s, li->data) == 0)
258 filter_list = g_list_append(filter_list, g_strdup(s));
259 li = g_list_first(filter_list);
261 nl = g_list_append(nl, strdup(li->data));
264 gtk_combo_set_popdown_strings(filter_cm, nl);
265 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
270 /* redisplay with no display filter */
272 filter_reset_cb(GtkWidget *w, gpointer data)
274 GtkWidget *filter_te = NULL;
276 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
277 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
280 filter_packets(&cfile, NULL);
283 /* GTKClist compare routine, overrides default to allow numeric comparison */
285 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
287 /* Get row text strings */
288 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
289 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
291 /* Attempt to convert to numbers */
292 double num1 = atof(text1);
293 double num2 = atof(text2);
295 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
297 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
298 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
299 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
300 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
301 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
302 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
303 (col_fmt == COL_PACKET_LENGTH)) {
305 /* Compare numeric column */
309 else if (num1 > num2)
317 /* Compare text column */
319 return (text1 != NULL);
324 return strcmp(text1, text2);
328 /* What to do when a column is clicked */
330 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
332 if (column == clist->sort_column) {
333 if (clist->sort_type == GTK_SORT_ASCENDING)
334 clist->sort_type = GTK_SORT_DESCENDING;
336 clist->sort_type = GTK_SORT_ASCENDING;
339 clist->sort_type = GTK_SORT_ASCENDING;
340 gtk_clist_set_sort_column(clist, column);
343 gtk_clist_sort(clist);
348 set_frame_mark(gboolean set, frame_data *frame, gint row) {
351 if (frame == NULL || row == -1) return;
352 frame->flags.marked = set;
354 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
355 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
360 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
361 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
365 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data) {
367 GdkEventButton *event_button = (GdkEventButton *)event;
370 if (w == NULL || event == NULL)
373 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
374 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
376 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
377 set_frame_mark(!fdata->flags.marked, fdata, row);
381 void mark_frame_cb(GtkWidget *w, gpointer data) {
382 if (cfile.current_frame) {
383 /* XXX hum, should better have a "cfile->current_row" here ... */
384 set_frame_mark(!cfile.current_frame->flags.marked,
386 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
387 cfile.current_frame));
391 static void mark_all_frames(gboolean set) {
393 if (cfile.plist == NULL) return;
394 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
397 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
401 void update_marked_frames(void) {
403 if (cfile.plist == NULL) return;
404 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
405 if (fdata->flags.marked)
408 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
413 void mark_all_frames_cb(GtkWidget *w, gpointer data) {
414 mark_all_frames(TRUE);
417 void unmark_all_frames_cb(GtkWidget *w, gpointer data) {
418 mark_all_frames(FALSE);
421 /* What to do when a list item is selected/unselected */
423 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
427 /* Remove the hex display tabbed pages */
428 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
429 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
431 select_packet(&cfile, row);
436 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
438 unselect_packet(&cfile);
443 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
446 gchar *help_str = NULL;
447 gboolean has_blurb = FALSE;
448 guint length = 0, byte_len;
449 GtkWidget *byte_view;
453 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
456 set_notebook_page( byte_nb_ptr, find_notebook_page( byte_nb_ptr, finfo->ds_name));
458 byte_view = gtk_object_get_data(GTK_OBJECT(byte_nb_ptr), E_BYTE_VIEW_TEXT_INFO_KEY);
459 byte_data = gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_PTR_KEY);
460 byte_len = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_LEN_KEY));
464 finfo_selected = finfo;
466 set_menus_for_selected_tree_row(TRUE);
468 /*if (finfo->hfinfo && finfo->hfinfo->type != FT_TEXT_ONLY) {*/
470 if (finfo->hfinfo->blurb != NULL &&
471 finfo->hfinfo->blurb[0] != '\0') {
473 length = strlen(finfo->hfinfo->blurb);
475 length = strlen(finfo->hfinfo->name);
477 length += strlen(finfo->hfinfo->abbrev) + 10;
478 help_str = g_malloc(sizeof(gchar) * length);
479 sprintf(help_str, "%s (%s)",
480 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
481 finfo->hfinfo->abbrev);
482 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, help_str);
486 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
491 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
493 GtkWidget *byte_view;
498 fi = (field_info*)user_data;
500 len = get_byte_view_and_data( byte_nb_ptr, &byte_view, &data);
502 if ( len < 0) return;
503 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
504 finfo_selected = NULL;
505 set_menus_for_selected_tree_row(FALSE);
506 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
510 void collapse_all_cb(GtkWidget *widget, gpointer data) {
511 if (cfile.protocol_tree)
512 collapse_all_tree(cfile.protocol_tree, tree_view);
515 void expand_all_cb(GtkWidget *widget, gpointer data) {
516 if (cfile.protocol_tree)
517 expand_all_tree(cfile.protocol_tree, tree_view);
520 void resolve_name_cb(GtkWidget *widget, gpointer data) {
521 if (cfile.protocol_tree) {
522 int tmp = g_resolving_actif;
523 g_resolving_actif = 1;
524 gtk_clist_clear ( GTK_CLIST(tree_view) );
525 proto_tree_draw(cfile.protocol_tree, tree_view);
526 g_resolving_actif = tmp;
530 /* Set the scrollbar placement of a scrolled window based upon pos value:
531 0 = left, 1 = right */
533 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
536 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
537 GTK_CORNER_TOP_LEFT);
539 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
540 GTK_CORNER_TOP_RIGHT);
544 /* List of all scrolled windows, so we can globally set the scrollbar
545 placement of them. */
546 static GList *scrolled_windows;
548 /* Add a scrolled window to the list of scrolled windows. */
549 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
552 remember_scrolled_window(GtkWidget *scrollw)
554 scrolled_windows = g_list_append(scrolled_windows, scrollw);
556 /* Catch the "destroy" event on the widget, so that we remove it from
557 the list when it's destroyed. */
558 gtk_signal_connect(GTK_OBJECT(scrollw), "destroy",
559 GTK_SIGNAL_FUNC(forget_scrolled_window), NULL);
562 /* Remove a scrolled window from the list of scrolled windows. */
564 forget_scrolled_window(GtkWidget *scrollw, gpointer data)
566 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
570 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
572 set_scrollbar_placement_scrollw((GtkWidget *)data,
576 /* Set the scrollbar placement of all scrolled windows based on pos value:
577 0 = left, 1 = right */
579 set_scrollbar_placement_all(int pos)
581 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
584 /* Set the selection mode of the packet list window. */
586 set_plist_sel_browse(gboolean val)
591 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
593 if (val == old_val) {
595 * The mode isn't changing, so don't do anything.
596 * In particular, don't gratuitiously unselect the
599 * XXX - why do we have to unselect the current packet
600 * ourselves? The documentation for the GtkCList at
602 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
604 * says "Note that setting the widget's selection mode to
605 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
606 * cause all the items in the GtkCList to become deselected."
612 unselect_packet(&cfile);
614 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
615 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
617 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
620 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
624 /* Set the font of the packet list window. */
626 set_plist_font(GdkFont *font)
631 style = gtk_style_new();
632 gdk_font_unref(style->font);
636 gtk_widget_set_style(packet_list, style);
638 /* Compute static column sizes to use during a "-S" capture, so that
639 the columns don't resize during a live capture. */
640 for (i = 0; i < cfile.cinfo.num_cols; i++) {
641 cfile.cinfo.col_width[i] = gdk_string_width(font,
642 get_column_longest_string(get_column_format(i)));
647 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
649 file_quit_cmd_cb(widget, data);
651 /* Say that the window should be deleted. */
656 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
658 /* XXX - should we check whether the capture file is an
659 unsaved temporary file for a live capture and, if so,
660 pop up a "do you want to exit without saving the capture
661 file?" dialog, and then just return, leaving said dialog
662 box to forcibly quit if the user clicks "OK"?
664 If so, note that this should be done in a subroutine that
665 returns TRUE if we do so, and FALSE otherwise, and that
666 "main_window_delete_event_cb()" should return its
669 /* Are we in the middle of reading a capture? */
670 if (cfile.state == FILE_READ_IN_PROGRESS) {
671 /* Yes, so we can't just close the file and quit, as
672 that may yank the rug out from under the read in
673 progress; instead, just set the state to
674 "FILE_READ_ABORTED" and return - the code doing the read
675 will check for that and, if it sees that, will clean
677 cfile.state = FILE_READ_ABORTED;
679 /* Close any capture file we have open; on some OSes, you
680 can't unlink a temporary capture file if you have it
682 "close_cap_file()" will unlink it after closing it if
683 it's a temporary file.
685 We do this here, rather than after the main loop returns,
686 as, after the main loop returns, the main window may have
687 been destroyed (if this is called due to a "destroy"
688 even on the main window rather than due to the user
689 selecting a menu item), and there may be a crash
690 or other problem when "close_cap_file()" tries to
691 clean up stuff in the main window.
693 XXX - is there a better place to put this?
694 Or should we have a routine that *just* closes the
695 capture file, and doesn't do anything with the UI,
696 which we'd call here, and another routine that
697 calls that routine and also cleans up the UI, which
698 we'd call elsewhere? */
699 close_cap_file(&cfile, info_bar);
701 /* Exit by leaving the main loop, so that any quit functions
702 we registered get called. */
710 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
713 fprintf(stderr, "%s [ -vh ] [ -kpQS ] [ -B <byte view height> ] [ -c count ]\n",
715 fprintf(stderr, "\t[ -f <capture filter> ] [ -i interface ] [ -m <medium font> ] \n");
716 fprintf(stderr, "\t[ -n ] [ -o <preference setting> ] ... [ -P <packet list height> ]\n");
717 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -s snaplen ] \n");
718 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ] [ -w savefile ]\n");
720 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ] [ -n ]\n",
722 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
723 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
724 fprintf(stderr, "\t[ -T <tree view height> ]\n");
735 printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
738 /* And now our feature presentation... [ fade to music ] */
740 main(int argc, char *argv[])
749 gboolean arg_error = FALSE;
753 char pcap_version[] = WPCAP_STRING;
755 extern char pcap_version[];
763 char *gpf_path, *pf_path, *cf_path, *df_path;
764 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
767 gboolean start_capture = FALSE;
768 gchar *save_file = NULL;
770 gchar err_str[PCAP_ERRBUF_SIZE];
771 gboolean stats_known;
772 struct pcap_stat stats;
774 gboolean capture_option_specified = FALSE;
776 gint pl_size = 280, tv_size = 95, bv_size = 75;
777 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
778 dfilter_t *rfcode = NULL;
779 gboolean rfilter_parse_failed = FALSE;
781 char *bold_font_name;
783 ethereal_path = argv[0];
786 /* Arrange that if we have no console window, and a GLib message logging
787 routine is called to log a message, we pop up a console window.
789 We do that by inserting our own handler for all messages logged
790 to the default domain; that handler pops up a console if necessary,
791 and then calls the default handler. */
792 g_log_set_handler(NULL,
794 G_LOG_LEVEL_CRITICAL|
799 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
800 console_log_handler, NULL);
804 command_name = get_basename(ethereal_path);
805 /* Set "capture_child" to indicate whether this is going to be a child
806 process for a "-S" capture. */
807 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
810 /* Register all dissectors; we must do this before checking for the
811 "-G" flag, as the "-G" flag dumps a list of fields registered
812 by the dissectors, and we must do it before we read the preferences,
813 in case any dissectors register preferences. */
814 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
816 /* Now register the preferences for any non-dissector modules.
817 We must do that before we read the preferences as well. */
818 prefs_register_modules();
820 /* If invoked with the "-G" flag, we dump out a glossary of
821 display filter symbols.
823 We must do this before calling "gtk_init()", because "gtk_init()"
824 tries to open an X display, and we don't want to have to do any X
825 stuff just to do a build.
827 Given that we call "gtk_init()" before doing the regular argument
828 list processing, so that it can handle X and GTK+ arguments and
829 remove them from the list at which we look, this means we must do
830 this before doing the regular argument list processing, as well.
834 you must give the "-G" flag as the first flag on the command line;
836 you must give it as "-G", nothing more, nothing less;
838 any arguments after the "-G" flag will not be used. */
839 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
840 proto_registrar_dump();
844 /* Set the current locale according to the program environment.
845 * We haven't localized anything, but some GTK widgets are localized
846 * (the file selection dialogue, for example).
847 * This also sets the C-language locale to the native environment. */
850 /* Let GTK get its args */
851 gtk_init (&argc, &argv);
853 /* Read the preference files. */
854 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
856 /* Read the capture filter file. */
857 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
859 /* Read the display filter file. */
860 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
862 /* Initialize the capture file struct */
864 cfile.plist_end = NULL;
866 cfile.filename = NULL;
867 cfile.user_saved = FALSE;
868 cfile.is_tempfile = FALSE;
870 cfile.dfilter = NULL;
873 cfile.cfilter = g_strdup(EMPTY_FILTER);
876 cfile.save_file = NULL;
877 cfile.save_file_fd = -1;
878 cfile.snap = WTAP_MAX_PACKET_SIZE;
880 col_init(&cfile.cinfo, prefs->num_cols);
882 /* Assemble the compile-time options */
883 comp_info_str = g_string_new("");
885 g_string_append(comp_info_str, "with ");
886 g_string_sprintfa(comp_info_str,
887 #ifdef GTK_MAJOR_VERSION
888 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
891 "GTK+ (version unknown)");
894 g_string_append(comp_info_str, ", with ");
895 g_string_sprintfa(comp_info_str,
896 #ifdef GLIB_MAJOR_VERSION
897 "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
900 "GLib (version unknown)");
904 g_string_append(comp_info_str, ", with libpcap ");
905 g_string_append(comp_info_str, pcap_version);
907 g_string_append(comp_info_str, ", without libpcap");
911 g_string_append(comp_info_str, ", with libz ");
913 g_string_append(comp_info_str, ZLIB_VERSION);
914 #else /* ZLIB_VERSION */
915 g_string_append(comp_info_str, "(version unknown)");
916 #endif /* ZLIB_VERSION */
917 #else /* HAVE_LIBZ */
918 g_string_append(comp_info_str, ", without libz");
919 #endif /* HAVE_LIBZ */
921 /* Oh, this is pretty */
922 #if defined(HAVE_UCD_SNMP_SNMP_H)
923 g_string_append(comp_info_str, ", with UCD SNMP ");
924 #ifdef HAVE_UCD_SNMP_VERSION_H
925 g_string_append(comp_info_str, VersionInfo);
926 #else /* HAVE_UCD_SNMP_VERSION_H */
927 g_string_append(comp_info_str, "(version unknown)");
928 #endif /* HAVE_UCD_SNMP_VERSION_H */
929 #elif defined(HAVE_SNMP_SNMP_H)
930 g_string_append(comp_info_str, ", with CMU SNMP ");
931 #ifdef HAVE_SNMP_VERSION_H
932 g_string_append(comp_info_str, snmp_Version());
933 #else /* HAVE_SNMP_VERSION_H */
934 g_string_append(comp_info_str, "(version unknown)");
935 #endif /* HAVE_SNMP_VERSION_H */
937 g_string_append(comp_info_str, ", without SNMP");
940 /* Now get our args */
941 while ((opt = getopt(argc, argv, "B:c:f:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
943 case 'B': /* Byte view pane height */
944 bv_size = atoi(optarg);
946 case 'c': /* Capture xxx packets */
948 cfile.count = atoi(optarg);
950 capture_option_specified = TRUE;
957 g_free(cfile.cfilter);
958 cfile.cfilter = g_strdup(optarg);
960 capture_option_specified = TRUE;
964 case 'h': /* Print help and exit */
968 case 'i': /* Use interface xxx */
970 cfile.iface = g_strdup(optarg);
972 capture_option_specified = TRUE;
976 case 'k': /* Start capture immediately */
978 start_capture = TRUE;
980 capture_option_specified = TRUE;
984 case 'm': /* Fixed-width font for the display */
985 if (prefs->gui_font_name != NULL)
986 g_free(prefs->gui_font_name);
987 prefs->gui_font_name = g_strdup(optarg);
989 case 'n': /* No name resolution */
990 g_resolving_actif = 0;
992 case 'o': /* Override preference from command line */
993 switch (prefs_set_pref(optarg)) {
995 case PREFS_SET_SYNTAX_ERR:
996 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1000 case PREFS_SET_NO_SUCH_PREF:
1001 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1007 case 'p': /* Don't capture in promiscuous mode */
1011 capture_option_specified = TRUE;
1015 case 'P': /* Packet list pane height */
1016 pl_size = atoi(optarg);
1018 case 'Q': /* Quit after capture (just capture to file) */
1021 start_capture = TRUE; /*** -Q implies -k !! ***/
1023 capture_option_specified = TRUE;
1027 case 'r': /* Read capture file xxx */
1028 /* We may set "last_open_dir" to "cf_name", and if we change
1029 "last_open_dir" later, we free the old value, so we have to
1030 set "cf_name" to something that's been allocated. */
1031 cf_name = g_strdup(optarg);
1033 case 'R': /* Read file filter */
1036 case 's': /* Set the snapshot (capture) length */
1038 cfile.snap = atoi(optarg);
1040 capture_option_specified = TRUE;
1044 case 'S': /* "Sync" mode: used for following file ala tail -f */
1048 capture_option_specified = TRUE;
1052 case 't': /* Time stamp type */
1053 if (strcmp(optarg, "r") == 0)
1054 timestamp_type = RELATIVE;
1055 else if (strcmp(optarg, "a") == 0)
1056 timestamp_type = ABSOLUTE;
1057 else if (strcmp(optarg, "ad") == 0)
1058 timestamp_type = ABSOLUTE_WITH_DATE;
1059 else if (strcmp(optarg, "d") == 0)
1060 timestamp_type = DELTA;
1062 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1064 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1065 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1069 case 'T': /* Tree view pane height */
1070 tv_size = atoi(optarg);
1072 case 'v': /* Show version and exit */
1075 if (console_was_created)
1080 case 'w': /* Write to capture file xxx */
1082 save_file = g_strdup(optarg);
1084 capture_option_specified = TRUE;
1088 case 'W': /* Write to capture file FD xxx */
1090 cfile.save_file_fd = atoi(optarg);
1092 capture_option_specified = TRUE;
1098 case 'Z': /* Write to pipe FD XXX */
1100 /* associate stdout with pipe */
1102 if (dup2(i, 1) < 0) {
1103 fprintf(stderr, "Unable to dup pipe handle\n");
1107 capture_option_specified = TRUE;
1109 #endif /* HAVE_LIBPCAP */
1114 case '?': /* Bad flag - print usage message */
1121 /* Load wpcap if possible */
1124 /* Start windows sockets */
1125 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1128 /* Notify all registered modules that have had any of their preferences
1129 changed either from one of the preferences file or from the command
1130 line that its preferences have changed. */
1133 #ifndef HAVE_LIBPCAP
1134 if (capture_option_specified)
1135 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1140 if (start_capture) {
1141 /* We're supposed to do a live capture; did the user specify an interface
1143 if (cfile.iface == NULL) {
1144 /* No - pick the first one from the list of interfaces. */
1145 if_list = get_interface_list(&err, err_str);
1146 if (if_list == NULL) {
1149 case CANT_GET_INTERFACE_LIST:
1150 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1154 case NO_INTERFACES_FOUND:
1155 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1160 cfile.iface = g_strdup(if_list->data); /* first interface */
1161 free_interface_list(if_list);
1164 if (capture_child) {
1165 if (cfile.save_file_fd == -1) {
1166 /* XXX - send this to the standard output as something our parent
1167 should put in an error message box? */
1168 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1174 /* Build the column format array */
1175 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1176 cfile.cinfo.col_fmt[i] = get_column_format(i);
1177 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1178 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1180 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1181 cfile.cinfo.col_data[i] = NULL;
1182 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1183 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1185 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1189 cfile.snap = WTAP_MAX_PACKET_SIZE;
1190 else if (cfile.snap < MIN_PACKET_SIZE)
1191 cfile.snap = MIN_PACKET_SIZE;
1193 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1194 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1195 gtk_rc_parse(rc_file);
1197 /* Try to load the regular and boldface fixed-width fonts */
1198 bold_font_name = boldify(prefs->gui_font_name);
1199 m_r_font = gdk_font_load(prefs->gui_font_name);
1200 m_b_font = gdk_font_load(bold_font_name);
1201 if (m_r_font == NULL || m_b_font == NULL) {
1202 /* XXX - pop this up as a dialog box? no */
1203 if (m_r_font == NULL) {
1207 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1208 prefs->gui_font_name);
1210 gdk_font_unref(m_r_font);
1212 if (m_b_font == NULL) {
1216 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1219 gdk_font_unref(m_b_font);
1221 g_free(bold_font_name);
1222 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1223 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1226 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1227 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1230 g_free(prefs->gui_font_name);
1231 prefs->gui_font_name = g_strdup("6x13");
1234 /* Call this for the side-effects that set_fonts() produces */
1235 set_fonts(m_r_font, m_b_font);
1239 /* Is this a "child" ethereal, which is only supposed to pop up a
1240 capture box to let us stop the capture, and run a capture
1241 to a file that our parent will read? */
1242 if (!capture_child) {
1244 /* No. Pop up the main window, and read in a capture file if
1247 create_main_window(pl_size, tv_size, bv_size, prefs);
1248 set_menus_for_capture_file(FALSE);
1250 cfile.colors = colfilter_new();
1252 /* If we were given the name of a capture file, read it in now;
1253 we defer it until now, so that, if we can't open it, and pop
1254 up an alert box, the alert box is more likely to come up on
1255 top of the main window - but before the preference-file-error
1256 alert box, so, if we get one of those, it's more likely to come
1259 if (rfilter != NULL) {
1260 if (!dfilter_compile(rfilter, &rfcode)) {
1261 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1262 rfilter_parse_failed = TRUE;
1265 if (!rfilter_parse_failed) {
1266 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1267 /* "open_cap_file()" succeeded, so it closed the previous
1268 capture file, and thus destroyed any previous read filter
1269 attached to "cf". */
1270 cfile.rfcode = rfcode;
1271 switch (read_cap_file(&cfile, &err)) {
1275 /* Just because we got an error, that doesn't mean we were unable
1276 to read any of the file; we handle what we could get from the
1285 /* Save the name of the containing directory specified in the
1286 path name, if any; we can write over cf_name, which is a
1287 good thing, given that "get_dirname()" does write over its
1289 s = get_dirname(cf_name);
1290 set_last_open_dir(s);
1293 dfilter_free(rfcode);
1294 cfile.rfcode = NULL;
1302 /* If the global preferences file exists but we failed to open it,
1303 pop up an alert box; we defer that until now, so that the alert
1304 box is more likely to come up on top of the main window. */
1305 if (gpf_path != NULL) {
1306 simple_dialog(ESD_TYPE_WARN, NULL,
1307 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1308 strerror(gpf_open_errno));
1311 /* If the user's preferences file exists but we failed to open it,
1312 pop up an alert box; we defer that until now, so that the alert
1313 box is more likely to come up on top of the main window. */
1314 if (pf_path != NULL) {
1315 simple_dialog(ESD_TYPE_WARN, NULL,
1316 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1317 strerror(pf_open_errno));
1320 /* If the user's capture filter file exists but we failed to open it,
1321 pop up an alert box; we defer that until now, so that the alert
1322 box is more likely to come up on top of the main window. */
1323 if (cf_path != NULL) {
1324 simple_dialog(ESD_TYPE_WARN, NULL,
1325 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1326 strerror(cf_open_errno));
1330 /* If the user's display filter file exists but we failed to open it,
1331 pop up an alert box; we defer that until now, so that the alert
1332 box is more likely to come up on top of the main window. */
1333 if (df_path != NULL) {
1334 simple_dialog(ESD_TYPE_WARN, NULL,
1335 "Could not open your display filter file\n\"%s\": %s.", df_path,
1336 strerror(df_open_errno));
1341 if (capture_child) {
1342 /* This is the child process for a sync mode or fork mode capture,
1343 so just do the low-level work of a capture - don't create
1344 a temporary file and fork off *another* child process (so don't
1345 call "do_capture()"). */
1347 /* XXX - hand these stats to the parent process */
1348 capture(&stats_known, &stats);
1350 /* The capture is done; there's nothing more for us to do. */
1353 if (start_capture) {
1354 /* "-k" was specified; start a capture. */
1355 do_capture(save_file);
1358 set_menus_for_capture_in_progress(FALSE);
1362 set_menus_for_capture_in_progress(FALSE);
1371 /* Shutdown windows sockets */
1374 /* For some unknown reason, the "atexit()" call in "create_console()"
1375 doesn't arrange that "destroy_console()" be called when we exit,
1376 so we call it here if a console was created. */
1377 if (console_was_created)
1383 /* This isn't reached, but we need it to keep GCC from complaining
1384 that "main()" returns without returning a value - it knows that
1385 "exit()" never returns, but it doesn't know that "gtk_exit()"
1386 doesn't, as GTK+ doesn't declare it with the attribute
1388 return 0; /* not reached */
1393 /* We build this as a GUI subsystem application on Win32, so
1394 "WinMain()", not "main()", gets called.
1396 Hack shamelessly stolen from the Win32 port of the GIMP. */
1398 #define _stdcall __attribute__((stdcall))
1402 WinMain (struct HINSTANCE__ *hInstance,
1403 struct HINSTANCE__ *hPrevInstance,
1407 has_no_console = TRUE;
1408 return main (__argc, __argv);
1412 * If this application has no console window to which its standard output
1413 * would go, create one.
1416 create_console(void)
1418 if (has_no_console) {
1419 /* We have no console to which to print the version string, so
1420 create one and make it the standard input, output, and error. */
1421 if (!AllocConsole())
1422 return; /* couldn't create console */
1423 freopen("CONIN$", "r", stdin);
1424 freopen("CONOUT$", "w", stdout);
1425 freopen("CONOUT$", "w", stderr);
1427 /* Well, we have a console now. */
1428 has_no_console = FALSE;
1429 console_was_created = TRUE;
1431 /* Now register "destroy_console()" as a routine to be called just
1432 before the application exits, so that we can destroy the console
1433 after the user has typed a key (so that the console doesn't just
1434 disappear out from under them, giving the user no chance to see
1435 the message(s) we put in there). */
1436 atexit(destroy_console);
1441 destroy_console(void)
1443 printf("\n\nPress any key to exit\n");
1448 /* This routine should not be necessary, at least as I read the GLib
1449 source code, as it looks as if GLib is, on Win32, *supposed* to
1450 create a console window into which to display its output.
1452 That doesn't happen, however. I suspect there's something completely
1453 broken about that code in GLib-for-Win32, and that it may be related
1454 to the breakage that forces us to just call "printf()" on the message
1455 rather than passing the message on to "g_log_default_handler()"
1456 (which is the routine that does the aforementioned non-functional
1457 console window creation). */
1459 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
1460 const char *message, gpointer user_data)
1463 if (console_was_created) {
1464 /* For some unknown reason, the above doesn't appear to actually cause
1465 anything to be sent to the standard output, so we'll just splat the
1466 message out directly, just to make sure it gets out. */
1467 printf("%s\n", message);
1469 g_log_default_handler(log_domain, log_level, message, user_data);
1473 /* Given a font name, construct the name of the next heavier version of
1476 #define XLFD_WEIGHT 3 /* index of the "weight" field */
1478 /* Map from a given weight to the appropriate weight for the "bold"
1480 XXX - the XLFD says these strings shouldn't be used for font matching;
1481 can we get the weight, as a number, from GDK, and ask GDK to find us
1482 a font just like the given font, but with the appropriate higher
1484 static const struct {
1488 { "ultralight", "light" },
1489 { "extralight", "semilight" },
1490 { "light", "medium" },
1491 { "semilight", "semibold" },
1492 { "medium", "bold" },
1493 { "normal", "bold" },
1494 { "semibold", "extrabold" },
1495 { "bold", "ultrabold" }
1497 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
1500 boldify(const char *font_name)
1502 char *bold_font_name;
1503 gchar **xlfd_tokens;
1506 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
1507 if (font_name[0] == '-') {
1508 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
1509 for (i = 0; i < N_WEIGHTS; i++) {
1510 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
1511 weight_map[i].light) == 0) {
1512 g_free(xlfd_tokens[XLFD_WEIGHT]);
1513 xlfd_tokens[XLFD_WEIGHT] =
1514 g_strdup(weight_map[i].heavier);
1518 bold_font_name = g_strjoinv("-", xlfd_tokens);
1519 g_strfreev(xlfd_tokens);
1521 /* Append "bold" to the name of the font. */
1522 bold_font_name = g_strconcat(font_name, "bold", NULL);
1524 return bold_font_name;
1529 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1531 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1533 *filter_bt, *filter_cm, *filter_te,
1535 GList *filter_list = NULL;
1536 GtkAccelGroup *accel;
1538 /* Display filter construct dialog has an Apply button, and "OK" not
1539 only sets our text widget, it activates it (i.e., it causes us to
1540 filter the capture). */
1541 static construct_args_t args = {
1542 "Ethereal: Display Filter",
1548 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1549 gtk_widget_set_name(top_level, "main window");
1550 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1551 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1552 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1553 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1554 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1556 /* Container for menu bar, paned windows and progress/info box */
1557 main_vbox = gtk_vbox_new(FALSE, 1);
1558 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1559 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1560 gtk_widget_show(main_vbox);
1563 get_main_menu(&menubar, &accel);
1564 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1565 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1566 gtk_widget_show(menubar);
1568 /* Panes for the packet list, tree, and byte view */
1569 u_pane = gtk_vpaned_new();
1570 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1571 l_pane = gtk_vpaned_new();
1572 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1573 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1574 gtk_widget_show(l_pane);
1575 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1576 gtk_widget_show(u_pane);
1579 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1580 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1581 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1582 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1583 remember_scrolled_window(pkt_scrollw);
1584 gtk_widget_show(pkt_scrollw);
1585 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1587 packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1588 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1590 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1591 set_plist_font(m_r_font);
1592 gtk_widget_set_name(packet_list, "packet list");
1593 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1594 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1595 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1596 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1597 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1598 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1599 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1600 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1601 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1603 /* Right-justify the packet number column. */
1604 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1605 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1608 gtk_widget_set_usize(packet_list, -1, pl_size);
1609 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1610 GTK_SIGNAL_FUNC(popup_menu_handler),
1611 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1612 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1613 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
1614 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1615 gtk_widget_show(packet_list);
1618 item_style = gtk_style_new();
1619 gdk_font_unref(item_style->font);
1620 item_style->font = m_r_font;
1621 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1622 prefs->gui_scrollbar_on_right);
1623 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1624 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1625 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1626 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1627 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
1628 GTK_SIGNAL_FUNC(popup_menu_handler),
1629 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1630 gtk_widget_show(tree_view);
1633 create_byte_view(bv_size, l_pane, &byte_nb_ptr, &bv_scrollw,
1634 prefs->gui_scrollbar_on_right);
1636 gtk_signal_connect(GTK_OBJECT(byte_nb_ptr), "button_press_event",
1637 GTK_SIGNAL_FUNC(popup_menu_handler),
1638 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
1640 /* Filter/info box */
1641 stat_hbox = gtk_hbox_new(FALSE, 1);
1642 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1643 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1644 gtk_widget_show(stat_hbox);
1646 filter_bt = gtk_button_new_with_label("Filter:");
1647 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1648 GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
1649 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1650 gtk_widget_show(filter_bt);
1652 filter_cm = gtk_combo_new();
1653 filter_list = g_list_append (filter_list, "");
1654 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1655 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1656 filter_te = GTK_COMBO(filter_cm)->entry;
1657 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1658 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1659 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1660 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1661 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1662 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1663 gtk_widget_show(filter_cm);
1665 filter_reset = gtk_button_new_with_label("Reset");
1666 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1667 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1668 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1669 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1670 gtk_widget_show(filter_reset);
1672 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1673 * of any widget that ends up calling a callback which needs
1674 * that text entry pointer */
1675 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1676 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1677 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1678 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1679 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1681 info_bar = gtk_statusbar_new();
1682 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1683 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1684 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
1685 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1686 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1687 gtk_widget_show(info_bar);
1689 gtk_widget_show(top_level);
1694 set_last_open_dir(char *dirname)
1698 if (last_open_dir) {
1699 g_free(last_open_dir);
1703 len = strlen(dirname);
1704 if (dirname[len-1] != G_DIR_SEPARATOR) {
1705 last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
1710 last_open_dir = NULL;