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.
47 #include <io.h> /* open/close on win32 */
50 #ifdef NEED_STRERROR_H
58 #ifdef _WIN32 /* Needed for console I/O */
63 #include <epan/epan.h>
64 #include <epan/filesystem.h>
65 #include <epan/epan_dissect.h>
66 #include <epan/timestamp.h>
67 #include <epan/packet.h>
68 #include <epan/plugins.h>
69 #include <epan/dfilter/dfilter.h>
70 #include <epan/strutil.h>
71 #include <epan/addr_resolv.h>
73 /* general (not GTK specific) */
74 #include "svnversion.h"
78 #include "disabled_protos.h"
79 #include <epan/prefs.h>
80 #include "filter_dlg.h"
81 #include "layout_prefs.h"
83 #include "color_filters.h"
85 #include "simple_dialog.h"
87 #include <epan/prefs-int.h>
88 #include "ringbuffer.h"
89 #include "../ui_util.h" /* beware: ui_util.h exists twice! */
92 #include "clopts_common.h"
93 #include "version_info.h"
97 #include "pcap-util.h"
100 #include "capture-wpcap.h"
102 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
103 #include "ethclist.h"
107 #include "statusbar.h"
108 #include "alert_box.h"
109 #include "dlg_utils.h"
110 #include "gtkglobals.h"
112 #include "ui_util.h" /* beware: ui_util.h exists twice! */
113 #include "compat_macros.h"
117 #include "../main_window.h"
119 #include "file_dlg.h"
120 #include <epan/column.h>
121 #include "proto_draw.h"
123 #include "packet_win.h"
125 #include "find_dlg.h"
126 #include "packet_list.h"
128 #include "follow_dlg.h"
129 #include "font_utils.h"
130 #include "about_dlg.h"
131 #include "help_dlg.h"
132 #include "decode_as_dlg.h"
133 #include "webbrowser.h"
134 #include "capture_dlg.h"
135 #include "../image/eicon3d64.xpm"
136 #include "capture_ui_utils.h"
141 * File under personal preferences directory in which GTK settings for
142 * Ethereal are stored.
144 #define RC_FILE "gtkrc"
147 #define DEF_READY_MESSAGE " Ready to load or capture"
149 #define DEF_READY_MESSAGE " Ready to load file"
153 GtkWidget *main_display_filter_widget=NULL;
154 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
155 static GtkWidget *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
156 static GtkWidget *main_first_pane, *main_second_pane;
157 static GtkWidget *status_pane;
158 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
159 static GtkWidget *info_bar;
160 static GtkWidget *packets_bar = NULL;
161 static GtkWidget *welcome_pane;
162 static guint main_ctx, file_ctx, help_ctx;
163 static guint packets_ctx;
164 static gchar *packets_str = NULL;
165 GString *comp_info_str, *runtime_info_str;
166 gchar *ethereal_path = NULL;
167 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
170 static gboolean has_console; /* TRUE if app has console */
171 /*static void create_console(void);*/
172 static void destroy_console(void);
173 static void console_log_handler(const char *log_domain,
174 GLogLevelFlags log_level, const char *message, gpointer user_data);
178 static gboolean list_link_layer_types;
179 capture_options global_capture_opts;
180 capture_options *capture_opts = &global_capture_opts;
184 static void create_main_window(gint, gint, gint, e_prefs*);
185 static void show_main_window(gboolean);
186 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
187 static void main_save_window_geometry(GtkWidget *widget);
189 #define E_DFILTER_CM_KEY "display_filter_combo"
190 #define E_DFILTER_FL_KEY "display_filter_list"
194 /* Match selected byte pattern */
196 match_selected_cb_do(gpointer data, int action, gchar *text)
198 GtkWidget *filter_te;
199 char *cur_filter, *new_filter;
204 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
207 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
209 switch (action&MATCH_SELECTED_MASK) {
211 case MATCH_SELECTED_REPLACE:
212 new_filter = g_strdup(text);
215 case MATCH_SELECTED_AND:
216 if ((!cur_filter) || (0 == strlen(cur_filter)))
217 new_filter = g_strdup(text);
219 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
222 case MATCH_SELECTED_OR:
223 if ((!cur_filter) || (0 == strlen(cur_filter)))
224 new_filter = g_strdup(text);
226 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
229 case MATCH_SELECTED_NOT:
230 new_filter = g_strconcat("!(", text, ")", NULL);
233 case MATCH_SELECTED_AND_NOT:
234 if ((!cur_filter) || (0 == strlen(cur_filter)))
235 new_filter = g_strconcat("!(", text, ")", NULL);
237 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
240 case MATCH_SELECTED_OR_NOT:
241 if ((!cur_filter) || (0 == strlen(cur_filter)))
242 new_filter = g_strconcat("!(", text, ")", NULL);
244 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
248 g_assert_not_reached();
253 /* Free up the copy we got of the old filter text. */
256 /* create a new one and set the display filter entry accordingly */
257 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
259 /* Run the display filter so it goes in effect. */
260 if (action&MATCH_SELECTED_APPLY_NOW)
261 main_filter_packets(&cfile, new_filter, FALSE);
263 /* Free up the new filter text. */
266 /* Free up the generated text we were handed. */
271 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
273 if (cfile.finfo_selected)
274 match_selected_cb_do((data ? data : w),
276 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
280 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
282 gchar *selected_proto_url;
283 gchar *proto_abbrev = data;
288 if (cfile.finfo_selected) {
289 /* open wiki page using the protocol abbreviation */
290 selected_proto_url = g_strdup_printf("http://wiki.ethereal.com/Protocols/%s", proto_abbrev);
291 browser_open_url(selected_proto_url);
292 g_free(selected_proto_url);
295 case(ESD_BTN_CANCEL):
298 g_assert_not_reached();
304 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
311 if (cfile.finfo_selected) {
312 /* convert selected field to protocol abbreviation */
313 /* XXX - could this conversion be simplified? */
314 field_id = cfile.finfo_selected->hfinfo->id;
315 /* if the selected field isn't a protocol, get it's parent */
316 if(!proto_registrar_is_protocol(field_id)) {
317 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
320 proto_abbrev = proto_registrar_get_abbrev(field_id);
322 /* ask the user if the wiki page really should be opened */
323 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
324 PRIMARY_TEXT_START "Open Ethereal Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
326 "This will open the \"%s\" related Ethereal Wiki page in your Web browser.\n"
328 "The Ethereal Wiki is a collaborative approach to provide information\n"
329 "about Ethereal in several ways (not limited to protocol specifics).\n"
331 "This Wiki is new, so the page of the selected protocol\n"
332 "may not exist and/or may not contain valuable information.\n"
334 "As everyone can edit the Wiki and add new content (or extend existing),\n"
335 "you are encouraged to add information if you can.\n"
337 "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
339 "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
340 "which will save you a lot of editing and will give a consistent look over the pages.",
341 proto_abbrev, proto_abbrev);
342 simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, proto_abbrev);
348 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
352 gchar *selected_proto_url;
355 if (cfile.finfo_selected) {
356 /* convert selected field to protocol abbreviation */
357 /* XXX - could this conversion be simplified? */
358 field_id = cfile.finfo_selected->hfinfo->id;
359 /* if the selected field isn't a protocol, get it's parent */
360 if(!proto_registrar_is_protocol(field_id)) {
361 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
364 proto_abbrev = proto_registrar_get_abbrev(field_id);
366 /* open reference page using the protocol abbreviation */
367 selected_proto_url = g_strdup_printf("http://www.ethereal.com/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
368 browser_open_url(selected_proto_url);
369 g_free(selected_proto_url);
375 get_text_from_packet_list(gpointer data)
377 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
378 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
379 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
387 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
388 cfile.pd, fdata->cap_len, &err, &err_info)) {
389 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
390 cf_read_error_message(err, err_info), cfile.filename);
394 edt = epan_dissect_new(FALSE, FALSE);
395 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
397 epan_dissect_fill_in_columns(edt);
399 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
400 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
401 len = strlen(cfile.cinfo.col_expr[column]) +
402 strlen(cfile.cinfo.col_expr_val[column]) + 5;
403 buf = g_malloc0(len);
404 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
405 cfile.cinfo.col_expr_val[column]);
408 epan_dissect_free(edt);
415 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
417 match_selected_cb_do(data,
419 get_text_from_packet_list(data));
424 /* XXX: use a preference for this setting! */
425 static guint dfilter_combo_max_recent = 10;
427 /* add a display filter to the combo box */
428 /* Note: a new filter string will replace an old identical one */
430 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
432 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
435 /* GtkCombos don't let us get at their list contents easily, so we maintain
436 our own filter list, and feed it to gtk_combo_set_popdown_strings when
437 a new filter is added. */
438 li = g_list_first(filter_list);
440 /* If the filter is already in the list, remove the old one and
441 * append the new one at the latest position (at g_list_append() below) */
442 if (li->data && strcmp(s, li->data) == 0) {
443 filter_list = g_list_remove(filter_list, li->data);
449 filter_list = g_list_append(filter_list, s);
450 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
451 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
452 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data);
458 /* write all non empty display filters (until maximum count)
459 * of the combo box GList to the user's recent file */
461 dfilter_recent_combo_write_all(FILE *rf) {
462 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
463 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
468 /* write all non empty display filter strings to the recent file (until max count) */
469 li = g_list_first(filter_list);
470 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
471 if (strlen(li->data)) {
472 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
478 /* empty the combobox entry field */
480 dfilter_combo_add_empty(void) {
481 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
483 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
487 /* add a display filter coming from the user's recent file to the dfilter combo box */
489 dfilter_combo_add_recent(gchar *s) {
490 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
494 if (!dfilter_combo_add(filter_cm, dup)) {
503 /* call cf_filter_packets() and add this filter string to the recent filter list */
505 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
507 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
508 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
510 gboolean add_filter = TRUE;
511 gboolean free_filter = TRUE;
513 cf_status_t cf_status;
515 s = g_strdup(dftext);
517 /* GtkCombos don't let us get at their list contents easily, so we maintain
518 our own filter list, and feed it to gtk_combo_set_popdown_strings when
519 a new filter is added. */
520 cf_status = cf_filter_packets(cf, s, force);
521 if (cf_status == CF_OK) {
522 li = g_list_first(filter_list);
524 if (li->data && strcmp(s, li->data) == 0)
530 /* trim list size first */
531 while (g_list_length(filter_list) >= dfilter_combo_max_recent) {
532 filter_list = g_list_remove(filter_list, g_list_first(filter_list)->data);
536 filter_list = g_list_append(filter_list, s);
537 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
538 gtk_combo_set_popdown_strings(filter_cm, filter_list);
539 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
545 return (cf_status == CF_OK);
549 /* Run the current display filter on the current packet set, and
552 filter_activate_cb(GtkWidget *w _U_, gpointer data)
556 s = gtk_entry_get_text(GTK_ENTRY(data));
558 main_filter_packets(&cfile, s, FALSE);
561 /* redisplay with no display filter */
563 filter_reset_cb(GtkWidget *w, gpointer data _U_)
565 GtkWidget *filter_te = NULL;
567 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
568 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
570 main_filter_packets(&cfile, "", FALSE);
573 /* mark as reference time frame */
575 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
579 frame->flags.ref_time=1;
581 frame->flags.ref_time=0;
583 cf_reftime_packets(&cfile);
587 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
592 if (cfile.current_frame) {
593 /* XXX hum, should better have a "cfile->current_row" here ... */
594 set_frame_reftime(!cfile.current_frame->flags.ref_time,
596 packet_list_find_row_from_data(cfile.current_frame));
599 case REFTIME_FIND_NEXT:
600 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
602 case REFTIME_FIND_PREV:
603 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
608 #if GTK_MAJOR_VERSION < 2
610 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
611 gpointer user_data _U_)
614 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
618 gchar *help_str = NULL;
619 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
621 gboolean has_blurb = FALSE;
622 guint length = 0, byte_len;
623 GtkWidget *byte_view;
624 const guint8 *byte_data;
625 #if GTK_MAJOR_VERSION >= 2
630 #if GTK_MAJOR_VERSION >= 2
631 /* if nothing is selected */
632 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
635 * Which byte view is displaying the current protocol tree
638 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
639 if (byte_view == NULL)
642 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
643 if (byte_data == NULL)
646 cf_unselect_field(&cfile);
647 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
648 cfile.current_frame, NULL, byte_len);
651 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
654 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
658 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
660 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
661 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
662 g_assert(byte_data != NULL);
664 cfile.finfo_selected = finfo;
665 set_menus_for_selected_tree_row(&cfile);
668 if (finfo->hfinfo->blurb != NULL &&
669 finfo->hfinfo->blurb[0] != '\0') {
671 length = strlen(finfo->hfinfo->blurb);
673 length = strlen(finfo->hfinfo->name);
675 if (finfo->length == 0) {
677 } else if (finfo->length == 1) {
678 strcpy (len_str, ", 1 byte");
680 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
682 statusbar_pop_field_msg(); /* get rid of current help msg */
684 help_str = g_strdup_printf("%s (%s)%s",
685 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
686 finfo->hfinfo->abbrev, len_str);
687 statusbar_push_field_msg(help_str);
691 * Don't show anything if the field name is zero-length;
692 * the pseudo-field for "proto_tree_add_text()" is such
693 * a field, and we don't want "Text (text)" showing up
694 * on the status line if you've selected such a field.
696 * XXX - there are zero-length fields for which we *do*
697 * want to show the field name.
699 * XXX - perhaps the name and abbrev field should be null
700 * pointers rather than null strings for that pseudo-field,
701 * but we'd have to add checks for null pointers in some
702 * places if we did that.
704 * Or perhaps protocol tree items added with
705 * "proto_tree_add_text()" should have -1 as the field index,
706 * with no pseudo-field being used, but that might also
707 * require special checks for -1 to be added.
709 statusbar_push_field_msg("");
713 #if GTK_MAJOR_VERSION < 2
714 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
717 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
722 #if GTK_MAJOR_VERSION < 2
724 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
725 gpointer user_data _U_)
727 GtkWidget *byte_view;
732 * Which byte view is displaying the current protocol tree
735 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
736 if (byte_view == NULL)
739 data = get_byte_view_data_and_length(byte_view, &len);
743 cf_unselect_field(&cfile);
744 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
749 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
751 collapse_all_tree(cfile.edt->tree, tree_view);
754 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
756 expand_all_tree(cfile.edt->tree, tree_view);
759 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
760 #if GTK_MAJOR_VERSION < 2
766 #if GTK_MAJOR_VERSION < 2
767 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
769 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
771 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
773 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
774 gtk_tree_path_free(path);
778 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
779 if (cfile.edt->tree) {
780 guint32 tmp = g_resolv_flags;
781 g_resolv_flags = RESOLV_ALL;
782 proto_tree_draw(cfile.edt->tree, tree_view);
783 g_resolv_flags = tmp;
788 * Push a message referring to file access onto the statusbar.
791 statusbar_push_file_msg(gchar *msg)
793 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
797 * Pop a message referring to file access off the statusbar.
800 statusbar_pop_file_msg(void)
802 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
806 * XXX - do we need multiple statusbar contexts?
810 * Push a message referring to the currently-selected field onto the statusbar.
813 statusbar_push_field_msg(gchar *msg)
815 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
819 * Pop a message referring to the currently-selected field off the statusbar.
822 statusbar_pop_field_msg(void)
824 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
828 * update the packets statusbar to the current values
830 void packets_bar_update(void)
834 /* remove old status */
837 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
840 /* do we have any packets? */
842 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
843 cfile.count, cfile.displayed_count, cfile.marked_count);
845 packets_str = g_strdup(" No Packets");
847 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
852 main_set_for_capture_file(gboolean have_capture_file_in)
854 have_capture_file = have_capture_file_in;
856 main_widgets_show_or_hide();
865 /* get the current geometry, before writing it to disk */
866 main_save_window_geometry(top_level);
868 /* write user's recent file to disk
869 * It is no problem to write this file, even if we do not quit */
870 write_recent(&rec_path);
872 /* XXX - should we check whether the capture file is an
873 unsaved temporary file for a live capture and, if so,
874 pop up a "do you want to exit without saving the capture
875 file?" dialog, and then just return, leaving said dialog
876 box to forcibly quit if the user clicks "OK"?
878 If so, note that this should be done in a subroutine that
879 returns TRUE if we do so, and FALSE otherwise, and if it
880 returns TRUE we should return TRUE without nuking anything.
882 Note that, if we do that, we might also want to check if
883 an "Update list of packets in real time" capture is in
884 progress and, if so, ask whether they want to terminate
885 the capture and discard it, and return TRUE, before nuking
886 any child capture, if they say they don't want to do so. */
889 /* Nuke any child capture in progress. */
890 capture_kill_child(capture_opts);
893 /* Are we in the middle of reading a capture? */
894 if (cfile.state == FILE_READ_IN_PROGRESS) {
895 /* Yes, so we can't just close the file and quit, as
896 that may yank the rug out from under the read in
897 progress; instead, just set the state to
898 "FILE_READ_ABORTED" and return - the code doing the read
899 will check for that and, if it sees that, will clean
901 cfile.state = FILE_READ_ABORTED;
903 /* Say that the window should *not* be deleted;
904 that'll be done by the code that cleans up. */
907 /* Close any capture file we have open; on some OSes, you
908 can't unlink a temporary capture file if you have it
910 "cf_close()" will unlink it after closing it if
911 it's a temporary file.
913 We do this here, rather than after the main loop returns,
914 as, after the main loop returns, the main window may have
915 been destroyed (if this is called due to a "destroy"
916 even on the main window rather than due to the user
917 selecting a menu item), and there may be a crash
918 or other problem when "cf_close()" tries to
919 clean up stuff in the main window.
921 XXX - is there a better place to put this?
922 Or should we have a routine that *just* closes the
923 capture file, and doesn't do anything with the UI,
924 which we'd call here, and another routine that
925 calls that routine and also cleans up the UI, which
926 we'd call elsewhere? */
929 /* Exit by leaving the main loop, so that any quit functions
930 we registered get called. */
933 /* Say that the window should be deleted. */
939 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
943 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
944 #if GTK_MAJOR_VERSION >= 2
945 gtk_window_present(GTK_WINDOW(top_level));
947 /* user didn't saved his current file, ask him */
948 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
949 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
950 "If you quit the program without saving, your capture data will be discarded.");
951 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
954 /* unchanged file, just exit */
955 /* "main_do_quit()" indicates whether the main window should be deleted. */
956 return main_do_quit();
963 main_load_window_geometry(GtkWidget *widget)
965 window_geometry_t geom;
967 geom.set_pos = prefs.gui_geometry_save_position;
968 geom.x = recent.gui_geometry_main_x;
969 geom.y = recent.gui_geometry_main_y;
970 geom.set_size = prefs.gui_geometry_save_size;
971 if (recent.gui_geometry_main_width > 0 &&
972 recent.gui_geometry_main_height > 0) {
973 geom.width = recent.gui_geometry_main_width;
974 geom.height = recent.gui_geometry_main_height;
975 geom.set_maximized = prefs.gui_geometry_save_maximized;
977 /* We assume this means the width and height weren't set in
978 the "recent" file (or that there is no "recent" file),
979 and weren't set to a default value, so we don't set the
980 size. (The "recent" file code rejects non-positive width
981 and height values.) */
982 geom.set_size = FALSE;
984 geom.maximized = recent.gui_geometry_main_maximized;
986 window_set_geometry(widget, &geom);
988 #if GTK_MAJOR_VERSION >= 2
989 /* XXX - rename recent settings? */
990 if (recent.gui_geometry_main_upper_pane)
991 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
992 if (recent.gui_geometry_main_lower_pane)
993 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
994 if (recent.gui_geometry_status_pane)
995 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
1001 main_save_window_geometry(GtkWidget *widget)
1003 window_geometry_t geom;
1005 window_get_geometry(widget, &geom);
1007 if (prefs.gui_geometry_save_position) {
1008 recent.gui_geometry_main_x = geom.x;
1009 recent.gui_geometry_main_y = geom.y;
1012 if (prefs.gui_geometry_save_size) {
1013 recent.gui_geometry_main_width = geom.width,
1014 recent.gui_geometry_main_height = geom.height;
1017 #if GTK_MAJOR_VERSION >= 2
1018 if(prefs.gui_geometry_save_maximized) {
1019 recent.gui_geometry_main_maximized = geom.maximized;
1022 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
1023 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
1024 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
1028 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1032 /* save file first */
1033 file_save_as_cmd(after_save_exit, NULL);
1035 case(ESD_BTN_DONT_SAVE):
1038 case(ESD_BTN_CANCEL):
1041 g_assert_not_reached();
1046 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1050 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1051 /* user didn't saved his current file, ask him */
1052 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1053 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1054 "If you quit the program without saving, your capture data will be discarded.");
1055 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1057 /* unchanged file, just exit */
1063 print_usage(gboolean print_ver) {
1069 fprintf(output, "This is GNU " PACKAGE " " VERSION
1074 comp_info_str->str, runtime_info_str->str);
1079 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n",
1081 fprintf(output, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
1082 fprintf(output, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
1083 fprintf(output, "\t[ -i <interface> ] [ -m <medium font> ] [ -N <resolving> ]\n");
1084 fprintf(output, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1085 fprintf(output, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1086 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1087 fprintf(output, "\t[ -w <savefile> ] [ -y <link type> ] [ -z <statistics string> ]\n");
1088 fprintf(output, "\t[ <infile> ]\n");
1090 fprintf(output, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1092 fprintf(output, "\t[ -N <resolving> ] [ -o <preference setting> ...\n");
1093 fprintf(output, "\t[ -P <packet list height> ] [ -r <infile> ] [ -R <read filter> ]\n");
1094 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1095 fprintf(output, "\t[ -z <statistics string> ] [ <infile> ]\n");
1106 printf(PACKAGE " " VERSION
1111 comp_info_str->str, runtime_info_str->str);
1115 get_natural_int(const char *string, const char *name)
1120 number = strtol(string, &p, 10);
1121 if (p == string || *p != '\0') {
1122 fprintf(stderr, "ethereal: The specified %s \"%s\" isn't a decimal number\n",
1127 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1131 if (number > INT_MAX) {
1132 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1133 name, string, INT_MAX);
1140 get_positive_int(const char *string, const char *name)
1144 number = get_natural_int(string, name);
1147 fprintf(stderr, "ethereal: The specified %s is zero\n",
1155 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1157 Once every 3 seconds we get a callback here which we use to update
1158 the tap extensions. Since Gtk1 is single threaded we dont have to
1159 worry about any locking or critical regions.
1162 update_cb(gpointer data _U_)
1164 draw_tap_listeners(FALSE);
1169 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1170 use threads all updte_thread_mutex can be dropped and protect/unprotect
1171 would just be empty functions.
1173 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1174 gtk1-ethereal and it will just work.
1176 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1178 update_thread(gpointer data _U_)
1182 g_get_current_time(&tv1);
1183 g_static_mutex_lock(&update_thread_mutex);
1184 gdk_threads_enter();
1185 draw_tap_listeners(FALSE);
1186 gdk_threads_leave();
1187 g_static_mutex_unlock(&update_thread_mutex);
1189 g_get_current_time(&tv2);
1190 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1191 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1192 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1193 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1200 protect_thread_critical_region(void)
1202 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1203 g_static_mutex_lock(&update_thread_mutex);
1207 unprotect_thread_critical_region(void)
1209 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1210 g_static_mutex_unlock(&update_thread_mutex);
1214 /* structure to keep track of what tap listeners have been registered.
1216 typedef struct _ethereal_tap_list {
1217 struct _ethereal_tap_list *next;
1219 void (*func)(char *arg);
1220 } ethereal_tap_list;
1221 static ethereal_tap_list *tap_list=NULL;
1224 register_ethereal_tap(char *cmd, void (*func)(char *arg))
1226 ethereal_tap_list *newtl;
1228 newtl=malloc(sizeof(ethereal_tap_list));
1229 newtl->next=tap_list;
1236 /* Set the file name in the status line, in the name for the main window,
1237 and in the name for the main window's icon. */
1239 set_display_filename(capture_file *cf)
1241 const gchar *name_ptr;
1243 static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
1244 static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
1246 gchar *win_name_fmt = "%s - Ethereal";
1250 name_ptr = cf_get_display_name(cf);
1252 if (!cf->is_tempfile) {
1253 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1254 add_menu_recent_capture_file(cf->filename);
1257 if (cf->f_len/1024/1024 > 10) {
1258 size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
1259 } else if (cf->f_len/1024 > 10) {
1260 size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
1262 size_str = g_strdup_printf("%ld bytes", cf->f_len);
1265 if (cf->drops_known) {
1266 done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str,
1267 cf->esec/3600, cf->esec%3600/60, cf->esec%60, cf->drops);
1269 done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
1270 cf->esec/3600, cf->esec%3600/60, cf->esec%60);
1272 statusbar_push_file_msg(done_msg);
1275 msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
1276 win_name = g_malloc(msg_len);
1277 snprintf(win_name, msg_len, win_name_fmt, name_ptr);
1278 set_main_window_name(win_name);
1284 main_cf_cb_file_closed(capture_file *cf)
1286 /* Destroy all windows, which refer to the
1287 capture file we're closing. */
1288 destroy_cfile_wins();
1290 /* Clear any file-related status bar messages.
1291 XXX - should be "clear *ALL* file-related status bar messages;
1292 will there ever be more than one on the stack? */
1293 statusbar_pop_file_msg();
1295 /* Restore the standard title bar message. */
1296 set_main_window_name("The Ethereal Network Analyzer");
1298 /* Disable all menu items that make sense only if you have a capture. */
1299 set_menus_for_capture_file(FALSE);
1300 set_menus_for_unsaved_capture_file(FALSE);
1301 set_menus_for_captured_packets(FALSE);
1302 set_menus_for_selected_packet(cf);
1303 set_menus_for_capture_in_progress(FALSE);
1304 set_menus_for_selected_tree_row(cf);
1306 /* Set up main window for no capture file. */
1307 main_set_for_capture_file(FALSE);
1311 main_cf_cb_file_read_start(capture_file *cf)
1313 const gchar *name_ptr;
1316 name_ptr = get_basename(cf->filename);
1318 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1319 statusbar_push_file_msg(load_msg);
1324 main_cf_cb_file_read_finished(capture_file *cf)
1326 statusbar_pop_file_msg();
1327 set_display_filename(cf);
1329 /* Enable menu items that make sense if you have a capture file you've
1330 finished reading. */
1331 set_menus_for_capture_file(TRUE);
1332 set_menus_for_unsaved_capture_file(!cf->user_saved);
1334 /* Enable menu items that make sense if you have some captured packets. */
1335 set_menus_for_captured_packets(TRUE);
1337 /* Set up main window for a capture file. */
1338 main_set_for_capture_file(TRUE);
1343 main_cf_cb_live_capture_prepare(capture_options *capture_opts)
1348 title = g_strdup_printf("%s: Capturing - Ethereal",
1349 get_interface_descriptive_name(capture_opts->iface));
1350 set_main_window_name(title);
1355 main_cf_cb_live_capture_started(capture_options *capture_opts)
1359 /* Disable menu items that make no sense if you're currently running
1361 set_menus_for_capture_in_progress(TRUE);
1363 /* Enable menu items that make sense if you have some captured
1364 packets (yes, I know, we don't have any *yet*). */
1365 set_menus_for_captured_packets(TRUE);
1367 capture_msg = g_strdup_printf(" %s: <live capture in progress>", get_interface_descriptive_name(capture_opts->iface));
1369 statusbar_push_file_msg(capture_msg);
1371 g_free(capture_msg);
1373 /* Set up main window for a capture file. */
1374 main_set_for_capture_file(TRUE);
1378 main_cf_cb_live_capture_finished(capture_file *cf)
1380 /* Pop the "<live capture in progress>" message off the status bar. */
1381 statusbar_pop_file_msg();
1383 set_display_filename(cf);
1385 /* Enable menu items that make sense if you're not currently running
1387 set_menus_for_capture_in_progress(FALSE);
1389 /* Enable menu items that make sense if you have a capture file
1390 you've finished reading. */
1391 set_menus_for_capture_file(TRUE);
1392 set_menus_for_unsaved_capture_file(!cf->user_saved);
1394 /* Set up main window for a capture file. */
1395 main_set_for_capture_file(TRUE);
1400 main_cf_cb_packet_selected(gpointer data)
1402 capture_file *cf = data;
1404 /* Display the GUI protocol tree and hex dump.
1405 XXX - why do we dump core if we call "proto_tree_draw()"
1406 before calling "add_byte_views()"? */
1407 add_main_byte_views(cf->edt);
1408 main_proto_tree_draw(cf->edt->tree);
1410 /* A packet is selected. */
1411 set_menus_for_selected_packet(cf);
1415 main_cf_cb_packet_unselected(capture_file *cf)
1417 /* Clear out the display of that packet. */
1418 clear_tree_and_hex_views();
1420 /* No packet is selected. */
1421 set_menus_for_selected_packet(cf);
1425 main_cf_cb_field_unselected(capture_file *cf)
1427 statusbar_pop_field_msg();
1428 set_menus_for_selected_tree_row(cf);
1432 main_cf_cb_file_safe_started(gchar * filename)
1434 const gchar *name_ptr;
1437 name_ptr = get_basename(filename);
1439 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1441 statusbar_push_file_msg(save_msg);
1446 main_cf_cb_file_safe_finished(gpointer data _U_)
1448 /* Pop the "Saving:" message off the status bar. */
1449 statusbar_pop_file_msg();
1453 main_cf_cb_file_safe_failed(gpointer data _U_)
1455 /* Pop the "Saving:" message off the status bar. */
1456 statusbar_pop_file_msg();
1460 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1462 set_menus_for_unsaved_capture_file(FALSE);
1465 void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1468 case(cf_cb_file_closed):
1469 main_cf_cb_file_closed(data);
1471 case(cf_cb_file_read_start):
1472 main_cf_cb_file_read_start(data);
1474 case(cf_cb_file_read_finished):
1475 main_cf_cb_file_read_finished(data);
1478 case(cf_cb_live_capture_prepare):
1479 main_cf_cb_live_capture_prepare(data);
1481 case(cf_cb_live_capture_started):
1482 main_cf_cb_live_capture_started(data);
1484 case(cf_cb_live_capture_finished):
1485 main_cf_cb_live_capture_finished(data);
1488 case(cf_cb_packet_selected):
1489 main_cf_cb_packet_selected(data);
1491 case(cf_cb_packet_unselected):
1492 main_cf_cb_packet_unselected(data);
1494 case(cf_cb_field_unselected):
1495 main_cf_cb_field_unselected(data);
1497 case(cf_cb_file_safe_started):
1498 main_cf_cb_file_safe_started(data);
1500 case(cf_cb_file_safe_finished):
1501 main_cf_cb_file_safe_finished(data);
1503 case(cf_cb_file_safe_reload_finished):
1504 main_cf_cb_file_safe_reload_finished(data);
1506 case(cf_cb_file_safe_failed):
1507 main_cf_cb_file_safe_failed(data);
1510 g_warning("main_cf_callback: event %u unknown", event);
1511 g_assert_not_reached();
1515 /* And now our feature presentation... [ fade to music ] */
1517 main(int argc, char *argv[])
1520 const char *command_name;
1525 extern char *optarg;
1526 gboolean arg_error = FALSE;
1534 char *gpf_path, *pf_path;
1535 char *cf_path, *df_path;
1536 char *gdp_path, *dp_path;
1537 int gpf_open_errno, gpf_read_errno;
1538 int pf_open_errno, pf_read_errno;
1539 int cf_open_errno, df_open_errno;
1540 int gdp_open_errno, gdp_read_errno;
1541 int dp_open_errno, dp_read_errno;
1544 gboolean start_capture = FALSE;
1547 GList *lt_list, *lt_entry;
1548 data_link_info_t *data_link_info;
1549 gchar err_str[PCAP_ERRBUF_SIZE];
1550 gchar *cant_get_if_list_errstr;
1551 gboolean stats_known;
1552 struct pcap_stat stats;
1554 gboolean capture_option_specified = FALSE;
1556 gint pl_size = 280, tv_size = 95, bv_size = 75;
1557 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1558 dfilter_t *rfcode = NULL;
1559 gboolean rfilter_parse_failed = FALSE;
1562 ethereal_tap_list *tli = NULL;
1563 gchar *tap_opt = NULL;
1564 GtkWidget *splash_win = NULL;
1566 #define OPTSTRING_INIT "a:b:B:c:f:Hhi:klLm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:"
1570 #define OPTSTRING_CHILD "W:Z:"
1572 #define OPTSTRING_CHILD "W:"
1575 #define OPTSTRING_CHILD ""
1576 #endif /* HAVE_LIBPCAP */
1578 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1582 /* Set the current locale according to the program environment.
1583 * We haven't localized anything, but some GTK widgets are localized
1584 * (the file selection dialogue, for example).
1585 * This also sets the C-language locale to the native environment. */
1588 /* Let GTK get its args */
1589 gtk_init (&argc, &argv);
1591 cf_callback_add(main_cf_callback, NULL);
1593 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1594 /* initialize our GTK eth_clist_type */
1595 init_eth_clist_type();
1598 ethereal_path = argv[0];
1601 /* Arrange that if we have no console window, and a GLib message logging
1602 routine is called to log a message, we pop up a console window.
1604 We do that by inserting our own handler for all messages logged
1605 to the default domain; that handler pops up a console if necessary,
1606 and then calls the default handler. */
1607 g_log_set_handler(NULL,
1609 G_LOG_LEVEL_CRITICAL|
1610 G_LOG_LEVEL_WARNING|
1611 G_LOG_LEVEL_MESSAGE|
1614 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1615 console_log_handler, NULL);
1619 /* Set the initial values in the capture_opts. This might be overwritten
1620 by preference settings and then again by the command line parameters. */
1621 capture_opts_init(capture_opts, &cfile);
1623 command_name = get_basename(ethereal_path);
1624 /* Set "capture_child" to indicate whether this is going to be a child
1625 process for a "-S" capture. */
1626 capture_opts->capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1627 if (capture_opts->capture_child) {
1628 strcat(optstring, OPTSTRING_CHILD);
1632 /* We want a splash screen only if we're not a child process */
1633 /* We also want it only if we're not being run with "-G".
1634 XXX - we also don't want it if we're being run with
1635 "-h" or "-v", as those are options to run Ethereal and just
1636 have it print stuff to the command line. That would require
1637 that we parse the argument list before putting up the splash
1638 screen, which means we'd need to do so before reading the
1639 preference files, as that could take enough time that we'd
1640 want the splash screen up while we're doing that. Unfortunately,
1641 that means we'd have to queue up, for example, "-o" options,
1642 so that we apply them *after* reading the preferences, as
1643 they're supposed to override saved preferences. */
1644 if ((argc < 2 || strcmp(argv[1], "-G") != 0)
1646 && !capture_opts->capture_child
1649 splash_win = splash_new("Loading Ethereal ...");
1652 splash_update(splash_win, "Registering dissectors ...");
1654 /* Register all dissectors; we must do this before checking for the
1655 "-G" flag, as the "-G" flag dumps information registered by the
1656 dissectors, and we must do it before we read the preferences, in
1657 case any dissectors register preferences. */
1658 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1659 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1661 splash_update(splash_win, "Registering tap listeners ...");
1663 /* Register all tap listeners; we do this before we parse the arguments,
1664 as the "-z" argument can specify a registered tap. */
1665 register_all_tap_listeners();
1667 splash_update(splash_win, "Loading module preferences ...");
1669 /* Now register the preferences for any non-dissector modules.
1670 We must do that before we read the preferences as well. */
1671 prefs_register_modules();
1673 /* If invoked with the "-G" flag, we dump out information based on
1674 the argument to the "-G" flag; if no argument is specified,
1675 for backwards compatibility we dump out a glossary of display
1678 We must do this before calling "gtk_init()", because "gtk_init()"
1679 tries to open an X display, and we don't want to have to do any X
1680 stuff just to do a build.
1682 Given that we call "gtk_init()" before doing the regular argument
1683 list processing, so that it can handle X and GTK+ arguments and
1684 remove them from the list at which we look, this means we must do
1685 this before doing the regular argument list processing, as well.
1689 you must give the "-G" flag as the first flag on the command line;
1691 you must give it as "-G", nothing more, nothing less;
1693 the first argument after the "-G" flag, if present, will be used
1694 to specify the information to dump;
1696 arguments after that will not be used. */
1697 handle_dashG_option(argc, argv, "ethereal");
1699 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1700 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1703 g_thread_init(NULL);
1705 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1706 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1708 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1709 /* this is to keep tap extensions updating once every 3 seconds */
1710 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1711 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1714 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1717 splash_update(splash_win, "Loading configuration files ...");
1719 /* Read the preference files. */
1720 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1721 &pf_open_errno, &pf_read_errno, &pf_path);
1722 if (gpf_path != NULL) {
1723 if (gpf_open_errno != 0) {
1724 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1725 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1726 strerror(gpf_open_errno));
1728 if (gpf_read_errno != 0) {
1729 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1730 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1731 strerror(gpf_read_errno));
1734 if (pf_path != NULL) {
1735 if (pf_open_errno != 0) {
1736 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1737 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1738 strerror(pf_open_errno));
1740 if (pf_read_errno != 0) {
1741 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1742 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1743 strerror(pf_read_errno));
1750 /* if the user wants a console to be always there, well, we should open one for him */
1751 if (prefs->gui_console_open == console_open_always) {
1757 /* If this is a capture child process, it should pay no attention
1758 to the "prefs.capture_prom_mode" setting in the preferences file;
1759 it should do what the parent process tells it to do, and if
1760 the parent process wants it not to run in promiscuous mode, it'll
1761 tell it so with a "-p" flag.
1763 Otherwise, set promiscuous mode from the preferences setting. */
1764 /* the same applies to other preferences settings as well. */
1765 if (capture_opts->capture_child) {
1766 auto_scroll_live = FALSE;
1768 capture_opts->promisc_mode = prefs->capture_prom_mode;
1769 capture_opts->show_info = prefs->capture_show_info;
1770 capture_opts->sync_mode = prefs->capture_real_time;
1771 auto_scroll_live = prefs->capture_auto_scroll;
1774 #endif /* HAVE_LIBPCAP */
1776 /* Set the name resolution code's flags from the preferences. */
1777 g_resolv_flags = prefs->name_resolve;
1779 /* Read the capture filter file. */
1780 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1781 if (cf_path != NULL) {
1782 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1783 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1784 strerror(cf_open_errno));
1788 /* Read the display filter file. */
1789 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1790 if (df_path != NULL) {
1791 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1792 "Could not open your display filter file\n\"%s\": %s.", df_path,
1793 strerror(df_open_errno));
1797 /* Read the disabled protocols file. */
1798 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1799 &dp_path, &dp_open_errno, &dp_read_errno);
1800 if (gdp_path != NULL) {
1801 if (gdp_open_errno != 0) {
1802 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1803 "Could not open global disabled protocols file\n\"%s\": %s.",
1804 gdp_path, strerror(gdp_open_errno));
1806 if (gdp_read_errno != 0) {
1807 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1808 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1809 gdp_path, strerror(gdp_read_errno));
1813 if (dp_path != NULL) {
1814 if (dp_open_errno != 0) {
1815 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1816 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1817 strerror(dp_open_errno));
1819 if (dp_read_errno != 0) {
1820 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1821 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
1822 strerror(dp_read_errno));
1827 init_cap_file(&cfile);
1830 /* Load wpcap if possible. Do this before collecting the run-time version information */
1833 /* Start windows sockets */
1834 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1837 /* Assemble the compile-time version information string */
1838 comp_info_str = g_string_new("Compiled ");
1839 g_string_append(comp_info_str, "with ");
1840 g_string_sprintfa(comp_info_str,
1841 #ifdef GTK_MAJOR_VERSION
1842 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1845 "GTK+ (version unknown)");
1848 g_string_append(comp_info_str, ", ");
1849 get_compiled_version_info(comp_info_str);
1851 /* Assemble the run-time version information string */
1852 runtime_info_str = g_string_new("Running ");
1853 get_runtime_version_info(runtime_info_str);
1855 /* Now get our args */
1856 while ((opt = getopt(argc, argv, optstring)) != -1) {
1858 /*** capture option specific ***/
1859 case 'a': /* autostop criteria */
1860 case 'b': /* Ringbuffer option */
1861 case 'c': /* Capture xxx packets */
1862 case 'f': /* capture filter */
1863 case 'k': /* Start capture immediately */
1864 case 'H': /* Hide capture info dialog box */
1865 case 'i': /* Use interface xxx */
1866 case 'p': /* Don't capture in promiscuous mode */
1867 case 'Q': /* Quit after capture (just capture to file) */
1868 case 's': /* Set the snapshot (capture) length */
1869 case 'S': /* "Sync" mode: used for following file ala tail -f */
1870 case 'w': /* Write to capture file xxx */
1871 case 'y': /* Set the pcap data link type */
1873 /* Hidden option supporting Sync mode */
1874 case 'Z': /* Write to pipe FD XXX */
1877 capture_opt_add(capture_opts, opt, optarg, &start_capture);
1879 capture_option_specified = TRUE;
1884 /* This is a hidden option supporting Sync mode, so we don't set
1885 * the error flags for the user in the non-libpcap case.
1887 case 'W': /* Write to capture file FD xxx */
1888 capture_opt_add(capture_opts, opt, optarg, &start_capture);
1892 /*** all non capture option specific ***/
1893 case 'B': /* Byte view pane height */
1894 bv_size = get_positive_int(optarg, "byte view pane height");
1896 case 'h': /* Print help and exit */
1900 case 'l': /* Automatic scrolling in live capture mode */
1902 auto_scroll_live = TRUE;
1904 capture_option_specified = TRUE;
1908 case 'L': /* Print list of link-layer types and exit */
1910 list_link_layer_types = TRUE;
1912 capture_option_specified = TRUE;
1916 case 'm': /* Fixed-width font for the display */
1917 if (prefs->PREFS_GUI_FONT_NAME != NULL)
1918 g_free(prefs->PREFS_GUI_FONT_NAME);
1919 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
1921 case 'n': /* No name resolution */
1922 g_resolv_flags = RESOLV_NONE;
1924 case 'N': /* Select what types of addresses/port #s to resolve */
1925 if (g_resolv_flags == RESOLV_ALL)
1926 g_resolv_flags = RESOLV_NONE;
1927 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1928 if (badopt != '\0') {
1929 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1934 case 'o': /* Override preference from command line */
1935 switch (prefs_set_pref(optarg)) {
1937 case PREFS_SET_SYNTAX_ERR:
1938 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1942 case PREFS_SET_NO_SUCH_PREF:
1943 case PREFS_SET_OBSOLETE:
1944 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1950 case 'P': /* Packet list pane height */
1951 pl_size = get_positive_int(optarg, "packet list pane height");
1953 case 'r': /* Read capture file xxx */
1954 /* We may set "last_open_dir" to "cf_name", and if we change
1955 "last_open_dir" later, we free the old value, so we have to
1956 set "cf_name" to something that's been allocated. */
1957 cf_name = g_strdup(optarg);
1959 case 'R': /* Read file filter */
1962 case 't': /* Time stamp type */
1963 if (strcmp(optarg, "r") == 0)
1964 set_timestamp_setting(TS_RELATIVE);
1965 else if (strcmp(optarg, "a") == 0)
1966 set_timestamp_setting(TS_ABSOLUTE);
1967 else if (strcmp(optarg, "ad") == 0)
1968 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
1969 else if (strcmp(optarg, "d") == 0)
1970 set_timestamp_setting(TS_DELTA);
1972 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1974 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1975 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1979 case 'T': /* Tree view pane height */
1980 tv_size = get_positive_int(optarg, "tree view pane height");
1982 case 'v': /* Show version and exit */
1990 for(tli=tap_list;tli;tli=tli->next){
1991 if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
1992 tap_opt = g_strdup(optarg);
1997 fprintf(stderr,"ethereal: invalid -z argument.\n");
1998 fprintf(stderr," -z argument must be one of :\n");
1999 for(tli=tap_list;tli;tli=tli->next){
2000 fprintf(stderr," %s\n",tli->cmd);
2006 case '?': /* Bad flag - print usage message */
2014 if (cf_name != NULL) {
2016 * Input file name specified with "-r" *and* specified as a regular
2017 * command-line argument.
2022 * Input file name not specified with "-r", and a command-line argument
2023 * was specified; treat it as the input file name.
2025 * Yes, this is different from tethereal, where non-flag command-line
2026 * arguments are a filter, but this works better on GUI desktops
2027 * where a command can be specified to be run to open a particular
2028 * file - yes, you could have "-r" as the last part of the command,
2029 * but that's a bit ugly.
2031 cf_name = g_strdup(argv[0]);
2041 * Extra command line arguments were specified; complain.
2043 fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2048 #ifndef HAVE_LIBPCAP
2049 if (capture_option_specified) {
2050 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2058 if (start_capture && list_link_layer_types) {
2059 /* Specifying *both* is bogus. */
2060 fprintf(stderr, "ethereal: You can't specify both -L and a live capture.\n");
2064 if (list_link_layer_types) {
2065 /* We're supposed to list the link-layer types for an interface;
2066 did the user also specify a capture file to be read? */
2068 /* Yes - that's bogus. */
2069 fprintf(stderr, "ethereal: You can't specify -L and a capture file to be read.\n");
2072 /* No - did they specify a ring buffer option? */
2073 if (capture_opts->multi_files_on) {
2074 fprintf(stderr, "ethereal: Ring buffer requested, but a capture isn't being done.\n");
2078 /* We're supposed to do a live capture; did the user also specify
2079 a capture file to be read? */
2080 if (start_capture && cf_name) {
2081 /* Yes - that's bogus. */
2082 fprintf(stderr, "ethereal: You can't specify both a live capture and a capture file to be read.\n");
2086 /* No - was the ring buffer option specified and, if so, does it make
2088 if (capture_opts->multi_files_on) {
2089 /* Ring buffer works only under certain conditions:
2090 a) ring buffer does not work with temporary files;
2091 b) sync_mode and capture_opts->ringbuffer_on are mutually exclusive -
2092 sync_mode takes precedence;
2093 c) it makes no sense to enable the ring buffer if the maximum
2094 file size is set to "infinite". */
2095 if (capture_opts->save_file == NULL) {
2096 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2097 capture_opts->multi_files_on = FALSE;
2099 if (capture_opts->sync_mode) {
2100 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2101 capture_opts->multi_files_on = FALSE;
2103 if (!capture_opts->has_autostop_filesize) {
2104 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
2105 capture_opts->multi_files_on = FALSE;
2110 if (start_capture || list_link_layer_types) {
2111 /* Did the user specify an interface to use? */
2112 if (capture_opts->iface == NULL) {
2113 /* No - is a default specified in the preferences file? */
2114 if (prefs->capture_device != NULL) {
2116 capture_opts->iface = g_strdup(prefs->capture_device);
2118 /* No - pick the first one from the list of interfaces. */
2119 if_list = get_interface_list(&err, err_str);
2120 if (if_list == NULL) {
2123 case CANT_GET_INTERFACE_LIST:
2124 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2125 fprintf(stderr, "%s\n", cant_get_if_list_errstr);
2126 g_free(cant_get_if_list_errstr);
2129 case NO_INTERFACES_FOUND:
2130 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2135 if_info = if_list->data; /* first interface */
2136 capture_opts->iface = g_strdup(if_info->name);
2137 free_interface_list(if_list);
2142 if (capture_opts->capture_child) {
2143 if (capture_opts->save_file_fd == -1) {
2144 /* XXX - send this to the standard output as something our parent
2145 should put in an error message box? */
2146 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2151 if (list_link_layer_types) {
2152 /* Get the list of link-layer types for the capture device. */
2153 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2154 if (lt_list == NULL) {
2155 if (err_str[0] != '\0') {
2156 fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2157 "Please check to make sure you have sufficient permissions, and that\n"
2158 "you have the proper interface or pipe specified.\n", err_str);
2160 fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2163 fprintf(stderr, "Data link types (use option -y to set):\n");
2164 for (lt_entry = lt_list; lt_entry != NULL;
2165 lt_entry = g_list_next(lt_entry)) {
2166 data_link_info = lt_entry->data;
2167 fprintf(stderr, " %s", data_link_info->name);
2168 if (data_link_info->description != NULL)
2169 fprintf(stderr, " (%s)", data_link_info->description);
2171 fprintf(stderr, " (not supported)");
2174 free_pcap_linktype_list(lt_list);
2178 if (capture_opts->has_snaplen) {
2179 if (capture_opts->snaplen < 1)
2180 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2181 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2182 capture_opts->snaplen = MIN_PACKET_SIZE;
2185 /* Check the value range of the ringbuffer_num_files parameter */
2186 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2187 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2188 #if RINGBUFFER_MIN_NUM_FILES > 0
2189 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2190 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2192 #endif /* HAVE_LIBPCAP */
2194 /* Notify all registered modules that have had any of their preferences
2195 changed either from one of the preferences file or from the command
2196 line that their preferences have changed. */
2199 /* disabled protocols as per configuration file */
2200 if (gdp_path == NULL && dp_path == NULL) {
2201 set_disabled_protos_list();
2204 /* Build the column format array */
2205 col_setup(&cfile.cinfo, prefs->num_cols);
2206 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2207 cfile.cinfo.col_fmt[i] = get_column_format(i);
2208 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2209 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2211 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2212 cfile.cinfo.col_data[i] = NULL;
2213 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2214 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2216 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2217 cfile.cinfo.col_fence[i] = 0;
2218 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2219 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2222 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2225 for (j = 0; j < NUM_COL_FMTS; j++) {
2226 if (!cfile.cinfo.fmt_matx[i][j])
2229 if (cfile.cinfo.col_first[j] == -1)
2230 cfile.cinfo.col_first[j] = i;
2231 cfile.cinfo.col_last[j] = i;
2235 /* read in rc file from global and personal configuration paths. */
2236 /* XXX - is this a good idea? */
2237 gtk_rc_parse(RC_FILE);
2238 rc_file = get_persconffile_path(RC_FILE, FALSE);
2239 gtk_rc_parse(rc_file);
2242 font_init(capture_opts->capture_child);
2247 /* close the splash screen, as we are going to open the main window now */
2248 splash_destroy(splash_win);
2252 /* Is this a "child" ethereal, which is only supposed to pop up a
2253 capture box to let us stop the capture, and run a capture
2254 to a file that our parent will read? */
2255 if (capture_opts->capture_child) {
2256 /* This is the child process for a sync mode or fork mode capture,
2257 so just do the low-level work of a capture - don't create
2258 a temporary file and fork off *another* child process (so don't
2259 call "do_capture()"). */
2261 /* Pop up any queued-up alert boxes. */
2262 display_queued_messages();
2264 /* XXX - hand these stats to the parent process */
2265 capture_start(capture_opts, &stats_known, &stats);
2267 /* The capture is done; there's nothing more for us to do. */
2272 /***********************************************************************/
2273 /* Everything is prepared now, preferences and command line was read in,
2274 we are NOT a child window for a synced capture. */
2276 /* Pop up the main window, and read in a capture file if
2278 create_main_window(pl_size, tv_size, bv_size, prefs);
2280 /* Read the recent file, as we have the gui now ready for it. */
2281 read_recent(&rf_path, &rf_open_errno);
2283 /* rearrange all the widgets as we now have the recent settings for this */
2284 main_widgets_rearrange();
2286 /* Fill in column titles. This must be done after the top level window
2289 XXX - is that still true, with fixed-width columns? */
2290 packet_list_set_column_titles();
2292 menu_recent_read_finished();
2294 switch (user_font_apply()) {
2297 case FA_FONT_NOT_RESIZEABLE:
2298 /* "user_font_apply()" popped up an alert box. */
2299 /* turn off zooming - font can't be resized */
2300 case FA_FONT_NOT_AVAILABLE:
2301 /* XXX - did we successfully load the un-zoomed version earlier?
2302 If so, this *probably* means the font is available, but not at
2303 this particular zoom level, but perhaps some other failure
2304 occurred; I'm not sure you can determine which is the case,
2306 /* turn off zooming - zoom level is unavailable */
2308 /* in any other case than FA_SUCCESS, turn off zooming */
2309 recent.gui_zoom_level = 0;
2310 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2313 dnd_init(top_level);
2319 /* the window can be sized only, if it's not already shown, so do it now! */
2320 main_load_window_geometry(top_level);
2322 /* If we were given the name of a capture file, read it in now;
2323 we defer it until now, so that, if we can't open it, and pop
2324 up an alert box, the alert box is more likely to come up on
2325 top of the main window - but before the preference-file-error
2326 alert box, so, if we get one of those, it's more likely to come
2329 show_main_window(TRUE);
2330 if (rfilter != NULL) {
2331 if (!dfilter_compile(rfilter, &rfcode)) {
2332 bad_dfilter_alert_box(rfilter);
2333 rfilter_parse_failed = TRUE;
2336 if (!rfilter_parse_failed) {
2337 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2338 /* "cf_open()" succeeded, so it closed the previous
2339 capture file, and thus destroyed any previous read filter
2340 attached to "cf". */
2342 cfile.rfcode = rfcode;
2343 /* Open tap windows; we do so after creating the main window,
2344 to avoid GTK warnings, and after successfully opening the
2345 capture file, so we know we have something to tap. */
2346 if (tap_opt && tli) {
2347 (*tli->func)(tap_opt);
2351 /* Read the capture file. */
2352 switch (cf_read(&cfile)) {
2356 /* Just because we got an error, that doesn't mean we were unable
2357 to read any of the file; we handle what we could get from the
2361 case CF_READ_ABORTED:
2366 /* Save the name of the containing directory specified in the
2367 path name, if any; we can write over cf_name, which is a
2368 good thing, given that "get_dirname()" does write over its
2370 s = get_dirname(cf_name);
2371 /* we might already set this from the recent file, don't overwrite this */
2372 if(get_last_open_dir() == NULL)
2373 set_last_open_dir(s);
2378 dfilter_free(rfcode);
2379 cfile.rfcode = NULL;
2384 if (start_capture) {
2385 if (capture_opts->save_file != NULL) {
2386 /* Save the directory name for future file dialogs. */
2387 /* (get_dirname overwrites filename) */
2388 s = get_dirname(g_strdup(capture_opts->save_file));
2389 set_last_open_dir(s);
2392 /* "-k" was specified; start a capture. */
2393 show_main_window(TRUE);
2394 if (do_capture(capture_opts)) {
2395 /* The capture started. Open tap windows; we do so after creating
2396 the main window, to avoid GTK warnings, and after starting the
2397 capture, so we know we have something to tap. */
2398 if (tap_opt && tli) {
2399 (*tli->func)(tap_opt);
2405 show_main_window(FALSE);
2406 set_menus_for_capture_in_progress(FALSE);
2409 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2410 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2411 if (capture_opts->cfilter) {
2412 g_free(capture_opts->cfilter);
2414 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2416 #else /* HAVE_LIBPCAP */
2417 show_main_window(FALSE);
2418 set_menus_for_capture_in_progress(FALSE);
2419 #endif /* HAVE_LIBPCAP */
2428 /* Shutdown windows sockets */
2431 /* For some unknown reason, the "atexit()" call in "create_console()"
2432 doesn't arrange that "destroy_console()" be called when we exit,
2433 so we call it here if a console was created. */
2439 /* This isn't reached, but we need it to keep GCC from complaining
2440 that "main()" returns without returning a value - it knows that
2441 "exit()" never returns, but it doesn't know that "gtk_exit()"
2442 doesn't, as GTK+ doesn't declare it with the attribute
2444 return 0; /* not reached */
2449 /* We build this as a GUI subsystem application on Win32, so
2450 "WinMain()", not "main()", gets called.
2452 Hack shamelessly stolen from the Win32 port of the GIMP. */
2454 #define _stdcall __attribute__((stdcall))
2458 WinMain (struct HINSTANCE__ *hInstance,
2459 struct HINSTANCE__ *hPrevInstance,
2463 has_console = FALSE;
2464 return main (__argc, __argv);
2468 * If this application has no console window to which its standard output
2469 * would go, create one.
2472 create_console(void)
2474 if (!has_console && prefs.gui_console_open != console_open_never) {
2475 /* We have no console to which to print the version string, so
2476 create one and make it the standard input, output, and error. */
2477 if (!AllocConsole())
2478 return; /* couldn't create console */
2479 freopen("CONIN$", "r", stdin);
2480 freopen("CONOUT$", "w", stdout);
2481 freopen("CONOUT$", "w", stderr);
2483 /* Well, we have a console now. */
2486 /* Now register "destroy_console()" as a routine to be called just
2487 before the application exits, so that we can destroy the console
2488 after the user has typed a key (so that the console doesn't just
2489 disappear out from under them, giving the user no chance to see
2490 the message(s) we put in there). */
2491 atexit(destroy_console);
2496 destroy_console(void)
2499 printf("\n\nPress any key to exit\n");
2505 /* This routine should not be necessary, at least as I read the GLib
2506 source code, as it looks as if GLib is, on Win32, *supposed* to
2507 create a console window into which to display its output.
2509 That doesn't happen, however. I suspect there's something completely
2510 broken about that code in GLib-for-Win32, and that it may be related
2511 to the breakage that forces us to just call "printf()" on the message
2512 rather than passing the message on to "g_log_default_handler()"
2513 (which is the routine that does the aforementioned non-functional
2514 console window creation). */
2516 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2517 const char *message, gpointer user_data)
2521 /* For some unknown reason, the above doesn't appear to actually cause
2522 anything to be sent to the standard output, so we'll just splat the
2523 message out directly, just to make sure it gets out. */
2524 printf("%s\n", message);
2526 g_log_default_handler(log_domain, log_level, message, user_data);
2531 GtkWidget *info_bar_new(void)
2533 /* tip: tooltips don't work on statusbars! */
2534 info_bar = gtk_statusbar_new();
2535 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2536 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2537 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2538 #if GTK_MAJOR_VERSION >= 2
2539 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2541 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2546 GtkWidget *packets_bar_new(void)
2548 /* tip: tooltips don't work on statusbars! */
2549 packets_bar = gtk_statusbar_new();
2550 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2551 packets_bar_update();
2558 * Helper for main_widgets_rearrange()
2560 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2561 gtk_container_remove(GTK_CONTAINER(data), widget);
2564 GtkWidget *main_widget_layout(gint layout_content)
2566 switch(layout_content) {
2567 case(layout_pane_content_none):
2570 case(layout_pane_content_plist):
2573 case(layout_pane_content_pdetails):
2576 case(layout_pane_content_pbytes):
2580 g_assert_not_reached();
2587 * Rearrange the main window widgets
2589 void main_widgets_rearrange(void) {
2590 GtkWidget *first_pane_widget1, *first_pane_widget2;
2591 GtkWidget *second_pane_widget1, *second_pane_widget2;
2592 gboolean split_top_left;
2594 /* be a bit faster */
2595 gtk_widget_hide(main_vbox);
2597 /* be sure, we don't loose a widget while rearranging */
2598 gtk_widget_ref(menubar);
2599 gtk_widget_ref(main_tb);
2600 gtk_widget_ref(filter_tb);
2601 gtk_widget_ref(pkt_scrollw);
2602 gtk_widget_ref(tv_scrollw);
2603 gtk_widget_ref(byte_nb_ptr);
2604 gtk_widget_ref(stat_hbox);
2605 gtk_widget_ref(info_bar);
2606 gtk_widget_ref(packets_bar);
2607 gtk_widget_ref(status_pane);
2608 gtk_widget_ref(main_pane_v1);
2609 gtk_widget_ref(main_pane_v2);
2610 gtk_widget_ref(main_pane_h1);
2611 gtk_widget_ref(main_pane_h2);
2612 gtk_widget_ref(welcome_pane);
2614 /* empty all containers participating */
2615 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2616 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2617 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2618 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2619 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2620 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2621 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2623 /* add the menubar always at the top */
2624 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2627 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2629 /* filter toolbar in toolbar area */
2630 if (!prefs.filter_toolbar_show_in_statusbar) {
2631 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2634 /* fill the main layout panes */
2635 switch(prefs.gui_layout_type) {
2636 case(layout_type_5):
2637 main_first_pane = main_pane_v1;
2638 main_second_pane = main_pane_v2;
2639 split_top_left = FALSE;
2641 case(layout_type_2):
2642 main_first_pane = main_pane_v1;
2643 main_second_pane = main_pane_h1;
2644 split_top_left = FALSE;
2646 case(layout_type_1):
2647 main_first_pane = main_pane_v1;
2648 main_second_pane = main_pane_h1;
2649 split_top_left = TRUE;
2651 case(layout_type_4):
2652 main_first_pane = main_pane_h1;
2653 main_second_pane = main_pane_v1;
2654 split_top_left = FALSE;
2656 case(layout_type_3):
2657 main_first_pane = main_pane_h1;
2658 main_second_pane = main_pane_v1;
2659 split_top_left = TRUE;
2661 case(layout_type_6):
2662 main_first_pane = main_pane_h1;
2663 main_second_pane = main_pane_h2;
2664 split_top_left = FALSE;
2667 main_first_pane = NULL;
2668 main_second_pane = NULL;
2669 split_top_left = FALSE;
2670 g_assert_not_reached();
2672 if (split_top_left) {
2673 first_pane_widget1 = main_second_pane;
2674 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2675 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2676 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2678 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2679 first_pane_widget2 = main_second_pane;
2680 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2681 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2683 if (first_pane_widget1 != NULL)
2684 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2685 if (first_pane_widget2 != NULL)
2686 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2687 if (second_pane_widget1 != NULL)
2688 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2689 if (second_pane_widget2 != NULL)
2690 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2692 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2695 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2697 /* statusbar hbox */
2698 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2700 /* filter toolbar in statusbar hbox */
2701 if (prefs.filter_toolbar_show_in_statusbar) {
2702 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2706 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2707 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2708 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2710 /* hide widgets on users recent settings */
2711 main_widgets_show_or_hide();
2713 gtk_widget_show(main_vbox);
2717 is_widget_visible(GtkWidget *widget, gpointer data)
2719 gboolean *is_visible = data;
2722 if (GTK_WIDGET_VISIBLE(widget))
2729 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2730 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2732 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2734 GtkWidget *w, *item_hb;
2735 #if GTK_MAJOR_VERSION >= 2
2736 gchar *formatted_message;
2740 item_hb = gtk_hbox_new(FALSE, 1);
2742 w = BUTTON_NEW_FROM_STOCK(stock_item);
2743 WIDGET_SET_SIZE(w, 60, 60);
2744 #if GTK_MAJOR_VERSION >= 2
2745 gtk_button_set_label(GTK_BUTTON(w), label);
2747 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
2748 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
2750 w = gtk_label_new(message);
2751 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2752 #if GTK_MAJOR_VERSION >= 2
2753 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
2754 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
2755 g_free(formatted_message);
2758 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
2764 /* XXX - the layout has to be improved */
2768 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
2769 GtkWidget *w, *icon;
2773 welcome_scrollw = scrolled_window_new(NULL, NULL);
2775 welcome_hb = gtk_hbox_new(FALSE, 1);
2776 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
2778 welcome_vb = gtk_vbox_new(FALSE, 1);
2780 item_hb = gtk_hbox_new(FALSE, 1);
2782 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
2783 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
2785 #if GTK_MAJOR_VERSION < 2
2786 message = "Welcome to Ethereal!";
2788 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
2790 w = gtk_label_new(message);
2791 #if GTK_MAJOR_VERSION >= 2
2792 gtk_label_set_markup(GTK_LABEL(w), message);
2794 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2795 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
2797 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2799 w = gtk_label_new("What would you like to do?");
2800 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
2801 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
2804 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
2806 "Capture live data from your network",
2807 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
2808 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2811 item_hb = welcome_item(GTK_STOCK_OPEN,
2813 "Open a previously captured file",
2814 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
2815 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2817 #if (GLIB_MAJOR_VERSION >= 2)
2818 item_hb = welcome_item(GTK_STOCK_HOME,
2820 "Visit the Ethereal homepage",
2821 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
2822 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2826 w = gtk_label_new("");
2827 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
2829 w = gtk_label_new("");
2830 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
2832 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
2834 w = gtk_label_new("");
2835 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
2837 gtk_widget_show_all(welcome_hb);
2839 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
2841 gtk_widget_show_all(welcome_scrollw);
2843 return welcome_scrollw;
2850 /* this is just a dummy to fill up window space, simply showing nothing */
2851 return scrolled_window_new(NULL, NULL);
2857 * XXX - this doesn't appear to work with the paned widgets in
2858 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
2859 * and the other pane doesn't grow to take up the rest of the pane.
2860 * It does appear to work with GTK+ 2.x.
2863 main_widgets_show_or_hide(void)
2865 gboolean main_second_pane_show;
2867 if (recent.main_toolbar_show) {
2868 gtk_widget_show(main_tb);
2870 gtk_widget_hide(main_tb);
2874 * Show the status hbox if either:
2876 * 1) we're showing the filter toolbar and we want it in the status
2881 * 2) we're showing the status bar.
2883 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
2884 recent.statusbar_show) {
2885 gtk_widget_show(stat_hbox);
2887 gtk_widget_hide(stat_hbox);
2890 if (recent.statusbar_show) {
2891 gtk_widget_show(status_pane);
2893 gtk_widget_hide(status_pane);
2896 if (recent.filter_toolbar_show) {
2897 gtk_widget_show(filter_tb);
2899 gtk_widget_hide(filter_tb);
2902 if (recent.packet_list_show && have_capture_file) {
2903 gtk_widget_show(pkt_scrollw);
2905 gtk_widget_hide(pkt_scrollw);
2908 if (recent.tree_view_show && have_capture_file) {
2909 gtk_widget_show(tv_scrollw);
2911 gtk_widget_hide(tv_scrollw);
2914 if (recent.byte_view_show && have_capture_file) {
2915 gtk_widget_show(byte_nb_ptr);
2917 gtk_widget_hide(byte_nb_ptr);
2920 if (have_capture_file) {
2921 gtk_widget_show(main_first_pane);
2923 gtk_widget_hide(main_first_pane);
2927 * Is anything in "main_second_pane" visible?
2928 * If so, show it, otherwise hide it.
2930 main_second_pane_show = FALSE;
2931 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
2932 &main_second_pane_show);
2933 if (main_second_pane_show) {
2934 gtk_widget_show(main_second_pane);
2936 gtk_widget_hide(main_second_pane);
2939 if (!have_capture_file) {
2941 gtk_widget_show(welcome_pane);
2944 gtk_widget_hide(welcome_pane);
2949 #if GTK_MAJOR_VERSION >= 2
2950 /* called, when the window state changes (minimized, maximized, ...) */
2952 window_state_event_cb (GtkWidget *widget _U_,
2956 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
2958 if( (event->type) == (GDK_WINDOW_STATE)) {
2959 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
2960 /* we might have dialogs popped up while we where iconified,
2962 display_queued_messages();
2971 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2974 *filter_bt, *filter_cm, *filter_te,
2975 *filter_add_expr_bt,
2978 GList *filter_list = NULL;
2979 GtkTooltips *tooltips;
2980 GtkAccelGroup *accel;
2982 /* Display filter construct dialog has an Apply button, and "OK" not
2983 only sets our text widget, it activates it (i.e., it causes us to
2984 filter the capture). */
2985 static construct_args_t args = {
2986 "Ethereal: Display Filter",
2991 /* use user-defined title if preference is set */
2992 title = create_user_window_title("The Ethereal Network Analyzer");
2995 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
2998 tooltips = gtk_tooltips_new();
3001 #if GTK_MAJOR_VERSION < 2
3002 /* has to be done, after top_level window is created */
3003 app_font_gtk1_init(top_level);
3007 gtk_widget_set_name(top_level, "main window");
3008 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3010 #if GTK_MAJOR_VERSION >= 2
3011 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3012 G_CALLBACK (window_state_event_cb), NULL);
3015 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3017 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3018 main_vbox = gtk_vbox_new(FALSE, 1);
3019 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3020 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3021 gtk_widget_show(main_vbox);
3024 menubar = main_menu_new(&accel);
3025 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3026 gtk_widget_show(menubar);
3029 main_tb = toolbar_new();
3030 gtk_widget_show (main_tb);
3033 pkt_scrollw = packet_list_new(prefs);
3034 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3035 gtk_widget_show(pkt_scrollw);
3038 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3039 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3040 gtk_widget_show(tv_scrollw);
3042 #if GTK_MAJOR_VERSION < 2
3043 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3044 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3047 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3048 "changed", tree_view_selection_changed_cb, NULL);
3050 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3051 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3052 gtk_widget_show(tree_view);
3055 byte_nb_ptr = byte_view_new();
3056 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3057 gtk_widget_show(byte_nb_ptr);
3059 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3060 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3063 /* Panes for the packet list, tree, and byte view */
3064 main_pane_v1 = gtk_vpaned_new();
3065 gtk_widget_show(main_pane_v1);
3066 main_pane_v2 = gtk_vpaned_new();
3067 gtk_widget_show(main_pane_v2);
3068 main_pane_h1 = gtk_hpaned_new();
3069 gtk_widget_show(main_pane_h1);
3070 main_pane_h2 = gtk_hpaned_new();
3071 gtk_widget_show(main_pane_h2);
3073 /* filter toolbar */
3074 #if GTK_MAJOR_VERSION < 2
3075 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3078 filter_tb = gtk_toolbar_new();
3079 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3080 GTK_ORIENTATION_HORIZONTAL);
3081 #endif /* GTK_MAJOR_VERSION */
3082 gtk_widget_show(filter_tb);
3084 /* Create the "Filter:" button */
3085 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3086 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3087 gtk_widget_show(filter_bt);
3088 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3090 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3091 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3093 /* Create the filter combobox */
3094 filter_cm = gtk_combo_new();
3096 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3097 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3098 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
3099 filter_te = GTK_COMBO(filter_cm)->entry;
3100 main_display_filter_widget=filter_te;
3101 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3102 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3103 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3104 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3105 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3106 WIDGET_SET_SIZE(filter_cm, 400, -1);
3107 gtk_widget_show(filter_cm);
3108 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3110 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3111 gtk_tooltips_set_tip(tooltips, filter_te,
3112 "Enter a display filter, or choose one of your recently used filters. "
3113 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3116 /* Create the "Add Expression..." button, to pop up a dialog
3117 for constructing filter comparison expressions. */
3118 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3119 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3120 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3121 gtk_widget_show(filter_add_expr_bt);
3122 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3123 "Add an expression to this filter string", "Private");
3125 /* Create the "Clear" button */
3126 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3127 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3128 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3129 gtk_widget_show(filter_reset);
3130 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3131 "Clear this filter string and update the display", "Private");
3133 /* Create the "Apply" button */
3134 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3135 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3136 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3137 gtk_widget_show(filter_apply);
3138 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3139 "Apply this filter string to the display", "Private");
3141 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3142 * of any widget that ends up calling a callback which needs
3143 * that text entry pointer */
3144 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3145 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3147 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3149 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3151 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3153 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3155 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3157 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3159 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3161 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3163 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3165 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3167 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3169 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3171 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3173 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3174 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3175 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3177 /* info (main) statusbar */
3178 info_bar = info_bar_new();
3179 gtk_widget_show(info_bar);
3181 /* packets statusbar */
3182 packets_bar = packets_bar_new();
3183 gtk_widget_show(packets_bar);
3185 /* Filter/status hbox */
3186 stat_hbox = gtk_hbox_new(FALSE, 1);
3187 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3188 gtk_widget_show(stat_hbox);
3190 /* Pane for the statusbar */
3191 status_pane = gtk_hpaned_new();
3192 gtk_widget_show(status_pane);
3194 /* Pane for the welcome screen */
3195 welcome_pane = welcome_new();
3196 gtk_widget_show(welcome_pane);
3200 show_main_window(gboolean doing_work)
3202 main_set_for_capture_file(doing_work);
3204 /*** we have finished all init things, show the main window ***/
3205 gtk_widget_show(top_level);
3207 /* the window can be maximized only, if it's visible, so do it after show! */
3208 main_load_window_geometry(top_level);
3210 /* process all pending GUI events before continue */
3211 while (gtk_events_pending()) gtk_main_iteration();
3213 /* Pop up any queued-up alert boxes. */
3214 display_queued_messages();