3 * $Id: main.c,v 1.458 2004/07/13 07:15:44 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.
32 * - Multiple window support
33 * - Add cut/copy/paste
34 * - Create header parsing routines
35 * - Make byte view selections more fancy?
56 #include <io.h> /* open/close on win32 */
59 #ifdef NEED_STRERROR_H
67 #ifdef WIN32 /* Needed for console I/O */
72 #include <epan/epan.h>
73 #include <epan/filesystem.h>
74 #include <epan/epan_dissect.h>
75 #include <epan/timestamp.h>
76 #include <epan/packet.h>
77 #include <epan/plugins.h>
78 #include <epan/dfilter/dfilter.h>
79 #include <epan/strutil.h>
80 #include <epan/resolv.h>
82 /* general (not GTK specific) */
83 #include "cvsversion.h"
87 #include "disabled_protos.h"
89 #include "filter_prefs.h"
90 #include "layout_prefs.h"
92 #include "color_filters.h"
93 #include "color_utils.h"
95 #include "simple_dialog.h"
97 #include "prefs-int.h"
98 #include "ringbuffer.h"
99 #include "../ui_util.h" /* beware: ui_util.h exists twice! */
102 #include "version_info.h"
106 #include "pcap-util.h"
109 #include "capture-wpcap.h"
113 #include "statusbar.h"
114 #include "alert_box.h"
115 #include "dlg_utils.h"
116 #include "gtkglobals.h"
118 #include "ui_util.h" /* beware: ui_util.h exists twice! */
119 #include "compat_macros.h"
124 #include "file_dlg.h"
126 #include "proto_draw.h"
128 #include "packet_win.h"
130 #include "find_dlg.h"
131 #include "packet_list.h"
133 #include "follow_dlg.h"
134 #include "font_utils.h"
135 #include "about_dlg.h"
139 * File under personal preferences directory in which GTK settings for
140 * Ethereal are stored.
142 #define RC_FILE "gtkrc"
145 #define DEF_READY_MESSAGE " Ready to load or capture"
147 #define DEF_READY_MESSAGE " Ready to load file"
151 GtkWidget *main_display_filter_widget=NULL;
152 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
153 static GtkWidget *none_lb, *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
154 static GtkWidget *main_first_pane, *main_second_pane;
155 static GtkWidget *status_pane;
156 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
157 static GtkWidget *info_bar;
158 static GtkWidget *packets_bar = NULL;
159 static guint main_ctx, file_ctx, help_ctx;
160 static guint packets_ctx;
161 static gchar *packets_str = NULL;
162 GString *comp_info_str, *runtime_info_str;
163 gchar *ethereal_path = NULL;
166 static gboolean has_console; /* TRUE if app has console */
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);
174 static gboolean list_link_layer_types;
177 static void create_main_window(gint, gint, gint, e_prefs*);
178 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_);
179 static void main_save_window_geometry(GtkWidget *widget);
181 #define E_DFILTER_CM_KEY "display_filter_combo"
182 #define E_DFILTER_FL_KEY "display_filter_list"
186 /* Match selected byte pattern */
188 match_selected_cb_do(gpointer data, int action, gchar *text)
190 GtkWidget *filter_te;
191 char *cur_filter, *new_filter;
196 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
199 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
201 switch (action&MATCH_SELECTED_MASK) {
203 case MATCH_SELECTED_REPLACE:
204 new_filter = g_strdup(text);
207 case MATCH_SELECTED_AND:
208 if ((!cur_filter) || (0 == strlen(cur_filter)))
209 new_filter = g_strdup(text);
211 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
214 case MATCH_SELECTED_OR:
215 if ((!cur_filter) || (0 == strlen(cur_filter)))
216 new_filter = g_strdup(text);
218 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
221 case MATCH_SELECTED_NOT:
222 new_filter = g_strconcat("!(", text, ")", NULL);
225 case MATCH_SELECTED_AND_NOT:
226 if ((!cur_filter) || (0 == strlen(cur_filter)))
227 new_filter = g_strconcat("!(", text, ")", NULL);
229 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
232 case MATCH_SELECTED_OR_NOT:
233 if ((!cur_filter) || (0 == strlen(cur_filter)))
234 new_filter = g_strconcat("!(", text, ")", NULL);
236 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
240 g_assert_not_reached();
245 /* Free up the copy we got of the old filter text. */
248 /* create a new one and set the display filter entry accordingly */
249 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
251 /* Run the display filter so it goes in effect. */
252 if (action&MATCH_SELECTED_APPLY_NOW)
253 main_filter_packets(&cfile, new_filter, FALSE);
255 /* Free up the new filter text. */
258 /* Free up the generated text we were handed. */
263 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
265 if (cfile.finfo_selected)
266 match_selected_cb_do((data ? data : w),
268 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
273 get_text_from_packet_list(gpointer data)
275 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
276 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
277 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
285 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
286 cfile.pd, fdata->cap_len, &err, &err_info)) {
287 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
288 cf_read_error_message(err, err_info), cfile.filename);
292 edt = epan_dissect_new(FALSE, FALSE);
293 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
295 epan_dissect_fill_in_columns(edt);
297 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
298 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
299 len = strlen(cfile.cinfo.col_expr[column]) +
300 strlen(cfile.cinfo.col_expr_val[column]) + 5;
301 buf = g_malloc0(len);
302 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
303 cfile.cinfo.col_expr_val[column]);
306 epan_dissect_free(edt);
313 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
315 match_selected_cb_do(data,
317 get_text_from_packet_list(data));
322 /* XXX: use a preference for this setting! */
323 static guint dfilter_combo_max_recent = 10;
325 /* add a display filter to the combo box */
326 /* Note: a new filter string will replace an old identical one */
328 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
330 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
333 /* GtkCombos don't let us get at their list contents easily, so we maintain
334 our own filter list, and feed it to gtk_combo_set_popdown_strings when
335 a new filter is added. */
336 li = g_list_first(filter_list);
338 /* If the filter is already in the list, remove the old one and
339 * append the new one at the latest position (at g_list_append() below) */
340 if (li->data && strcmp(s, li->data) == 0) {
341 filter_list = g_list_remove(filter_list, li->data);
347 filter_list = g_list_append(filter_list, s);
348 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
349 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
350 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data);
356 /* write all non empty display filters (until maximum count)
357 * of the combo box GList to the user's recent file */
359 dfilter_recent_combo_write_all(FILE *rf) {
360 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
361 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
366 /* write all non empty display filter strings to the recent file (until max count) */
367 li = g_list_first(filter_list);
368 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
369 if (strlen(li->data)) {
370 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
376 /* empty the combobox entry field */
378 dfilter_combo_add_empty(void) {
379 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
381 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
385 /* add a display filter coming from the user's recent file to the dfilter combo box */
387 dfilter_combo_add_recent(gchar *s) {
388 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
392 if (!dfilter_combo_add(filter_cm, dup)) {
401 /* call filter_packets() and add this filter string to the recent filter list */
403 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
405 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
406 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
408 gboolean add_filter = TRUE;
409 gboolean free_filter = TRUE;
411 gboolean filter_packets_ret;
413 s = g_strdup(dftext);
415 /* GtkCombos don't let us get at their list contents easily, so we maintain
416 our own filter list, and feed it to gtk_combo_set_popdown_strings when
417 a new filter is added. */
418 if ((filter_packets_ret = filter_packets(cf, s, force))) {
419 li = g_list_first(filter_list);
421 if (li->data && strcmp(s, li->data) == 0)
427 /* trim list size first */
428 while (g_list_length(filter_list) >= dfilter_combo_max_recent) {
429 filter_list = g_list_remove(filter_list, g_list_first(filter_list)->data);
433 filter_list = g_list_append(filter_list, s);
434 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
435 gtk_combo_set_popdown_strings(filter_cm, filter_list);
436 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
442 return filter_packets_ret;
446 /* Run the current display filter on the current packet set, and
449 filter_activate_cb(GtkWidget *w _U_, gpointer data)
453 s = gtk_entry_get_text(GTK_ENTRY(data));
455 main_filter_packets(&cfile, s, FALSE);
458 /* redisplay with no display filter */
460 filter_reset_cb(GtkWidget *w, gpointer data _U_)
462 GtkWidget *filter_te = NULL;
464 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
465 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
467 main_filter_packets(&cfile, "", FALSE);
470 /* mark as reference time frame */
472 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
476 frame->flags.ref_time=1;
478 frame->flags.ref_time=0;
480 reftime_packets(&cfile);
484 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
489 if (cfile.current_frame) {
490 /* XXX hum, should better have a "cfile->current_row" here ... */
491 set_frame_reftime(!cfile.current_frame->flags.ref_time,
493 packet_list_find_row_from_data(cfile.current_frame));
496 case REFTIME_FIND_NEXT:
497 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
499 case REFTIME_FIND_PREV:
500 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
505 #if GTK_MAJOR_VERSION < 2
507 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
508 gpointer user_data _U_)
511 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
515 gchar *help_str = NULL;
516 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
518 gboolean has_blurb = FALSE;
519 guint length = 0, byte_len;
520 GtkWidget *byte_view;
521 const guint8 *byte_data;
522 #if GTK_MAJOR_VERSION >= 2
527 #if GTK_MAJOR_VERSION >= 2
528 /* if nothing is selected */
529 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
532 * Which byte view is displaying the current protocol tree
535 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
536 if (byte_view == NULL)
539 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
540 if (byte_data == NULL)
543 unselect_field(&cfile);
544 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
545 cfile.current_frame, NULL, byte_len);
548 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
551 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
555 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
557 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
558 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
559 g_assert(byte_data != NULL);
561 cfile.finfo_selected = finfo;
562 set_menus_for_selected_tree_row(&cfile);
565 if (finfo->hfinfo->blurb != NULL &&
566 finfo->hfinfo->blurb[0] != '\0') {
568 length = strlen(finfo->hfinfo->blurb);
570 length = strlen(finfo->hfinfo->name);
572 if (finfo->length == 0) {
574 } else if (finfo->length == 1) {
575 strcpy (len_str, ", 1 byte");
577 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
579 statusbar_pop_field_msg(); /* get rid of current help msg */
581 help_str = g_strdup_printf("%s (%s)%s",
582 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
583 finfo->hfinfo->abbrev, len_str);
584 statusbar_push_field_msg(help_str);
588 * Don't show anything if the field name is zero-length;
589 * the pseudo-field for "proto_tree_add_text()" is such
590 * a field, and we don't want "Text (text)" showing up
591 * on the status line if you've selected such a field.
593 * XXX - there are zero-length fields for which we *do*
594 * want to show the field name.
596 * XXX - perhaps the name and abbrev field should be null
597 * pointers rather than null strings for that pseudo-field,
598 * but we'd have to add checks for null pointers in some
599 * places if we did that.
601 * Or perhaps protocol tree items added with
602 * "proto_tree_add_text()" should have -1 as the field index,
603 * with no pseudo-field being used, but that might also
604 * require special checks for -1 to be added.
606 statusbar_push_field_msg("");
610 #if GTK_MAJOR_VERSION < 2
611 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
614 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
619 #if GTK_MAJOR_VERSION < 2
621 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
622 gpointer user_data _U_)
624 GtkWidget *byte_view;
629 * Which byte view is displaying the current protocol tree
632 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
633 if (byte_view == NULL)
636 data = get_byte_view_data_and_length(byte_view, &len);
640 unselect_field(&cfile);
641 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
646 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
648 collapse_all_tree(cfile.edt->tree, tree_view);
651 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
653 expand_all_tree(cfile.edt->tree, tree_view);
656 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
657 #if GTK_MAJOR_VERSION < 2
663 #if GTK_MAJOR_VERSION < 2
664 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
666 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
668 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
670 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
671 gtk_tree_path_free(path);
675 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
676 if (cfile.edt->tree) {
677 guint32 tmp = g_resolv_flags;
678 g_resolv_flags = RESOLV_ALL;
679 proto_tree_draw(cfile.edt->tree, tree_view);
680 g_resolv_flags = tmp;
685 * Push a message referring to file access onto the statusbar.
688 statusbar_push_file_msg(gchar *msg)
690 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
694 * Pop a message referring to file access off the statusbar.
697 statusbar_pop_file_msg(void)
699 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
703 * XXX - do we need multiple statusbar contexts?
707 * Push a message referring to the currently-selected field onto the statusbar.
710 statusbar_push_field_msg(gchar *msg)
712 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
716 * Pop a message referring to the currently-selected field off the statusbar.
719 statusbar_pop_field_msg(void)
721 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
725 * update the packets statusbar to the current values
727 void packets_bar_update(void)
731 /* remove old status */
734 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
737 /* do we have any packets? */
739 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
740 cfile.count, cfile.displayed_count, cfile.marked_count);
742 packets_str = g_strdup(" No Packets");
744 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
755 /* get the current geometry, before writing it to disk */
756 main_save_window_geometry(top_level);
758 /* write user's recent file to disk
759 * It is no problem to write this file, even if we do not quit */
760 write_recent(&rec_path);
762 /* XXX - should we check whether the capture file is an
763 unsaved temporary file for a live capture and, if so,
764 pop up a "do you want to exit without saving the capture
765 file?" dialog, and then just return, leaving said dialog
766 box to forcibly quit if the user clicks "OK"?
768 If so, note that this should be done in a subroutine that
769 returns TRUE if we do so, and FALSE otherwise, and if it
770 returns TRUE we should return TRUE without nuking anything.
772 Note that, if we do that, we might also want to check if
773 an "Update list of packets in real time" capture is in
774 progress and, if so, ask whether they want to terminate
775 the capture and discard it, and return TRUE, before nuking
776 any child capture, if they say they don't want to do so. */
779 /* Nuke any child capture in progress. */
780 kill_capture_child();
783 /* Are we in the middle of reading a capture? */
784 if (cfile.state == FILE_READ_IN_PROGRESS) {
785 /* Yes, so we can't just close the file and quit, as
786 that may yank the rug out from under the read in
787 progress; instead, just set the state to
788 "FILE_READ_ABORTED" and return - the code doing the read
789 will check for that and, if it sees that, will clean
791 cfile.state = FILE_READ_ABORTED;
793 /* Say that the window should *not* be deleted;
794 that'll be done by the code that cleans up. */
797 /* Close any capture file we have open; on some OSes, you
798 can't unlink a temporary capture file if you have it
800 "cf_close()" will unlink it after closing it if
801 it's a temporary file.
803 We do this here, rather than after the main loop returns,
804 as, after the main loop returns, the main window may have
805 been destroyed (if this is called due to a "destroy"
806 even on the main window rather than due to the user
807 selecting a menu item), and there may be a crash
808 or other problem when "cf_close()" tries to
809 clean up stuff in the main window.
811 XXX - is there a better place to put this?
812 Or should we have a routine that *just* closes the
813 capture file, and doesn't do anything with the UI,
814 which we'd call here, and another routine that
815 calls that routine and also cleans up the UI, which
816 we'd call elsewhere? */
819 /* Exit by leaving the main loop, so that any quit functions
820 we registered get called. */
823 /* Say that the window should be deleted. */
829 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
833 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
834 #if GTK_MAJOR_VERSION >= 2
835 gtk_window_present(GTK_WINDOW(top_level));
837 /* user didn't saved his current file, ask him */
838 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
839 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
840 "If you quit the program without saving, your capture data will be discarded.");
841 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
844 /* unchanged file, just exit */
845 /* "main_do_quit()" indicates whether the main window should be deleted. */
846 return main_do_quit();
853 main_load_window_geometry(GtkWidget *widget)
855 window_geometry_t geom;
857 geom.set_pos = prefs.gui_geometry_save_position;
858 geom.x = recent.gui_geometry_main_x;
859 geom.y = recent.gui_geometry_main_y;
860 geom.set_size = prefs.gui_geometry_save_size;
861 if (recent.gui_geometry_main_width > 0 &&
862 recent.gui_geometry_main_height > 0) {
863 geom.width = recent.gui_geometry_main_width;
864 geom.height = recent.gui_geometry_main_height;
865 geom.set_maximized = prefs.gui_geometry_save_maximized;
867 /* We assume this means the width and height weren't set in
868 the "recent" file (or that there is no "recent" file),
869 and weren't set to a default value, so we don't set the
870 size. (The "recent" file code rejects non-positive width
871 and height values.) */
872 geom.set_size = FALSE;
874 geom.maximized = recent.gui_geometry_main_maximized;
876 window_set_geometry(widget, &geom);
878 #if GTK_MAJOR_VERSION >= 2
879 /* XXX - rename recent settings? */
880 if (recent.gui_geometry_main_upper_pane)
881 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
882 if (recent.gui_geometry_main_lower_pane)
883 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
884 if (recent.gui_geometry_status_pane)
885 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
891 main_save_window_geometry(GtkWidget *widget)
893 window_geometry_t geom;
895 window_get_geometry(widget, &geom);
897 if (prefs.gui_geometry_save_position) {
898 recent.gui_geometry_main_x = geom.x;
899 recent.gui_geometry_main_y = geom.y;
902 if (prefs.gui_geometry_save_size) {
903 recent.gui_geometry_main_width = geom.width,
904 recent.gui_geometry_main_height = geom.height;
907 #if GTK_MAJOR_VERSION >= 2
908 if(prefs.gui_geometry_save_maximized) {
909 recent.gui_geometry_main_maximized = geom.maximized;
912 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
913 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
914 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
918 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
922 /* save file first */
923 file_save_as_cmd(after_save_exit, NULL);
925 case(ESD_BTN_DONT_SAVE):
928 case(ESD_BTN_CANCEL):
931 g_assert_not_reached();
936 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
940 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
941 /* user didn't saved his current file, ask him */
942 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
943 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
944 "If you quit the program without saving, your capture data will be discarded.");
945 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
947 /* unchanged file, just exit */
953 print_usage(gboolean print_ver) {
959 fprintf(output, "This is GNU " PACKAGE " " VERSION
964 comp_info_str->str, runtime_info_str->str);
969 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n",
971 fprintf(output, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
972 fprintf(output, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
973 fprintf(output, "\t[ -i <interface> ] [ -m <medium font> ] [ -N <resolving> ]\n");
974 fprintf(output, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
975 fprintf(output, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
976 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
977 fprintf(output, "\t[ -w <savefile> ] [ -y <link type> ] [ -z <statistics string> ]\n");
978 fprintf(output, "\t[ <infile> ]\n");
980 fprintf(output, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n",
982 fprintf(output, "\t[ -N <resolving> ] [ -o <preference setting> ...\n");
983 fprintf(output, "\t[ -P <packet list height> ] [ -r <infile> ] [ -R <read filter> ]\n");
984 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
985 fprintf(output, "\t[ -z <statistics string> ] [ <infile> ]\n");
996 printf(PACKAGE " " VERSION
1001 comp_info_str->str, runtime_info_str->str);
1005 get_natural_int(const char *string, const char *name)
1010 number = strtol(string, &p, 10);
1011 if (p == string || *p != '\0') {
1012 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1017 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1021 if (number > INT_MAX) {
1022 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1023 name, string, INT_MAX);
1030 get_positive_int(const char *string, const char *name)
1034 number = get_natural_int(string, name);
1037 fprintf(stderr, "ethereal: The specified %s is zero\n",
1047 * Given a string of the form "<autostop criterion>:<value>", as might appear
1048 * as an argument to a "-a" option, parse it and set the criterion in
1049 * question. Return an indication of whether it succeeded or failed
1053 set_autostop_criterion(const char *autostoparg)
1057 colonp = strchr(autostoparg, ':');
1065 * Skip over any white space (there probably won't be any, but
1066 * as we allow it in the preferences file, we might as well
1069 while (isspace((guchar)*p))
1073 * Put the colon back, so if our caller uses, in an
1074 * error message, the string they passed us, the message
1080 if (strcmp(autostoparg,"duration") == 0) {
1081 capture_opts.has_autostop_duration = TRUE;
1082 capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1083 } else if (strcmp(autostoparg,"filesize") == 0) {
1084 capture_opts.has_autostop_filesize = TRUE;
1085 capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1089 *colonp = ':'; /* put the colon back */
1094 * Given a string of the form "<ring buffer file>:<duration>", as might appear
1095 * as an argument to a "-b" option, parse it and set the arguments in
1096 * question. Return an indication of whether it succeeded or failed
1100 get_ring_arguments(const char *arg)
1102 gchar *p = NULL, *colonp;
1104 colonp = strchr(arg, ':');
1106 if (colonp != NULL) {
1111 capture_opts.ring_num_files =
1112 get_natural_int(arg, "number of ring buffer files");
1118 * Skip over any white space (there probably won't be any, but
1119 * as we allow it in the preferences file, we might as well
1122 while (isspace((guchar)*p))
1126 * Put the colon back, so if our caller uses, in an
1127 * error message, the string they passed us, the message
1134 capture_opts.has_file_duration = TRUE;
1135 capture_opts.file_duration = get_positive_int(p,
1136 "ring buffer duration");
1138 *colonp = ':'; /* put the colon back */
1143 #if defined WIN32 || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1145 Once every 3 seconds we get a callback here which we use to update
1146 the tap extensions. Since Gtk1 is single threaded we dont have to
1147 worry about any locking or critical regions.
1150 update_cb(gpointer data _U_)
1152 draw_tap_listeners(FALSE);
1157 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1158 use threads all updte_thread_mutex can be dropped and protect/unprotect
1159 would just be empty functions.
1161 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1162 gtk1-ethereal and it will just work.
1164 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1166 update_thread(gpointer data _U_)
1170 g_get_current_time(&tv1);
1171 g_static_mutex_lock(&update_thread_mutex);
1172 gdk_threads_enter();
1173 draw_tap_listeners(FALSE);
1174 gdk_threads_leave();
1175 g_static_mutex_unlock(&update_thread_mutex);
1177 g_get_current_time(&tv2);
1178 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1179 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1180 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1181 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1188 protect_thread_critical_region(void)
1190 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1191 g_static_mutex_lock(&update_thread_mutex);
1195 unprotect_thread_critical_region(void)
1197 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1198 g_static_mutex_unlock(&update_thread_mutex);
1202 /* structure to keep track of what tap listeners have been registered.
1204 typedef struct _ethereal_tap_list {
1205 struct _ethereal_tap_list *next;
1207 void (*func)(char *arg);
1208 } ethereal_tap_list;
1209 static ethereal_tap_list *tap_list=NULL;
1212 register_ethereal_tap(char *cmd, void (*func)(char *arg))
1214 ethereal_tap_list *newtl;
1216 newtl=malloc(sizeof(ethereal_tap_list));
1217 newtl->next=tap_list;
1225 enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL };
1227 /* convert drag and drop URI to a local filename */
1229 dnd_uri2filename(gchar *cf_name)
1238 * Remove URI header.
1239 * On win32 (at least WinXP), this string looks like (UNC or local filename):
1240 * file:////servername/sharename/dir1/dir2/capture-file.cap
1242 * file:///d:/dir1/dir2/capture-file.cap
1243 * we have to remove the prefix to get a valid filename.
1245 * On UNIX (at least KDE 3.0 Konqueror), this string looks like:
1246 * file:/dir1/dir2/capture-file.cap
1247 * we have to remove the file: to get a valid filename.
1249 if (strncmp("file:////", cf_name, 9) == 0) {
1250 /* win32 UNC: now becoming: //servername/sharename/dir1/dir2/capture-file.cap */
1252 } else if (strncmp("file:///", cf_name, 8) == 0) {
1253 /* win32 local: now becoming: d:/dir1/dir2/capture-file.cap */
1255 } else if (strncmp("file:", cf_name, 5) == 0) {
1256 /* unix local: now becoming: /dir1/dir2/capture-file.cap */
1261 * unescape the escaped URI characters (spaces, ...)
1263 * we have to replace escaped chars to their equivalents,
1264 * e.g. %20 (always a two digit hexstring) -> ' '
1265 * the percent character '%' is escaped be a double one "%%"
1267 * we do this conversation "in place" as the result is always
1268 * equal or smaller in size.
1276 /* this is an escaped '%' char (was: "%%") */
1281 /* convert escaped hexnumber to unscaped character */
1285 ret = sscanf(esc, "%x", &i);
1291 /* somethings wrong, just jump over that char
1292 * this will result in a wrong string, but we might get
1293 * user feedback and can fix it later ;-) */
1309 dnd_merge_files(int in_file_count, char **in_filenames)
1314 char tmpname[128+1];
1317 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
1319 /* merge the files in chonological order */
1320 merge_ok = merge_n_files(out_fd, in_file_count, in_filenames, FALSE, &err);
1324 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1325 "An error occurred while merging the files: \"%s\".",
1326 wtap_strerror(err));
1333 /* Try to open the merged capture file. */
1334 if ((err = cf_open(tmpname, TRUE /* temporary file */, &cfile)) != 0) {
1335 /* We couldn't open it; don't dismiss the open dialog box,
1336 just leave it around so that the user can, after they
1337 dismiss the alert box popped up for the open error,
1342 switch (cf_read(&cfile)) {
1346 /* Just because we got an error, that doesn't mean we were unable
1347 to read any of the file; we handle what we could get from the
1352 /* The user bailed out of re-reading the capture file; the
1353 capture file has been closed - just free the capture file name
1354 string and return (without changing the last containing
1359 gtk_widget_grab_focus(packet_list);
1362 /* open/merge the dnd file */
1364 dnd_open_file_cmd(GtkSelectionData *selection_data)
1367 gchar *cf_name, *cf_name_freeme;
1370 GString *dialog_text;
1372 char **in_filenames;
1375 /* DND_TARGET_URL on Win32:
1376 * The selection_data->data is a single string, containing one or more URI's,
1377 * seperated by CR/NL chars. The length of the whole field can be found
1378 * in the selection_data->length field. If it contains one file, simply open it,
1379 * If it contains more than one file, ask to merge these files. */
1381 /* the data string is not zero terminated -> make a zero terminated "copy" of it */
1382 cf_name_freeme = g_malloc(selection_data->length + 1);
1383 memcpy(cf_name_freeme, selection_data->data, selection_data->length);
1384 cf_name_freeme[selection_data->length] = '\0';
1386 /* count the number of input files */
1387 cf_name = cf_name_freeme;
1388 for(in_files = 0; (cf_name = strstr(cf_name, "\r\n")) != NULL; ) {
1393 in_filenames = g_malloc(sizeof(char*) * in_files);
1395 /* store the starts of the file entries in a gchar array */
1396 cf_name = cf_name_freeme;
1397 in_filenames[0] = cf_name;
1398 for(files_work = 1; (cf_name = strstr(cf_name, "\r\n")) != NULL && files_work < in_files; ) {
1400 in_filenames[files_work] = cf_name;
1404 /* replace trailing CR NL simply with zeroes (in place), so we get valid terminated strings */
1405 cf_name = cf_name_freeme;
1406 g_strdelimit(cf_name, "\r\n", '\0');
1408 /* convert all filenames from URI to local filename (in place) */
1409 for(files_work = 0; files_work < in_files; files_work++) {
1410 in_filenames[files_work] = dnd_uri2filename(in_filenames[files_work]);
1415 /* shouldn't happen */
1418 /* open and read the capture file (this will close an existing file) */
1419 if ((err = cf_open(in_filenames[0], FALSE, &cfile)) == 0) {
1421 add_menu_recent_capture_file(in_filenames[0]);
1423 /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */
1427 /* build and show the info dialog */
1428 dialog_text = g_string_sized_new(200);
1429 g_string_append(dialog_text, PRIMARY_TEXT_START
1430 "Merging the following files:" PRIMARY_TEXT_END "\n\n");
1431 for(files_work = 0; files_work < in_files; files_work++) {
1432 g_string_append(dialog_text, in_filenames[files_work]);
1433 g_string_append(dialog_text, "\n");
1435 g_string_append(dialog_text, "\nThe packets in these files will be merged chronologically into a new temporary file.");
1436 dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
1439 g_string_free(dialog_text, TRUE);
1441 /* actually merge the files now */
1442 dnd_merge_files(in_files, in_filenames);
1445 g_free(in_filenames);
1446 g_free(cf_name_freeme);
1449 /* ask the user to save current unsaved file, before opening the dnd file */
1451 dnd_save_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1455 /* save file first */
1456 file_save_as_cmd(after_save_open_dnd_file, data);
1458 case(ESD_BTN_DONT_SAVE):
1460 dnd_open_file_cmd(data);
1462 case(ESD_BTN_CANCEL):
1465 g_assert_not_reached();
1470 /* we have received some drag and drop data */
1471 /* (as we only registered to "text/uri-list", we will only get a file list here) */
1473 dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_,
1474 GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_)
1478 if (info == DND_TARGET_URL) {
1479 /* ask the user to save it's current capture file first */
1480 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1481 /* user didn't saved his current file, ask him */
1482 dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
1483 ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1484 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1485 "If you open a new capture file without saving, your current capture data will be discarded.");
1486 simple_dialog_set_cb(dialog, dnd_save_file_answered_cb, selection_data);
1488 /* unchanged file */
1489 dnd_open_file_cmd(selection_data);
1494 /* init the drag and drop functionality */
1496 dnd_init(GtkWidget *w)
1498 /* we are only interested in the URI list containing filenames */
1499 static GtkTargetEntry target_entry[] = {
1500 /*{"STRING", 0, DND_TARGET_STRING},*/
1501 /*{"text/plain", 0, DND_TARGET_STRING},*/
1502 {"text/uri-list", 0, DND_TARGET_URL}
1505 /* set this window as a dnd destination */
1507 w, GTK_DEST_DEFAULT_ALL, target_entry,
1508 sizeof(target_entry) / sizeof(GtkTargetEntry),
1509 (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) );
1511 /* get notified, if some dnd coming in */
1512 gtk_signal_connect(GTK_OBJECT(w), "drag_data_received",
1513 GTK_SIGNAL_FUNC(dnd_data_received), NULL);
1517 /* And now our feature presentation... [ fade to music ] */
1519 main(int argc, char *argv[])
1527 extern char *optarg;
1528 gboolean arg_error = FALSE;
1536 char *gpf_path, *pf_path;
1537 char *cf_path, *df_path;
1538 char *gdp_path, *dp_path;
1539 int gpf_open_errno, gpf_read_errno;
1540 int pf_open_errno, pf_read_errno;
1541 int cf_open_errno, df_open_errno;
1542 int gdp_open_errno, gdp_read_errno;
1543 int dp_open_errno, dp_read_errno;
1546 gboolean start_capture = FALSE;
1547 gchar *save_file = NULL;
1550 GList *lt_list, *lt_entry;
1551 data_link_info_t *data_link_info;
1552 gchar err_str[PCAP_ERRBUF_SIZE];
1553 gchar *cant_get_if_list_errstr;
1554 gboolean stats_known;
1555 struct pcap_stat stats;
1557 gboolean capture_option_specified = FALSE;
1559 gint pl_size = 280, tv_size = 95, bv_size = 75;
1560 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1561 dfilter_t *rfcode = NULL;
1562 gboolean rfilter_parse_failed = FALSE;
1565 ethereal_tap_list *tli = NULL;
1566 gchar *tap_opt = NULL;
1567 GtkWidget *splash_win = NULL;
1569 #define OPTSTRING_INIT "a:b:B:c:f:Hhi:klLm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:"
1573 #define OPTSTRING_CHILD "W:Z:"
1575 #define OPTSTRING_CHILD "W:"
1578 #define OPTSTRING_CHILD ""
1579 #endif /* HAVE_LIBPCAP */
1581 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1585 /* Set the current locale according to the program environment.
1586 * We haven't localized anything, but some GTK widgets are localized
1587 * (the file selection dialogue, for example).
1588 * This also sets the C-language locale to the native environment. */
1591 /* Let GTK get its args */
1592 gtk_init (&argc, &argv);
1595 ethereal_path = argv[0];
1598 /* Arrange that if we have no console window, and a GLib message logging
1599 routine is called to log a message, we pop up a console window.
1601 We do that by inserting our own handler for all messages logged
1602 to the default domain; that handler pops up a console if necessary,
1603 and then calls the default handler. */
1604 g_log_set_handler(NULL,
1606 G_LOG_LEVEL_CRITICAL|
1607 G_LOG_LEVEL_WARNING|
1608 G_LOG_LEVEL_MESSAGE|
1611 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1612 console_log_handler, NULL);
1615 command_name = get_basename(ethereal_path);
1616 /* Set "capture_child" to indicate whether this is going to be a child
1617 process for a "-S" capture. */
1618 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1619 if (capture_child) {
1620 strcat(optstring, OPTSTRING_CHILD);
1621 } else if (argc < 2 || strcmp(argv[1], "-G") != 0) {
1622 /* We want a splash screen only if we're not a child process */
1623 splash_win = splash_new("Loading Ethereal ...");
1627 splash_update(splash_win, "Registering dissectors ...");
1629 /* Register all dissectors; we must do this before checking for the
1630 "-G" flag, as the "-G" flag dumps information registered by the
1631 dissectors, and we must do it before we read the preferences, in
1632 case any dissectors register preferences. */
1633 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1634 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1636 splash_update(splash_win, "Registering tap listeners ...");
1638 /* Register all tap listeners; we do this before we parse the arguments,
1639 as the "-z" argument can specify a registered tap. */
1640 register_all_tap_listeners();
1642 splash_update(splash_win, "Loading module preferences ...");
1644 /* Now register the preferences for any non-dissector modules.
1645 We must do that before we read the preferences as well. */
1646 prefs_register_modules();
1648 /* If invoked with the "-G" flag, we dump out information based on
1649 the argument to the "-G" flag; if no argument is specified,
1650 for backwards compatibility we dump out a glossary of display
1653 We must do this before calling "gtk_init()", because "gtk_init()"
1654 tries to open an X display, and we don't want to have to do any X
1655 stuff just to do a build.
1657 Given that we call "gtk_init()" before doing the regular argument
1658 list processing, so that it can handle X and GTK+ arguments and
1659 remove them from the list at which we look, this means we must do
1660 this before doing the regular argument list processing, as well.
1664 you must give the "-G" flag as the first flag on the command line;
1666 you must give it as "-G", nothing more, nothing less;
1668 the first argument after the "-G" flag, if present, will be used
1669 to specify the information to dump;
1671 arguments after that will not be used. */
1672 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1674 proto_registrar_dump_fields();
1676 if (strcmp(argv[2], "fields") == 0)
1677 proto_registrar_dump_fields();
1678 else if (strcmp(argv[2], "protocols") == 0)
1679 proto_registrar_dump_protocols();
1681 fprintf(stderr, "ethereal: Invalid \"%s\" option for -G flag\n",
1689 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1690 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined G_THREADS_ENABLED && defined USE_THREADS
1693 g_thread_init(NULL);
1695 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1696 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1698 #else /* WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1699 /* this is to keep tap extensions updating once every 3 seconds */
1700 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1701 #endif /* !WIN32 && GTK2 && G_THREADS_ENABLED */
1704 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1707 splash_update(splash_win, "Loading configuration files ...");
1709 /* Read the preference files. */
1710 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1711 &pf_open_errno, &pf_read_errno, &pf_path);
1712 if (gpf_path != NULL) {
1713 if (gpf_open_errno != 0) {
1714 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1715 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1716 strerror(gpf_open_errno));
1718 if (gpf_read_errno != 0) {
1719 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1720 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1721 strerror(gpf_read_errno));
1724 if (pf_path != NULL) {
1725 if (pf_open_errno != 0) {
1726 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1727 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1728 strerror(pf_open_errno));
1730 if (pf_read_errno != 0) {
1731 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1732 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1733 strerror(pf_read_errno));
1740 if (prefs->gui_console_open == console_open_always) {
1746 capture_opts.has_snaplen = FALSE;
1747 capture_opts.snaplen = MIN_PACKET_SIZE;
1748 capture_opts.linktype = -1;
1750 capture_opts.buffer_size = 1;
1753 capture_opts.has_autostop_packets = FALSE;
1754 capture_opts.autostop_packets = 1;
1755 capture_opts.has_autostop_duration = FALSE;
1756 capture_opts.autostop_duration = 60 /* 1 min */;
1757 capture_opts.has_autostop_filesize = FALSE;
1758 capture_opts.autostop_filesize = 1024 * 1024 /* 1 MB */;
1759 capture_opts.has_autostop_files = FALSE;
1760 capture_opts.autostop_files = 1;
1762 capture_opts.multi_files_on = FALSE;
1763 capture_opts.has_ring_num_files = TRUE;
1764 capture_opts.ring_num_files = 2;
1765 capture_opts.has_file_duration = FALSE;
1766 capture_opts.file_duration = 60 /* 1 min */;
1768 /* If this is a capture child process, it should pay no attention
1769 to the "prefs.capture_prom_mode" setting in the preferences file;
1770 it should do what the parent process tells it to do, and if
1771 the parent process wants it not to run in promiscuous mode, it'll
1772 tell it so with a "-p" flag.
1774 Otherwise, set promiscuous mode from the preferences setting. */
1775 /* the same applies to other preferences settings as well. */
1776 if (capture_child) {
1777 capture_opts.promisc_mode = TRUE; /* maybe changed by command line below */
1778 capture_opts.show_info = TRUE; /* maybe changed by command line below */
1779 capture_opts.sync_mode = TRUE; /* always true in child process */
1780 auto_scroll_live = FALSE; /* doesn't matter in child process */
1783 capture_opts.promisc_mode = prefs->capture_prom_mode;
1784 capture_opts.show_info = prefs->capture_show_info;
1785 capture_opts.sync_mode = prefs->capture_real_time;
1786 auto_scroll_live = prefs->capture_auto_scroll;
1789 #endif /* HAVE_LIBPCAP */
1791 /* Set the name resolution code's flags from the preferences. */
1792 g_resolv_flags = prefs->name_resolve;
1794 /* Read the capture filter file. */
1795 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1796 if (cf_path != NULL) {
1797 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1798 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1799 strerror(cf_open_errno));
1803 /* Read the display filter file. */
1804 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1805 if (df_path != NULL) {
1806 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1807 "Could not open your display filter file\n\"%s\": %s.", df_path,
1808 strerror(df_open_errno));
1812 /* Read the disabled protocols file. */
1813 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1814 &dp_path, &dp_open_errno, &dp_read_errno);
1815 if (gdp_path != NULL) {
1816 if (gdp_open_errno != 0) {
1817 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1818 "Could not open global disabled protocols file\n\"%s\": %s.",
1819 gdp_path, strerror(gdp_open_errno));
1821 if (gdp_read_errno != 0) {
1822 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1823 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1824 gdp_path, strerror(gdp_read_errno));
1828 if (dp_path != NULL) {
1829 if (dp_open_errno != 0) {
1830 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1831 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1832 strerror(dp_open_errno));
1834 if (dp_read_errno != 0) {
1835 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1836 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
1837 strerror(dp_read_errno));
1842 init_cap_file(&cfile);
1845 /* Load wpcap if possible. Do this before collecting the run-time version information */
1848 /* Start windows sockets */
1849 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1852 /* Assemble the compile-time version information string */
1853 comp_info_str = g_string_new("Compiled ");
1854 g_string_append(comp_info_str, "with ");
1855 g_string_sprintfa(comp_info_str,
1856 #ifdef GTK_MAJOR_VERSION
1857 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1860 "GTK+ (version unknown)");
1863 g_string_append(comp_info_str, ", ");
1864 get_compiled_version_info(comp_info_str);
1866 /* Assemble the run-time version information string */
1867 runtime_info_str = g_string_new("Running ");
1868 get_runtime_version_info(runtime_info_str);
1870 /* Now get our args */
1871 while ((opt = getopt(argc, argv, optstring)) != -1) {
1873 case 'a': /* autostop criteria */
1875 if (set_autostop_criterion(optarg) == FALSE) {
1876 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1880 capture_option_specified = TRUE;
1884 case 'b': /* Ringbuffer option */
1886 capture_opts.multi_files_on = TRUE;
1887 capture_opts.has_ring_num_files = TRUE;
1888 if (get_ring_arguments(optarg) == FALSE) {
1889 fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
1893 capture_option_specified = TRUE;
1897 case 'B': /* Byte view pane height */
1898 bv_size = get_positive_int(optarg, "byte view pane height");
1900 case 'c': /* Capture xxx packets */
1902 capture_opts.has_autostop_packets = TRUE;
1903 capture_opts.autostop_packets = get_positive_int(optarg, "packet count");
1905 capture_option_specified = TRUE;
1912 g_free(cfile.cfilter);
1913 cfile.cfilter = g_strdup(optarg);
1915 capture_option_specified = TRUE;
1919 case 'h': /* Print help and exit */
1923 case 'i': /* Use interface xxx */
1925 cfile.iface = g_strdup(optarg);
1927 capture_option_specified = TRUE;
1931 case 'k': /* Start capture immediately */
1933 start_capture = TRUE;
1935 capture_option_specified = TRUE;
1939 case 'l': /* Automatic scrolling in live capture mode */
1941 auto_scroll_live = TRUE;
1943 capture_option_specified = TRUE;
1947 case 'H': /* Hide capture info dialog box */
1949 capture_opts.show_info = FALSE;
1951 capture_option_specified = TRUE;
1955 case 'L': /* Print list of link-layer types and exit */
1957 list_link_layer_types = TRUE;
1959 capture_option_specified = TRUE;
1963 case 'm': /* Fixed-width font for the display */
1964 if (prefs->PREFS_GUI_FONT_NAME != NULL)
1965 g_free(prefs->PREFS_GUI_FONT_NAME);
1966 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
1968 case 'n': /* No name resolution */
1969 g_resolv_flags = RESOLV_NONE;
1971 case 'N': /* Select what types of addresses/port #s to resolve */
1972 if (g_resolv_flags == RESOLV_ALL)
1973 g_resolv_flags = RESOLV_NONE;
1974 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1975 if (badopt != '\0') {
1976 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1981 case 'o': /* Override preference from command line */
1982 switch (prefs_set_pref(optarg)) {
1984 case PREFS_SET_SYNTAX_ERR:
1985 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1989 case PREFS_SET_NO_SUCH_PREF:
1990 case PREFS_SET_OBSOLETE:
1991 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1997 case 'p': /* Don't capture in promiscuous mode */
1999 capture_opts.promisc_mode = FALSE;
2001 capture_option_specified = TRUE;
2005 case 'P': /* Packet list pane height */
2006 pl_size = get_positive_int(optarg, "packet list pane height");
2008 case 'Q': /* Quit after capture (just capture to file) */
2010 quit_after_cap = TRUE;
2011 start_capture = TRUE; /*** -Q implies -k !! ***/
2013 capture_option_specified = TRUE;
2017 case 'r': /* Read capture file xxx */
2018 /* We may set "last_open_dir" to "cf_name", and if we change
2019 "last_open_dir" later, we free the old value, so we have to
2020 set "cf_name" to something that's been allocated. */
2021 cf_name = g_strdup(optarg);
2023 case 'R': /* Read file filter */
2026 case 's': /* Set the snapshot (capture) length */
2028 capture_opts.has_snaplen = TRUE;
2029 capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
2031 capture_option_specified = TRUE;
2035 case 'S': /* "Sync" mode: used for following file ala tail -f */
2037 capture_opts.sync_mode = TRUE;
2039 capture_option_specified = TRUE;
2043 case 't': /* Time stamp type */
2044 if (strcmp(optarg, "r") == 0)
2045 set_timestamp_setting(TS_RELATIVE);
2046 else if (strcmp(optarg, "a") == 0)
2047 set_timestamp_setting(TS_ABSOLUTE);
2048 else if (strcmp(optarg, "ad") == 0)
2049 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
2050 else if (strcmp(optarg, "d") == 0)
2051 set_timestamp_setting(TS_DELTA);
2053 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
2055 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
2056 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
2060 case 'T': /* Tree view pane height */
2061 tv_size = get_positive_int(optarg, "tree view pane height");
2063 case 'v': /* Show version and exit */
2070 case 'w': /* Write to capture file xxx */
2072 save_file = g_strdup(optarg);
2074 capture_option_specified = TRUE;
2078 case 'y': /* Set the pcap data link type */
2080 #ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
2081 capture_opts.linktype = pcap_datalink_name_to_val(optarg);
2082 if (capture_opts.linktype == -1) {
2083 fprintf(stderr, "ethereal: The specified data link type \"%s\" is not valid\n",
2087 #else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
2088 /* XXX - just treat it as a number */
2089 capture_opts.linktype = get_natural_int(optarg, "data link type");
2090 #endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
2091 #else /* HAVE_LIBPCAP */
2092 capture_option_specified = TRUE;
2094 #endif /* HAVE_LIBPCAP */
2097 /* This is a hidden option supporting Sync mode, so we don't set
2098 * the error flags for the user in the non-libpcap case.
2100 case 'W': /* Write to capture file FD xxx */
2101 cfile.save_file_fd = atoi(optarg);
2105 for(tli=tap_list;tli;tli=tli->next){
2106 if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
2107 tap_opt = g_strdup(optarg);
2112 fprintf(stderr,"ethereal: invalid -z argument.\n");
2113 fprintf(stderr," -z argument must be one of :\n");
2114 for(tli=tap_list;tli;tli=tli->next){
2115 fprintf(stderr," %s\n",tli->cmd);
2123 /* Hidden option supporting Sync mode */
2124 case 'Z': /* Write to pipe FD XXX */
2125 /* associate stdout with pipe */
2127 if (dup2(i, 1) < 0) {
2128 fprintf(stderr, "Unable to dup pipe handle\n");
2132 #endif /* HAVE_LIBPCAP */
2136 case '?': /* Bad flag - print usage message */
2144 if (cf_name != NULL) {
2146 * Input file name specified with "-r" *and* specified as a regular
2147 * command-line argument.
2152 * Input file name not specified with "-r", and a command-line argument
2153 * was specified; treat it as the input file name.
2155 * Yes, this is different from tethereal, where non-flag command-line
2156 * arguments are a filter, but this works better on GUI desktops
2157 * where a command can be specified to be run to open a particular
2158 * file - yes, you could have "-r" as the last part of the command,
2159 * but that's a bit ugly.
2161 cf_name = g_strdup(argv[0]);
2169 * Extra command line arguments were specified; complain.
2171 fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2175 #ifndef HAVE_LIBPCAP
2176 if (capture_option_specified)
2177 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2185 if (start_capture && list_link_layer_types) {
2186 /* Specifying *both* is bogus. */
2187 fprintf(stderr, "ethereal: You cannot specify both -L and a live capture.\n");
2191 if (list_link_layer_types) {
2192 /* We're supposed to list the link-layer types for an interface;
2193 did the user also specify a capture file to be read? */
2195 /* Yes - that's bogus. */
2196 fprintf(stderr, "ethereal: You cannot specify -L and a capture file to be read.\n");
2199 /* No - did they specify a ring buffer option? */
2200 if (capture_opts.multi_files_on) {
2201 fprintf(stderr, "ethereal: Ring buffer requested, but a capture is not being done.\n");
2205 /* We're supposed to do a live capture; did the user also specify
2206 a capture file to be read? */
2207 if (start_capture && cf_name) {
2208 /* Yes - that's bogus. */
2209 fprintf(stderr, "ethereal: You cannot specify both a live capture and a capture file to be read.\n");
2213 /* No - was the ring buffer option specified and, if so, does it make
2215 if (capture_opts.multi_files_on) {
2216 /* Ring buffer works only under certain conditions:
2217 a) ring buffer does not work with temporary files;
2218 b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
2219 sync_mode takes precedence;
2220 c) it makes no sense to enable the ring buffer if the maximum
2221 file size is set to "infinite". */
2222 if (save_file == NULL) {
2223 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2224 capture_opts.multi_files_on = FALSE;
2226 if (capture_opts.sync_mode) {
2227 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2228 capture_opts.multi_files_on = FALSE;
2230 if (!capture_opts.has_autostop_filesize) {
2231 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
2232 capture_opts.multi_files_on = FALSE;
2237 if (start_capture || list_link_layer_types) {
2238 /* Did the user specify an interface to use? */
2239 if (cfile.iface == NULL) {
2240 /* No - is a default specified in the preferences file? */
2241 if (prefs->capture_device != NULL) {
2243 cfile.iface = g_strdup(prefs->capture_device);
2245 /* No - pick the first one from the list of interfaces. */
2246 if_list = get_interface_list(&err, err_str);
2247 if (if_list == NULL) {
2250 case CANT_GET_INTERFACE_LIST:
2251 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2252 fprintf(stderr, "%s\n", cant_get_if_list_errstr);
2253 g_free(cant_get_if_list_errstr);
2256 case NO_INTERFACES_FOUND:
2257 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2262 if_info = if_list->data; /* first interface */
2263 cfile.iface = g_strdup(if_info->name);
2264 free_interface_list(if_list);
2269 if (capture_child) {
2270 if (cfile.save_file_fd == -1) {
2271 /* XXX - send this to the standard output as something our parent
2272 should put in an error message box? */
2273 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2278 if (list_link_layer_types) {
2279 /* Get the list of link-layer types for the capture device. */
2280 lt_list = get_pcap_linktype_list(cfile.iface, err_str);
2281 if (lt_list == NULL) {
2282 if (err_str[0] != '\0') {
2283 fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2284 "Please check to make sure you have sufficient permissions, and that\n"
2285 "you have the proper interface or pipe specified.\n", err_str);
2287 fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2290 fprintf(stderr, "Data link types (use option -y to set):\n");
2291 for (lt_entry = lt_list; lt_entry != NULL;
2292 lt_entry = g_list_next(lt_entry)) {
2293 data_link_info = lt_entry->data;
2294 fprintf(stderr, " %s", data_link_info->name);
2295 if (data_link_info->description != NULL)
2296 fprintf(stderr, " (%s)", data_link_info->description);
2298 fprintf(stderr, " (not supported)");
2301 free_pcap_linktype_list(lt_list);
2307 /* Notify all registered modules that have had any of their preferences
2308 changed either from one of the preferences file or from the command
2309 line that their preferences have changed. */
2312 /* disabled protocols as per configuration file */
2313 if (gdp_path == NULL && dp_path == NULL) {
2314 set_disabled_protos_list();
2317 /* Build the column format array */
2318 col_setup(&cfile.cinfo, prefs->num_cols);
2319 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2320 cfile.cinfo.col_fmt[i] = get_column_format(i);
2321 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2322 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2324 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2325 cfile.cinfo.col_data[i] = NULL;
2326 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2327 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2329 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2330 cfile.cinfo.col_fence[i] = 0;
2331 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2332 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2335 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2338 for (j = 0; j < NUM_COL_FMTS; j++) {
2339 if (!cfile.cinfo.fmt_matx[i][j])
2342 if (cfile.cinfo.col_first[j] == -1)
2343 cfile.cinfo.col_first[j] = i;
2344 cfile.cinfo.col_last[j] = i;
2349 if (capture_opts.has_snaplen) {
2350 if (capture_opts.snaplen < 1)
2351 capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
2352 else if (capture_opts.snaplen < MIN_PACKET_SIZE)
2353 capture_opts.snaplen = MIN_PACKET_SIZE;
2356 /* Check the value range of the ringbuffer_num_files parameter */
2357 if (capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2358 capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2359 #if RINGBUFFER_MIN_NUM_FILES > 0
2360 else if (capture_opts.num_files < RINGBUFFER_MIN_NUM_FILES)
2361 capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2365 /* read in rc file from global and personal configuration paths. */
2366 /* XXX - is this a good idea? */
2367 gtk_rc_parse(RC_FILE);
2368 rc_file = get_persconffile_path(RC_FILE, FALSE);
2369 gtk_rc_parse(rc_file);
2373 /* close the splash screen, as we are going to open the main window now */
2374 splash_destroy(splash_win);
2377 /* Is this a "child" ethereal, which is only supposed to pop up a
2378 capture box to let us stop the capture, and run a capture
2379 to a file that our parent will read? */
2380 if (!capture_child) {
2382 /* No. Pop up the main window, and read in a capture file if
2384 create_main_window(pl_size, tv_size, bv_size, prefs);
2386 /* Read the recent file, as we have the gui now ready for it. */
2387 read_recent(&rf_path, &rf_open_errno);
2389 /* rearrange all the widgets as we now have the recent settings for this */
2390 main_widgets_rearrange();
2392 /* Fill in column titles. This must be done after the top level window
2395 XXX - is that still true, with fixed-width columns? */
2396 packet_list_set_column_titles();
2398 menu_recent_read_finished();
2400 switch (user_font_apply()) {
2403 case FA_FONT_NOT_RESIZEABLE:
2404 /* "user_font_apply()" popped up an alert box. */
2405 /* turn off zooming - font can't be resized */
2406 case FA_FONT_NOT_AVAILABLE:
2407 /* XXX - did we successfully load the un-zoomed version earlier?
2408 If so, this *probably* means the font is available, but not at
2409 this particular zoom level, but perhaps some other failure
2410 occurred; I'm not sure you can determine which is the case,
2412 /* turn off zooming - zoom level is unavailable */
2414 /* in any other case than FA_SUCCESS, turn off zooming */
2415 recent.gui_zoom_level = 0;
2416 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2419 dnd_init(top_level);
2424 /* the window can be sized only, if it's not already shown, so do it now! */
2425 main_load_window_geometry(top_level);
2427 /*** we have finished all init things, show the main window ***/
2428 gtk_widget_show(top_level);
2430 /* the window can be maximized only, if it's visible, so do it after show! */
2431 main_load_window_geometry(top_level);
2433 /* process all pending GUI events before continue */
2434 while (gtk_events_pending()) gtk_main_iteration();
2436 /* Pop up any queued-up alert boxes. */
2437 display_queued_messages();
2439 /* If we were given the name of a capture file, read it in now;
2440 we defer it until now, so that, if we can't open it, and pop
2441 up an alert box, the alert box is more likely to come up on
2442 top of the main window - but before the preference-file-error
2443 alert box, so, if we get one of those, it's more likely to come
2446 if (rfilter != NULL) {
2447 if (!dfilter_compile(rfilter, &rfcode)) {
2448 bad_dfilter_alert_box(rfilter);
2449 rfilter_parse_failed = TRUE;
2452 if (!rfilter_parse_failed) {
2453 if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
2454 /* "cf_open()" succeeded, so it closed the previous
2455 capture file, and thus destroyed any previous read filter
2456 attached to "cf". */
2457 cfile.rfcode = rfcode;
2459 /* Open tap windows; we do so after creating the main window,
2460 to avoid GTK warnings, and after successfully opening the
2461 capture file, so we know we have something to tap. */
2462 if (tap_opt && tli) {
2463 (*tli->func)(tap_opt);
2467 /* Read the capture file. */
2468 switch (cf_read(&cfile)) {
2472 /* Just because we got an error, that doesn't mean we were unable
2473 to read any of the file; we handle what we could get from the
2482 /* Save the name of the containing directory specified in the
2483 path name, if any; we can write over cf_name, which is a
2484 good thing, given that "get_dirname()" does write over its
2486 s = get_dirname(cf_name);
2487 /* we might already set this from the recent file, don't overwrite this */
2488 if(get_last_open_dir() == NULL)
2489 set_last_open_dir(s);
2494 dfilter_free(rfcode);
2495 cfile.rfcode = NULL;
2500 if (start_capture) {
2501 /* "-k" was specified; start a capture. */
2502 if (do_capture(save_file)) {
2503 /* The capture started. Open tap windows; we do so after creating
2504 the main window, to avoid GTK warnings, and after starting the
2505 capture, so we know we have something to tap. */
2506 if (tap_opt && tli) {
2507 (*tli->func)(tap_opt);
2511 if (save_file != NULL) {
2512 /* Save the directory name for future file dialogs. */
2513 s = get_dirname(save_file); /* Overwrites save_file */
2514 set_last_open_dir(s);
2520 set_menus_for_capture_in_progress(FALSE);
2523 /* This is the child process for a sync mode or fork mode capture,
2524 so just do the low-level work of a capture - don't create
2525 a temporary file and fork off *another* child process (so don't
2526 call "do_capture()"). */
2528 /* Pop up any queued-up alert boxes. */
2529 display_queued_messages();
2531 /* XXX - hand these stats to the parent process */
2532 capture(&stats_known, &stats);
2534 /* The capture is done; there's nothing more for us to do. */
2537 if (!start_capture && (cfile.cfilter == NULL || strlen(cfile.cfilter) == 0)) {
2538 if (cfile.cfilter) {
2539 g_free(cfile.cfilter);
2541 cfile.cfilter = g_strdup(get_conn_cfilter());
2543 #else /* HAVE_LIBPCAP */
2544 set_menus_for_capture_in_progress(FALSE);
2545 #endif /* HAVE_LIBPCAP */
2553 /* Shutdown windows sockets */
2556 /* For some unknown reason, the "atexit()" call in "create_console()"
2557 doesn't arrange that "destroy_console()" be called when we exit,
2558 so we call it here if a console was created. */
2564 /* This isn't reached, but we need it to keep GCC from complaining
2565 that "main()" returns without returning a value - it knows that
2566 "exit()" never returns, but it doesn't know that "gtk_exit()"
2567 doesn't, as GTK+ doesn't declare it with the attribute
2569 return 0; /* not reached */
2574 /* We build this as a GUI subsystem application on Win32, so
2575 "WinMain()", not "main()", gets called.
2577 Hack shamelessly stolen from the Win32 port of the GIMP. */
2579 #define _stdcall __attribute__((stdcall))
2583 WinMain (struct HINSTANCE__ *hInstance,
2584 struct HINSTANCE__ *hPrevInstance,
2588 has_console = FALSE;
2589 return main (__argc, __argv);
2593 * If this application has no console window to which its standard output
2594 * would go, create one.
2597 create_console(void)
2599 if (!has_console && prefs.gui_console_open != console_open_never) {
2600 /* We have no console to which to print the version string, so
2601 create one and make it the standard input, output, and error. */
2602 if (!AllocConsole())
2603 return; /* couldn't create console */
2604 freopen("CONIN$", "r", stdin);
2605 freopen("CONOUT$", "w", stdout);
2606 freopen("CONOUT$", "w", stderr);
2608 /* Well, we have a console now. */
2611 /* Now register "destroy_console()" as a routine to be called just
2612 before the application exits, so that we can destroy the console
2613 after the user has typed a key (so that the console doesn't just
2614 disappear out from under them, giving the user no chance to see
2615 the message(s) we put in there). */
2616 atexit(destroy_console);
2621 destroy_console(void)
2624 printf("\n\nPress any key to exit\n");
2630 /* This routine should not be necessary, at least as I read the GLib
2631 source code, as it looks as if GLib is, on Win32, *supposed* to
2632 create a console window into which to display its output.
2634 That doesn't happen, however. I suspect there's something completely
2635 broken about that code in GLib-for-Win32, and that it may be related
2636 to the breakage that forces us to just call "printf()" on the message
2637 rather than passing the message on to "g_log_default_handler()"
2638 (which is the routine that does the aforementioned non-functional
2639 console window creation). */
2641 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2642 const char *message, gpointer user_data)
2646 /* For some unknown reason, the above doesn't appear to actually cause
2647 anything to be sent to the standard output, so we'll just splat the
2648 message out directly, just to make sure it gets out. */
2649 printf("%s\n", message);
2651 g_log_default_handler(log_domain, log_level, message, user_data);
2656 GtkWidget *info_bar_new(void)
2658 /* tip: tooltips don't work on statusbars! */
2659 info_bar = gtk_statusbar_new();
2660 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2661 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2662 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2663 #if GTK_MAJOR_VERSION >= 2
2664 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2666 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2671 GtkWidget *packets_bar_new(void)
2673 /* tip: tooltips don't work on statusbars! */
2674 packets_bar = gtk_statusbar_new();
2675 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2676 packets_bar_update();
2683 * Helper for main_widgets_rearrange()
2685 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2686 gtk_container_remove(GTK_CONTAINER(data), widget);
2689 GtkWidget *main_widget_layout(gint layout_content)
2691 switch(layout_content) {
2692 case(layout_pane_content_none):
2695 case(layout_pane_content_plist):
2698 case(layout_pane_content_pdetails):
2701 case(layout_pane_content_pbytes):
2705 g_assert_not_reached();
2712 * Rearrange the main window widgets
2714 void main_widgets_rearrange(void) {
2715 GtkWidget *pane_content[3];
2717 /* be a bit faster */
2718 gtk_widget_hide(main_vbox);
2720 /* be sure, we don't loose a widget while rearranging */
2721 gtk_widget_ref(menubar);
2722 gtk_widget_ref(main_tb);
2723 gtk_widget_ref(filter_tb);
2724 gtk_widget_ref(pkt_scrollw);
2725 gtk_widget_ref(tv_scrollw);
2726 gtk_widget_ref(byte_nb_ptr);
2727 gtk_widget_ref(stat_hbox);
2728 gtk_widget_ref(info_bar);
2729 gtk_widget_ref(packets_bar);
2730 gtk_widget_ref(status_pane);
2731 gtk_widget_ref(none_lb);
2732 gtk_widget_ref(main_pane_v1);
2733 gtk_widget_ref(main_pane_v2);
2734 gtk_widget_ref(main_pane_h1);
2735 gtk_widget_ref(main_pane_h2);
2737 /* empty all containers participating */
2738 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2739 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2740 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2741 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2742 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2743 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2744 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2746 /* add the menubar always at the top */
2747 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2750 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2752 /* filter toolbar in toolbar area */
2753 if (!prefs.filter_toolbar_show_in_statusbar) {
2754 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2757 /* get the corresponding widgets to the content setting */
2758 pane_content[0] = main_widget_layout(prefs.gui_layout_content_1);
2759 pane_content[1] = main_widget_layout(prefs.gui_layout_content_2);
2760 pane_content[2] = main_widget_layout(prefs.gui_layout_content_3);
2762 /* fill the main layout panes */
2763 switch(prefs.gui_layout_type) {
2764 case(layout_type_5):
2765 main_first_pane = main_pane_v1;
2766 main_second_pane = main_pane_v2;
2767 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2768 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2769 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2770 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2772 case(layout_type_2):
2773 main_first_pane = main_pane_v1;
2774 main_second_pane = main_pane_h1;
2775 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2776 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2777 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2778 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2780 case(layout_type_1):
2781 main_first_pane = main_pane_v1;
2782 main_second_pane = main_pane_h1;
2783 gtk_paned_add1(GTK_PANED(main_first_pane), main_second_pane);
2784 gtk_paned_add2(GTK_PANED(main_first_pane), pane_content[2]);
2785 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[0], TRUE, TRUE);
2786 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[1], FALSE, FALSE);
2788 case(layout_type_4):
2789 main_first_pane = main_pane_h1;
2790 main_second_pane = main_pane_v1;
2791 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2792 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2793 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2794 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2796 case(layout_type_3):
2797 main_first_pane = main_pane_h1;
2798 main_second_pane = main_pane_v1;
2799 gtk_paned_add1(GTK_PANED(main_first_pane), main_second_pane);
2800 gtk_paned_add2(GTK_PANED(main_first_pane), pane_content[2]);
2801 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[0], TRUE, TRUE);
2802 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[1], FALSE, FALSE);
2804 case(layout_type_6):
2805 main_first_pane = main_pane_h1;
2806 main_second_pane = main_pane_h2;
2807 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2808 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2809 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2810 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2813 g_assert_not_reached();
2816 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2818 /* statusbar hbox */
2819 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2821 /* filter toolbar in statusbar hbox */
2822 if (prefs.filter_toolbar_show_in_statusbar) {
2823 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2827 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2828 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2829 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2831 /* hide widgets on users recent settings */
2832 main_widgets_show_or_hide();
2834 gtk_widget_show(main_vbox);
2838 is_widget_visible(GtkWidget *widget, gpointer data)
2840 gboolean *is_visible = data;
2843 if (GTK_WIDGET_VISIBLE(widget))
2849 * XXX - this doesn't appear to work with the paned widgets in
2850 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
2851 * and the other pane doesn't grow to take up the rest of the pane.
2852 * It does appear to work with GTK+ 2.x.
2855 main_widgets_show_or_hide(void)
2857 gboolean main_second_pane_show;
2859 if (recent.main_toolbar_show) {
2860 gtk_widget_show(main_tb);
2862 gtk_widget_hide(main_tb);
2866 * Show the status hbox if either:
2868 * 1) we're showing the filter toolbar and we want it in the status
2873 * 2) we're showing the status bar.
2875 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
2876 recent.statusbar_show) {
2877 gtk_widget_show(stat_hbox);
2879 gtk_widget_hide(stat_hbox);
2882 if (recent.statusbar_show) {
2883 gtk_widget_show(status_pane);
2885 gtk_widget_hide(status_pane);
2888 if (recent.filter_toolbar_show) {
2889 gtk_widget_show(filter_tb);
2891 gtk_widget_hide(filter_tb);
2894 if (recent.packet_list_show) {
2895 gtk_widget_show(pkt_scrollw);
2897 gtk_widget_hide(pkt_scrollw);
2900 if (recent.tree_view_show) {
2901 gtk_widget_show(tv_scrollw);
2903 gtk_widget_hide(tv_scrollw);
2906 if (recent.byte_view_show) {
2907 gtk_widget_show(byte_nb_ptr);
2909 gtk_widget_hide(byte_nb_ptr);
2913 * Is anything in "main_second_pane" visible?
2914 * If so, show it, otherwise hide it.
2916 main_second_pane_show = FALSE;
2917 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
2918 &main_second_pane_show);
2919 if (main_second_pane_show) {
2920 gtk_widget_show(main_second_pane);
2922 gtk_widget_hide(main_second_pane);
2927 #if GTK_MAJOR_VERSION >= 2
2928 /* called, when the window state changes (minimized, maximized, ...) */
2930 window_state_event_cb (GtkWidget *widget _U_,
2934 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
2936 if( (event->type) == (GDK_WINDOW_STATE)) {
2937 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
2938 /* we might have dialogs popped up while we where iconified,
2940 display_queued_messages();
2949 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2952 *filter_bt, *filter_cm, *filter_te,
2953 *filter_add_expr_bt,
2956 GList *filter_list = NULL;
2957 GtkTooltips *tooltips;
2958 GtkAccelGroup *accel;
2959 /* Display filter construct dialog has an Apply button, and "OK" not
2960 only sets our text widget, it activates it (i.e., it causes us to
2961 filter the capture). */
2962 static construct_args_t args = {
2963 "Ethereal: Display Filter",
2969 top_level = window_new(GTK_WINDOW_TOPLEVEL, "The Ethereal Network Analyzer");
2971 tooltips = gtk_tooltips_new();
2974 #if GTK_MAJOR_VERSION < 2
2975 /* has to be done, after top_level window is created */
2976 app_font_gtk1_init(top_level);
2980 gtk_widget_set_name(top_level, "main window");
2981 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
2983 #if GTK_MAJOR_VERSION >= 2
2984 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
2985 G_CALLBACK (window_state_event_cb), NULL);
2988 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2990 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
2991 main_vbox = gtk_vbox_new(FALSE, 1);
2992 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2993 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2994 gtk_widget_show(main_vbox);
2997 menubar = main_menu_new(&accel);
2998 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2999 gtk_widget_show(menubar);
3002 main_tb = toolbar_new();
3003 gtk_widget_show (main_tb);
3006 pkt_scrollw = packet_list_new(prefs);
3007 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3008 gtk_widget_show(pkt_scrollw);
3011 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3012 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3013 gtk_widget_show(tv_scrollw);
3015 #if GTK_MAJOR_VERSION < 2
3016 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3017 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3020 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3021 "changed", tree_view_selection_changed_cb, NULL);
3023 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3024 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3025 gtk_widget_show(tree_view);
3028 byte_nb_ptr = byte_view_new();
3029 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3030 gtk_widget_show(byte_nb_ptr);
3032 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3033 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3036 /* Panes for the packet list, tree, and byte view */
3037 none_lb = gtk_label_new("None");
3039 main_pane_v1 = gtk_vpaned_new();
3040 gtk_widget_show(main_pane_v1);
3041 main_pane_v2 = gtk_vpaned_new();
3042 gtk_widget_show(main_pane_v2);
3043 main_pane_h1 = gtk_hpaned_new();
3044 gtk_widget_show(main_pane_h1);
3045 main_pane_h2 = gtk_hpaned_new();
3046 gtk_widget_show(main_pane_h2);
3048 /* filter toolbar */
3049 #if GTK_MAJOR_VERSION < 2
3050 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3053 filter_tb = gtk_toolbar_new();
3054 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3055 GTK_ORIENTATION_HORIZONTAL);
3056 #endif /* GTK_MAJOR_VERSION */
3057 gtk_widget_show(filter_tb);
3059 /* Create the "Filter:" button */
3060 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3061 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3062 gtk_widget_show(filter_bt);
3063 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3065 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3066 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3068 /* Create the filter combobox */
3069 filter_cm = gtk_combo_new();
3071 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3072 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3073 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
3074 filter_te = GTK_COMBO(filter_cm)->entry;
3075 main_display_filter_widget=filter_te;
3076 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3077 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3078 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3079 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3080 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3081 WIDGET_SET_SIZE(filter_cm, 400, -1);
3082 gtk_widget_show(filter_cm);
3083 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3085 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3086 gtk_tooltips_set_tip(tooltips, filter_te,
3087 "Enter a display filter, or choose one of your recently used filters. "
3088 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3091 /* Create the "Add Expression..." button, to pop up a dialog
3092 for constructing filter comparison expressions. */
3093 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3094 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3095 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3096 gtk_widget_show(filter_add_expr_bt);
3097 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3098 "Add an expression to this filter string", "Private");
3100 /* Create the "Clear" button */
3101 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3102 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3103 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3104 gtk_widget_show(filter_reset);
3105 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3106 "Clear this filter string and update the display", "Private");
3108 /* Create the "Apply" button */
3109 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3110 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3111 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3112 gtk_widget_show(filter_apply);
3113 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3114 "Apply this filter string to the display", "Private");
3116 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3117 * of any widget that ends up calling a callback which needs
3118 * that text entry pointer */
3119 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3120 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3122 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3124 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3126 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3128 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3130 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3132 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3134 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3136 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3138 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3140 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3142 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3144 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3146 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3148 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3149 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3150 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3152 /* info (main) statusbar */
3153 info_bar = info_bar_new();
3154 gtk_widget_show(info_bar);
3156 /* packets statusbar */
3157 packets_bar = packets_bar_new();
3158 gtk_widget_show(packets_bar);
3160 /* Filter/status hbox */
3161 stat_hbox = gtk_hbox_new(FALSE, 1);
3162 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3163 gtk_widget_show(stat_hbox);
3165 /* Pane for the statusbar */
3166 status_pane = gtk_hpaned_new();
3167 gtk_widget_show(status_pane);