3 * $Id: main.c,v 1.197 2001/05/01 00:18:48 guy 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"
142 #include "capture-wpcap.h"
148 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
149 *info_bar, *tv_scrollw, *pkt_scrollw;
150 static GtkWidget *bv_scrollw;
151 GdkFont *m_r_font, *m_b_font;
152 guint m_font_height, m_font_width;
153 guint main_ctx, file_ctx, help_ctx;
154 static GString *comp_info_str;
155 gchar *ethereal_path = NULL;
156 gchar *last_open_dir = NULL;
158 ts_type timestamp_type = RELATIVE;
160 GtkStyle *item_style;
162 /* Specifies the field currently selected in the GUI protocol tree */
163 field_info *finfo_selected = NULL;
166 static gboolean has_no_console; /* TRUE if app has no console */
167 static gboolean console_was_created; /* TRUE if console was created */
168 static void create_console(void);
169 static void destroy_console(void);
170 static void console_log_handler(const char *log_domain,
171 GLogLevelFlags log_level, const char *message, gpointer user_data);
174 static void create_main_window(gint, gint, gint, e_prefs*);
176 /* About Ethereal window */
178 about_ethereal( GtkWidget *w, gpointer data ) {
179 simple_dialog(ESD_TYPE_INFO, NULL,
180 "Ethereal - Network Protocol Analyzer\n"
181 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
184 "Check the man page for complete documentation and\n"
185 "for the list of contributors.\n"
187 "\nSee http://www.ethereal.com/ for more information.",
192 set_fonts(GdkFont *regular, GdkFont *bold)
194 /* Yes, assert. The code that loads the font should check
195 * for NULL and provide its own error message. */
196 g_assert(m_r_font && m_b_font);
200 m_font_height = m_r_font->ascent + m_r_font->descent;
201 m_font_width = gdk_string_width(m_r_font, "0");
205 /* Match selected byte pattern */
207 match_selected_cb(GtkWidget *w, gpointer data)
210 GtkWidget *filter_te;
212 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
214 if (!finfo_selected) {
215 simple_dialog(ESD_TYPE_CRIT, NULL,
216 "Error determining selected bytes. Please make\n"
217 "sure you have selected a field within the tree\n"
218 "view to be matched.");
222 buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
224 /* create a new one and set the display filter entry accordingly */
225 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
227 /* Run the display filter so it goes in effect. */
228 filter_packets(&cfile, buf);
230 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
235 /* Run the current display filter on the current packet set, and
238 filter_activate_cb(GtkWidget *w, gpointer data)
240 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
241 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
242 GList *li, *nl = NULL;
243 gboolean add_filter = TRUE;
245 char *s = gtk_entry_get_text(GTK_ENTRY(w));
247 /* GtkCombos don't let us get at their list contents easily, so we maintain
248 our own filter list, and feed it to gtk_combo_set_popdown_strings when
249 a new filter is added. */
250 if (filter_packets(&cfile, g_strdup(s))) {
251 li = g_list_first(filter_list);
253 if (li->data && strcmp(s, li->data) == 0)
259 filter_list = g_list_append(filter_list, g_strdup(s));
260 li = g_list_first(filter_list);
262 nl = g_list_append(nl, strdup(li->data));
265 gtk_combo_set_popdown_strings(filter_cm, nl);
266 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
271 /* redisplay with no display filter */
273 filter_reset_cb(GtkWidget *w, gpointer data)
275 GtkWidget *filter_te = NULL;
277 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
278 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
281 filter_packets(&cfile, NULL);
284 /* GTKClist compare routine, overrides default to allow numeric comparison */
286 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
288 /* Get row text strings */
289 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
290 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
292 /* Attempt to convert to numbers */
293 double num1 = atof(text1);
294 double num2 = atof(text2);
296 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
298 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
299 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
300 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
301 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
302 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
303 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
304 (col_fmt == COL_PACKET_LENGTH)) {
306 /* Compare numeric column */
310 else if (num1 > num2)
318 /* Compare text column */
320 return (text1 != NULL);
325 return strcmp(text1, text2);
329 /* What to do when a column is clicked */
331 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
333 if (column == clist->sort_column) {
334 if (clist->sort_type == GTK_SORT_ASCENDING)
335 clist->sort_type = GTK_SORT_DESCENDING;
337 clist->sort_type = GTK_SORT_ASCENDING;
340 clist->sort_type = GTK_SORT_ASCENDING;
341 gtk_clist_set_sort_column(clist, column);
344 gtk_clist_sort(clist);
349 set_frame_mark(gboolean set, frame_data *frame, gint row) {
352 if (frame == NULL || row == -1) return;
353 frame->flags.marked = set;
355 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
356 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
361 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
362 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
366 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data) {
368 GdkEventButton *event_button = (GdkEventButton *)event;
371 if (w == NULL || event == NULL)
374 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
375 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
377 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
378 set_frame_mark(!fdata->flags.marked, fdata, row);
382 void mark_frame_cb(GtkWidget *w, gpointer data) {
383 if (cfile.current_frame) {
384 /* XXX hum, should better have a "cfile->current_row" here ... */
385 set_frame_mark(!cfile.current_frame->flags.marked,
387 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
388 cfile.current_frame));
392 static void mark_all_frames(gboolean set) {
394 if (cfile.plist == NULL) return;
395 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
398 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
402 void update_marked_frames(void) {
404 if (cfile.plist == NULL) return;
405 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
406 if (fdata->flags.marked)
409 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
414 void mark_all_frames_cb(GtkWidget *w, gpointer data) {
415 mark_all_frames(TRUE);
418 void unmark_all_frames_cb(GtkWidget *w, gpointer data) {
419 mark_all_frames(FALSE);
422 /* What to do when a list item is selected/unselected */
424 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
428 /* Remove the hex display tabbed pages */
429 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
430 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
432 select_packet(&cfile, row);
437 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
439 unselect_packet(&cfile);
444 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
447 gchar *help_str = NULL;
448 gboolean has_blurb = FALSE;
449 guint length = 0, byte_len;
450 GtkWidget *byte_view;
454 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
457 set_notebook_page( byte_nb_ptr, find_notebook_page( byte_nb_ptr, finfo->ds_name));
459 byte_view = gtk_object_get_data(GTK_OBJECT(byte_nb_ptr), E_BYTE_VIEW_TEXT_INFO_KEY);
460 byte_data = gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_PTR_KEY);
461 byte_len = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_DATA_LEN_KEY));
465 finfo_selected = finfo;
467 set_menus_for_selected_tree_row(TRUE);
470 if (finfo->hfinfo->blurb != NULL &&
471 finfo->hfinfo->blurb[0] != '\0') {
473 length = strlen(finfo->hfinfo->blurb);
475 length = strlen(finfo->hfinfo->name);
478 length += strlen(finfo->hfinfo->abbrev) + 10;
479 help_str = g_malloc(sizeof(gchar) * length);
480 sprintf(help_str, "%s (%s)",
481 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
482 finfo->hfinfo->abbrev);
483 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, help_str);
487 * Don't show anything if the field name is zero-length;
488 * the pseudo-field for "proto_tree_add_text()" is such
489 * a field, and we don't want "Text (text)" showing up
490 * on the status line if you've selected such a field.
492 * XXX - perhaps the name and abbrev field should be null
493 * pointers rather than null strings for that pseudo-field,
494 * but we'd have to add checks for null pointers in some
495 * places if we did that.
497 * Or perhaps protocol tree items added with
498 * "proto_tree_add_text()" should have -1 as the field index,
499 * with no pseudo-field being used, but that might also
500 * require special checks for -1 to be added.
502 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, "");
506 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
511 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
513 GtkWidget *byte_view;
518 fi = (field_info*)user_data;
520 len = get_byte_view_and_data( byte_nb_ptr, &byte_view, &data);
522 if ( len < 0) return;
523 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
524 finfo_selected = NULL;
525 set_menus_for_selected_tree_row(FALSE);
526 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
530 void collapse_all_cb(GtkWidget *widget, gpointer data) {
531 if (cfile.protocol_tree)
532 collapse_all_tree(cfile.protocol_tree, tree_view);
535 void expand_all_cb(GtkWidget *widget, gpointer data) {
536 if (cfile.protocol_tree)
537 expand_all_tree(cfile.protocol_tree, tree_view);
540 void resolve_name_cb(GtkWidget *widget, gpointer data) {
541 if (cfile.protocol_tree) {
542 int tmp = prefs.name_resolve;
543 prefs.name_resolve = 1;
544 gtk_clist_clear ( GTK_CLIST(tree_view) );
545 proto_tree_draw(cfile.protocol_tree, tree_view);
546 prefs.name_resolve = tmp;
550 /* Set the scrollbar placement of a scrolled window based upon pos value:
551 0 = left, 1 = right */
553 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
556 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
557 GTK_CORNER_TOP_LEFT);
559 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
560 GTK_CORNER_TOP_RIGHT);
564 /* List of all scrolled windows, so we can globally set the scrollbar
565 placement of them. */
566 static GList *scrolled_windows;
568 /* Add a scrolled window to the list of scrolled windows. */
569 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
572 remember_scrolled_window(GtkWidget *scrollw)
574 scrolled_windows = g_list_append(scrolled_windows, scrollw);
576 /* Catch the "destroy" event on the widget, so that we remove it from
577 the list when it's destroyed. */
578 gtk_signal_connect(GTK_OBJECT(scrollw), "destroy",
579 GTK_SIGNAL_FUNC(forget_scrolled_window), NULL);
582 /* Remove a scrolled window from the list of scrolled windows. */
584 forget_scrolled_window(GtkWidget *scrollw, gpointer data)
586 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
590 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
592 set_scrollbar_placement_scrollw((GtkWidget *)data,
596 /* Set the scrollbar placement of all scrolled windows based on pos value:
597 0 = left, 1 = right */
599 set_scrollbar_placement_all(int pos)
601 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
604 /* Set the selection mode of the packet list window. */
606 set_plist_sel_browse(gboolean val)
611 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
613 if (val == old_val) {
615 * The mode isn't changing, so don't do anything.
616 * In particular, don't gratuitiously unselect the
619 * XXX - why do we have to unselect the current packet
620 * ourselves? The documentation for the GtkCList at
622 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
624 * says "Note that setting the widget's selection mode to
625 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
626 * cause all the items in the GtkCList to become deselected."
632 unselect_packet(&cfile);
634 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
635 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
637 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
640 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
644 /* Set the font of the packet list window. */
646 set_plist_font(GdkFont *font)
651 style = gtk_style_new();
652 gdk_font_unref(style->font);
656 gtk_widget_set_style(packet_list, style);
658 /* Compute static column sizes to use during a "-S" capture, so that
659 the columns don't resize during a live capture. */
660 for (i = 0; i < cfile.cinfo.num_cols; i++) {
661 cfile.cinfo.col_width[i] = gdk_string_width(font,
662 get_column_longest_string(get_column_format(i)));
667 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
669 file_quit_cmd_cb(widget, data);
671 /* Say that the window should be deleted. */
676 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
678 /* XXX - should we check whether the capture file is an
679 unsaved temporary file for a live capture and, if so,
680 pop up a "do you want to exit without saving the capture
681 file?" dialog, and then just return, leaving said dialog
682 box to forcibly quit if the user clicks "OK"?
684 If so, note that this should be done in a subroutine that
685 returns TRUE if we do so, and FALSE otherwise, and that
686 "main_window_delete_event_cb()" should return its
689 /* Are we in the middle of reading a capture? */
690 if (cfile.state == FILE_READ_IN_PROGRESS) {
691 /* Yes, so we can't just close the file and quit, as
692 that may yank the rug out from under the read in
693 progress; instead, just set the state to
694 "FILE_READ_ABORTED" and return - the code doing the read
695 will check for that and, if it sees that, will clean
697 cfile.state = FILE_READ_ABORTED;
699 /* Close any capture file we have open; on some OSes, you
700 can't unlink a temporary capture file if you have it
702 "close_cap_file()" will unlink it after closing it if
703 it's a temporary file.
705 We do this here, rather than after the main loop returns,
706 as, after the main loop returns, the main window may have
707 been destroyed (if this is called due to a "destroy"
708 even on the main window rather than due to the user
709 selecting a menu item), and there may be a crash
710 or other problem when "close_cap_file()" tries to
711 clean up stuff in the main window.
713 XXX - is there a better place to put this?
714 Or should we have a routine that *just* closes the
715 capture file, and doesn't do anything with the UI,
716 which we'd call here, and another routine that
717 calls that routine and also cleans up the UI, which
718 we'd call elsewhere? */
719 close_cap_file(&cfile, info_bar);
721 /* Exit by leaving the main loop, so that any quit functions
722 we registered get called. */
730 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
733 fprintf(stderr, "%s [ -vh ] [ -kpQS ] [ -B <byte view height> ] [ -c count ]\n",
735 fprintf(stderr, "\t[ -f <capture filter> ] [ -i interface ] [ -m <medium font> ] \n");
736 fprintf(stderr, "\t[ -n ] [ -o <preference setting> ] ... [ -P <packet list height> ]\n");
737 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -s snaplen ] \n");
738 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ] [ -w savefile ]\n");
740 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ] [ -n ]\n",
742 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
743 fprintf(stderr, "\t[ -r infile ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
744 fprintf(stderr, "\t[ -T <tree view height> ]\n");
755 printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
759 get_positive_int(const char *string, const char *name)
764 number = strtol(string, &p, 10);
765 if (p == string || *p != '\0') {
766 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
771 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
775 if (number > INT_MAX) {
776 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
777 name, string, INT_MAX);
783 /* And now our feature presentation... [ fade to music ] */
785 main(int argc, char *argv[])
794 gboolean arg_error = FALSE;
798 char pcap_version[] = WPCAP_STRING;
800 extern char pcap_version[];
808 char *gpf_path, *pf_path, *cf_path, *df_path;
809 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
812 gboolean start_capture = FALSE;
813 gchar *save_file = NULL;
815 gchar err_str[PCAP_ERRBUF_SIZE];
816 gboolean stats_known;
817 struct pcap_stat stats;
819 gboolean capture_option_specified = FALSE;
821 gint pl_size = 280, tv_size = 95, bv_size = 75;
822 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
823 dfilter_t *rfcode = NULL;
824 gboolean rfilter_parse_failed = FALSE;
826 char *bold_font_name;
828 ethereal_path = argv[0];
831 /* Arrange that if we have no console window, and a GLib message logging
832 routine is called to log a message, we pop up a console window.
834 We do that by inserting our own handler for all messages logged
835 to the default domain; that handler pops up a console if necessary,
836 and then calls the default handler. */
837 g_log_set_handler(NULL,
839 G_LOG_LEVEL_CRITICAL|
844 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
845 console_log_handler, NULL);
849 command_name = get_basename(ethereal_path);
850 /* Set "capture_child" to indicate whether this is going to be a child
851 process for a "-S" capture. */
852 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
855 /* Register all dissectors; we must do this before checking for the
856 "-G" flag, as the "-G" flag dumps a list of fields registered
857 by the dissectors, and we must do it before we read the preferences,
858 in case any dissectors register preferences. */
859 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
861 /* Now register the preferences for any non-dissector modules.
862 We must do that before we read the preferences as well. */
863 prefs_register_modules();
865 /* If invoked with the "-G" flag, we dump out a glossary of
866 display filter symbols.
868 We must do this before calling "gtk_init()", because "gtk_init()"
869 tries to open an X display, and we don't want to have to do any X
870 stuff just to do a build.
872 Given that we call "gtk_init()" before doing the regular argument
873 list processing, so that it can handle X and GTK+ arguments and
874 remove them from the list at which we look, this means we must do
875 this before doing the regular argument list processing, as well.
879 you must give the "-G" flag as the first flag on the command line;
881 you must give it as "-G", nothing more, nothing less;
883 any arguments after the "-G" flag will not be used. */
884 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
885 proto_registrar_dump();
889 /* Set the current locale according to the program environment.
890 * We haven't localized anything, but some GTK widgets are localized
891 * (the file selection dialogue, for example).
892 * This also sets the C-language locale to the native environment. */
895 /* Let GTK get its args */
896 gtk_init (&argc, &argv);
898 /* Read the preference files. */
899 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
901 /* Read the capture filter file. */
902 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
904 /* Read the display filter file. */
905 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
907 /* Initialize the capture file struct */
909 cfile.plist_end = NULL;
911 cfile.filename = NULL;
912 cfile.user_saved = FALSE;
913 cfile.is_tempfile = FALSE;
915 cfile.dfilter = NULL;
918 cfile.cfilter = g_strdup(EMPTY_FILTER);
921 cfile.save_file = NULL;
922 cfile.save_file_fd = -1;
923 cfile.snap = WTAP_MAX_PACKET_SIZE;
925 col_init(&cfile.cinfo, prefs->num_cols);
927 /* Assemble the compile-time options */
928 comp_info_str = g_string_new("");
930 g_string_append(comp_info_str, "with ");
931 g_string_sprintfa(comp_info_str,
932 #ifdef GTK_MAJOR_VERSION
933 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
936 "GTK+ (version unknown)");
939 g_string_append(comp_info_str, ", with ");
940 g_string_sprintfa(comp_info_str,
941 #ifdef GLIB_MAJOR_VERSION
942 "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
945 "GLib (version unknown)");
949 g_string_append(comp_info_str, ", with libpcap ");
950 g_string_append(comp_info_str, pcap_version);
952 g_string_append(comp_info_str, ", without libpcap");
956 g_string_append(comp_info_str, ", with libz ");
958 g_string_append(comp_info_str, ZLIB_VERSION);
959 #else /* ZLIB_VERSION */
960 g_string_append(comp_info_str, "(version unknown)");
961 #endif /* ZLIB_VERSION */
962 #else /* HAVE_LIBZ */
963 g_string_append(comp_info_str, ", without libz");
964 #endif /* HAVE_LIBZ */
966 /* Oh, this is pretty */
967 #if defined(HAVE_UCD_SNMP_SNMP_H)
968 g_string_append(comp_info_str, ", with UCD SNMP ");
969 #ifdef HAVE_UCD_SNMP_VERSION_H
970 g_string_append(comp_info_str, VersionInfo);
971 #else /* HAVE_UCD_SNMP_VERSION_H */
972 g_string_append(comp_info_str, "(version unknown)");
973 #endif /* HAVE_UCD_SNMP_VERSION_H */
974 #elif defined(HAVE_SNMP_SNMP_H)
975 g_string_append(comp_info_str, ", with CMU SNMP ");
976 #ifdef HAVE_SNMP_VERSION_H
977 g_string_append(comp_info_str, snmp_Version());
978 #else /* HAVE_SNMP_VERSION_H */
979 g_string_append(comp_info_str, "(version unknown)");
980 #endif /* HAVE_SNMP_VERSION_H */
982 g_string_append(comp_info_str, ", without SNMP");
985 /* Now get our args */
986 while ((opt = getopt(argc, argv, "B:c:f:hi:km:no:pP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
988 case 'B': /* Byte view pane height */
989 bv_size = get_positive_int(optarg, "byte view pane height");
991 case 'c': /* Capture xxx packets */
993 cfile.count = get_positive_int(optarg, "packet count");
995 capture_option_specified = TRUE;
1002 g_free(cfile.cfilter);
1003 cfile.cfilter = g_strdup(optarg);
1005 capture_option_specified = TRUE;
1009 case 'h': /* Print help and exit */
1013 case 'i': /* Use interface xxx */
1015 cfile.iface = g_strdup(optarg);
1017 capture_option_specified = TRUE;
1021 case 'k': /* Start capture immediately */
1023 start_capture = TRUE;
1025 capture_option_specified = TRUE;
1029 case 'm': /* Fixed-width font for the display */
1030 if (prefs->gui_font_name != NULL)
1031 g_free(prefs->gui_font_name);
1032 prefs->gui_font_name = g_strdup(optarg);
1034 case 'n': /* No name resolution */
1035 prefs->name_resolve = 0;
1037 case 'o': /* Override preference from command line */
1038 switch (prefs_set_pref(optarg)) {
1040 case PREFS_SET_SYNTAX_ERR:
1041 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1045 case PREFS_SET_NO_SUCH_PREF:
1046 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1052 case 'p': /* Don't capture in promiscuous mode */
1054 prefs->capture_prom_mode = 0;
1056 capture_option_specified = TRUE;
1060 case 'P': /* Packet list pane height */
1061 pl_size = get_positive_int(optarg, "packet list pane height");
1063 case 'Q': /* Quit after capture (just capture to file) */
1066 start_capture = TRUE; /*** -Q implies -k !! ***/
1068 capture_option_specified = TRUE;
1072 case 'r': /* Read capture file xxx */
1073 /* We may set "last_open_dir" to "cf_name", and if we change
1074 "last_open_dir" later, we free the old value, so we have to
1075 set "cf_name" to something that's been allocated. */
1076 cf_name = g_strdup(optarg);
1078 case 'R': /* Read file filter */
1081 case 's': /* Set the snapshot (capture) length */
1083 cfile.snap = get_positive_int(optarg, "snapshot length");
1085 capture_option_specified = TRUE;
1089 case 'S': /* "Sync" mode: used for following file ala tail -f */
1091 prefs->capture_real_time = TRUE;
1093 capture_option_specified = TRUE;
1097 case 't': /* Time stamp type */
1098 if (strcmp(optarg, "r") == 0)
1099 timestamp_type = RELATIVE;
1100 else if (strcmp(optarg, "a") == 0)
1101 timestamp_type = ABSOLUTE;
1102 else if (strcmp(optarg, "ad") == 0)
1103 timestamp_type = ABSOLUTE_WITH_DATE;
1104 else if (strcmp(optarg, "d") == 0)
1105 timestamp_type = DELTA;
1107 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1109 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1110 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1114 case 'T': /* Tree view pane height */
1115 tv_size = get_positive_int(optarg, "tree view pane height");
1117 case 'v': /* Show version and exit */
1120 if (console_was_created)
1125 case 'w': /* Write to capture file xxx */
1127 save_file = g_strdup(optarg);
1129 capture_option_specified = TRUE;
1133 case 'W': /* Write to capture file FD xxx */
1135 cfile.save_file_fd = atoi(optarg);
1137 capture_option_specified = TRUE;
1143 case 'Z': /* Write to pipe FD XXX */
1145 /* associate stdout with pipe */
1147 if (dup2(i, 1) < 0) {
1148 fprintf(stderr, "Unable to dup pipe handle\n");
1152 capture_option_specified = TRUE;
1154 #endif /* HAVE_LIBPCAP */
1159 case '?': /* Bad flag - print usage message */
1166 /* Load wpcap if possible */
1169 /* Start windows sockets */
1170 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1173 /* Notify all registered modules that have had any of their preferences
1174 changed either from one of the preferences file or from the command
1175 line that its preferences have changed. */
1178 #ifndef HAVE_LIBPCAP
1179 if (capture_option_specified)
1180 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1185 if (start_capture) {
1186 /* We're supposed to do a live capture; did the user specify an interface
1188 if (cfile.iface == NULL) {
1189 /* No - pick the first one from the list of interfaces. */
1190 if_list = get_interface_list(&err, err_str);
1191 if (if_list == NULL) {
1194 case CANT_GET_INTERFACE_LIST:
1195 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1199 case NO_INTERFACES_FOUND:
1200 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1205 cfile.iface = g_strdup(if_list->data); /* first interface */
1206 free_interface_list(if_list);
1209 if (capture_child) {
1210 if (cfile.save_file_fd == -1) {
1211 /* XXX - send this to the standard output as something our parent
1212 should put in an error message box? */
1213 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1219 /* Build the column format array */
1220 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1221 cfile.cinfo.col_fmt[i] = get_column_format(i);
1222 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1223 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1225 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1226 cfile.cinfo.col_data[i] = NULL;
1227 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1228 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1230 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1234 cfile.snap = WTAP_MAX_PACKET_SIZE;
1235 else if (cfile.snap < MIN_PACKET_SIZE)
1236 cfile.snap = MIN_PACKET_SIZE;
1238 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1239 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1240 gtk_rc_parse(rc_file);
1242 /* Try to load the regular and boldface fixed-width fonts */
1243 bold_font_name = boldify(prefs->gui_font_name);
1244 m_r_font = gdk_font_load(prefs->gui_font_name);
1245 m_b_font = gdk_font_load(bold_font_name);
1246 if (m_r_font == NULL || m_b_font == NULL) {
1247 /* XXX - pop this up as a dialog box? no */
1248 if (m_r_font == NULL) {
1252 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1253 prefs->gui_font_name);
1255 gdk_font_unref(m_r_font);
1257 if (m_b_font == NULL) {
1261 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1264 gdk_font_unref(m_b_font);
1266 g_free(bold_font_name);
1267 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1268 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1271 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1272 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1275 g_free(prefs->gui_font_name);
1276 prefs->gui_font_name = g_strdup("6x13");
1279 /* Call this for the side-effects that set_fonts() produces */
1280 set_fonts(m_r_font, m_b_font);
1284 /* Is this a "child" ethereal, which is only supposed to pop up a
1285 capture box to let us stop the capture, and run a capture
1286 to a file that our parent will read? */
1287 if (!capture_child) {
1289 /* No. Pop up the main window, and read in a capture file if
1292 create_main_window(pl_size, tv_size, bv_size, prefs);
1293 set_menus_for_capture_file(FALSE);
1295 cfile.colors = colfilter_new();
1297 /* If we were given the name of a capture file, read it in now;
1298 we defer it until now, so that, if we can't open it, and pop
1299 up an alert box, the alert box is more likely to come up on
1300 top of the main window - but before the preference-file-error
1301 alert box, so, if we get one of those, it's more likely to come
1304 if (rfilter != NULL) {
1305 if (!dfilter_compile(rfilter, &rfcode)) {
1306 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1307 rfilter_parse_failed = TRUE;
1310 if (!rfilter_parse_failed) {
1311 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1312 /* "open_cap_file()" succeeded, so it closed the previous
1313 capture file, and thus destroyed any previous read filter
1314 attached to "cf". */
1315 cfile.rfcode = rfcode;
1316 switch (read_cap_file(&cfile, &err)) {
1320 /* Just because we got an error, that doesn't mean we were unable
1321 to read any of the file; we handle what we could get from the
1330 /* Save the name of the containing directory specified in the
1331 path name, if any; we can write over cf_name, which is a
1332 good thing, given that "get_dirname()" does write over its
1334 s = get_dirname(cf_name);
1335 set_last_open_dir(s);
1338 dfilter_free(rfcode);
1339 cfile.rfcode = NULL;
1347 /* If the global preferences file exists but we failed to open it,
1348 pop up an alert box; we defer that until now, so that the alert
1349 box is more likely to come up on top of the main window. */
1350 if (gpf_path != NULL) {
1351 simple_dialog(ESD_TYPE_WARN, NULL,
1352 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1353 strerror(gpf_open_errno));
1356 /* If the user's preferences file exists but we failed to open it,
1357 pop up an alert box; we defer that until now, so that the alert
1358 box is more likely to come up on top of the main window. */
1359 if (pf_path != NULL) {
1360 simple_dialog(ESD_TYPE_WARN, NULL,
1361 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1362 strerror(pf_open_errno));
1365 /* If the user's capture filter file exists but we failed to open it,
1366 pop up an alert box; we defer that until now, so that the alert
1367 box is more likely to come up on top of the main window. */
1368 if (cf_path != NULL) {
1369 simple_dialog(ESD_TYPE_WARN, NULL,
1370 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1371 strerror(cf_open_errno));
1375 /* If the user's display filter file exists but we failed to open it,
1376 pop up an alert box; we defer that until now, so that the alert
1377 box is more likely to come up on top of the main window. */
1378 if (df_path != NULL) {
1379 simple_dialog(ESD_TYPE_WARN, NULL,
1380 "Could not open your display filter file\n\"%s\": %s.", df_path,
1381 strerror(df_open_errno));
1386 if (capture_child) {
1387 /* This is the child process for a sync mode or fork mode capture,
1388 so just do the low-level work of a capture - don't create
1389 a temporary file and fork off *another* child process (so don't
1390 call "do_capture()"). */
1392 /* XXX - hand these stats to the parent process */
1393 capture(&stats_known, &stats);
1395 /* The capture is done; there's nothing more for us to do. */
1398 if (start_capture) {
1399 /* "-k" was specified; start a capture. */
1400 do_capture(save_file);
1403 set_menus_for_capture_in_progress(FALSE);
1407 set_menus_for_capture_in_progress(FALSE);
1416 /* Shutdown windows sockets */
1419 /* For some unknown reason, the "atexit()" call in "create_console()"
1420 doesn't arrange that "destroy_console()" be called when we exit,
1421 so we call it here if a console was created. */
1422 if (console_was_created)
1428 /* This isn't reached, but we need it to keep GCC from complaining
1429 that "main()" returns without returning a value - it knows that
1430 "exit()" never returns, but it doesn't know that "gtk_exit()"
1431 doesn't, as GTK+ doesn't declare it with the attribute
1433 return 0; /* not reached */
1438 /* We build this as a GUI subsystem application on Win32, so
1439 "WinMain()", not "main()", gets called.
1441 Hack shamelessly stolen from the Win32 port of the GIMP. */
1443 #define _stdcall __attribute__((stdcall))
1447 WinMain (struct HINSTANCE__ *hInstance,
1448 struct HINSTANCE__ *hPrevInstance,
1452 has_no_console = TRUE;
1453 return main (__argc, __argv);
1457 * If this application has no console window to which its standard output
1458 * would go, create one.
1461 create_console(void)
1463 if (has_no_console) {
1464 /* We have no console to which to print the version string, so
1465 create one and make it the standard input, output, and error. */
1466 if (!AllocConsole())
1467 return; /* couldn't create console */
1468 freopen("CONIN$", "r", stdin);
1469 freopen("CONOUT$", "w", stdout);
1470 freopen("CONOUT$", "w", stderr);
1472 /* Well, we have a console now. */
1473 has_no_console = FALSE;
1474 console_was_created = TRUE;
1476 /* Now register "destroy_console()" as a routine to be called just
1477 before the application exits, so that we can destroy the console
1478 after the user has typed a key (so that the console doesn't just
1479 disappear out from under them, giving the user no chance to see
1480 the message(s) we put in there). */
1481 atexit(destroy_console);
1486 destroy_console(void)
1488 printf("\n\nPress any key to exit\n");
1493 /* This routine should not be necessary, at least as I read the GLib
1494 source code, as it looks as if GLib is, on Win32, *supposed* to
1495 create a console window into which to display its output.
1497 That doesn't happen, however. I suspect there's something completely
1498 broken about that code in GLib-for-Win32, and that it may be related
1499 to the breakage that forces us to just call "printf()" on the message
1500 rather than passing the message on to "g_log_default_handler()"
1501 (which is the routine that does the aforementioned non-functional
1502 console window creation). */
1504 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
1505 const char *message, gpointer user_data)
1508 if (console_was_created) {
1509 /* For some unknown reason, the above doesn't appear to actually cause
1510 anything to be sent to the standard output, so we'll just splat the
1511 message out directly, just to make sure it gets out. */
1512 printf("%s\n", message);
1514 g_log_default_handler(log_domain, log_level, message, user_data);
1518 /* Given a font name, construct the name of the next heavier version of
1521 #define XLFD_WEIGHT 3 /* index of the "weight" field */
1523 /* Map from a given weight to the appropriate weight for the "bold"
1525 XXX - the XLFD says these strings shouldn't be used for font matching;
1526 can we get the weight, as a number, from GDK, and ask GDK to find us
1527 a font just like the given font, but with the appropriate higher
1529 static const struct {
1533 { "ultralight", "light" },
1534 { "extralight", "semilight" },
1535 { "light", "medium" },
1536 { "semilight", "semibold" },
1537 { "medium", "bold" },
1538 { "normal", "bold" },
1539 { "semibold", "extrabold" },
1540 { "bold", "ultrabold" }
1542 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
1545 boldify(const char *font_name)
1547 char *bold_font_name;
1548 gchar **xlfd_tokens;
1551 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
1552 if (font_name[0] == '-') {
1553 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
1554 for (i = 0; i < N_WEIGHTS; i++) {
1555 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
1556 weight_map[i].light) == 0) {
1557 g_free(xlfd_tokens[XLFD_WEIGHT]);
1558 xlfd_tokens[XLFD_WEIGHT] =
1559 g_strdup(weight_map[i].heavier);
1563 bold_font_name = g_strjoinv("-", xlfd_tokens);
1564 g_strfreev(xlfd_tokens);
1566 /* Append "bold" to the name of the font. */
1567 bold_font_name = g_strconcat(font_name, "bold", NULL);
1569 return bold_font_name;
1574 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1576 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1578 *filter_bt, *filter_cm, *filter_te,
1580 GList *filter_list = NULL;
1581 GtkAccelGroup *accel;
1583 /* Display filter construct dialog has an Apply button, and "OK" not
1584 only sets our text widget, it activates it (i.e., it causes us to
1585 filter the capture). */
1586 static construct_args_t args = {
1587 "Ethereal: Display Filter",
1593 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1594 gtk_widget_set_name(top_level, "main window");
1595 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1596 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1597 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1598 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1599 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1601 /* Container for menu bar, paned windows and progress/info box */
1602 main_vbox = gtk_vbox_new(FALSE, 1);
1603 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1604 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1605 gtk_widget_show(main_vbox);
1608 get_main_menu(&menubar, &accel);
1609 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1610 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1611 gtk_widget_show(menubar);
1613 /* Panes for the packet list, tree, and byte view */
1614 u_pane = gtk_vpaned_new();
1615 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1616 l_pane = gtk_vpaned_new();
1617 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1618 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1619 gtk_widget_show(l_pane);
1620 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1621 gtk_widget_show(u_pane);
1624 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1625 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1626 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1627 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1628 remember_scrolled_window(pkt_scrollw);
1629 gtk_widget_show(pkt_scrollw);
1630 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1632 packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1633 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1635 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1636 set_plist_font(m_r_font);
1637 gtk_widget_set_name(packet_list, "packet list");
1638 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1639 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1640 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1641 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1642 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1643 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1644 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1645 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1646 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1648 /* Right-justify the packet number column. */
1649 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1650 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1653 gtk_widget_set_usize(packet_list, -1, pl_size);
1654 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1655 GTK_SIGNAL_FUNC(popup_menu_handler),
1656 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1657 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
1658 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
1659 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1660 gtk_widget_show(packet_list);
1663 item_style = gtk_style_new();
1664 gdk_font_unref(item_style->font);
1665 item_style->font = m_r_font;
1666 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1667 prefs->gui_scrollbar_on_right);
1668 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1669 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1670 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1671 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1672 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
1673 GTK_SIGNAL_FUNC(popup_menu_handler),
1674 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1675 gtk_widget_show(tree_view);
1678 create_byte_view(bv_size, l_pane, &byte_nb_ptr, &bv_scrollw,
1679 prefs->gui_scrollbar_on_right);
1681 gtk_signal_connect(GTK_OBJECT(byte_nb_ptr), "button_press_event",
1682 GTK_SIGNAL_FUNC(popup_menu_handler),
1683 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
1685 /* Filter/info box */
1686 stat_hbox = gtk_hbox_new(FALSE, 1);
1687 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1688 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1689 gtk_widget_show(stat_hbox);
1691 filter_bt = gtk_button_new_with_label("Filter:");
1692 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1693 GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
1694 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1695 gtk_widget_show(filter_bt);
1697 filter_cm = gtk_combo_new();
1698 filter_list = g_list_append (filter_list, "");
1699 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1700 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1701 filter_te = GTK_COMBO(filter_cm)->entry;
1702 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1703 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1704 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1705 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1706 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1707 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1708 gtk_widget_show(filter_cm);
1710 filter_reset = gtk_button_new_with_label("Reset");
1711 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1712 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1713 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1714 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1715 gtk_widget_show(filter_reset);
1717 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1718 * of any widget that ends up calling a callback which needs
1719 * that text entry pointer */
1720 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1721 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1722 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1723 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1724 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1726 info_bar = gtk_statusbar_new();
1727 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1728 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1729 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
1730 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1731 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1732 gtk_widget_show(info_bar);
1734 gtk_widget_show(top_level);
1739 set_last_open_dir(char *dirname)
1743 if (last_open_dir) {
1744 g_free(last_open_dir);
1748 len = strlen(dirname);
1749 if (dirname[len-1] != G_DIR_SEPARATOR) {
1750 last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
1755 last_open_dir = NULL;