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.
43 #include <io.h> /* open/close on win32 */
46 #ifdef NEED_STRERROR_H
54 #ifdef _WIN32 /* Needed for console I/O */
59 #include <epan/epan.h>
60 #include <epan/filesystem.h>
61 #include <epan/epan_dissect.h>
62 #include <epan/timestamp.h>
63 #include <epan/packet.h>
64 #include <epan/plugins.h>
65 #include <epan/dfilter/dfilter.h>
66 #include <epan/strutil.h>
67 #include <epan/addr_resolv.h>
68 #include <epan/emem.h>
70 /* general (not GTK specific) */
74 #include "disabled_protos.h"
75 #include <epan/prefs.h>
76 #include "filter_dlg.h"
77 #include "layout_prefs.h"
79 #include "color_filters.h"
81 #include "simple_dialog.h"
83 #include <epan/prefs-int.h>
84 #include "ringbuffer.h"
85 #include "../ui_util.h"
87 #include <epan/stat_cmd_args.h>
89 #include "clopts_common.h"
90 #include "version_info.h"
95 #include "pcap-util.h"
100 #include "capture-wpcap.h"
101 #include "capture_wpcap_packet.h"
104 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
105 #include "ethclist.h"
109 #include "statusbar.h"
110 #include "alert_box.h"
111 #include "dlg_utils.h"
112 #include "gtkglobals.h"
114 #include "gui_utils.h"
115 #include "compat_macros.h"
119 #include "../main_window.h"
121 #include "file_dlg.h"
122 #include <epan/column.h>
123 #include "proto_draw.h"
125 #include "packet_win.h"
127 #include "find_dlg.h"
128 #include "packet_list.h"
130 #include "follow_dlg.h"
131 #include "font_utils.h"
132 #include "about_dlg.h"
133 #include "help_dlg.h"
134 #include "decode_as_dlg.h"
135 #include "webbrowser.h"
136 #include "capture_dlg.h"
138 #include "../image/eicon3d64.xpm"
140 #include "capture_ui_utils.h"
142 #include "../epan/emem.h"
147 * Files under personal and global preferences directories in which
148 * GTK settings for Ethereal are stored.
150 #define RC_FILE "gtkrc"
153 #define DEF_READY_MESSAGE " Ready to load or capture"
155 #define DEF_READY_MESSAGE " Ready to load file"
159 GtkWidget *main_display_filter_widget=NULL;
160 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
161 static GtkWidget *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
162 static GtkWidget *main_first_pane, *main_second_pane;
163 static GtkWidget *status_pane;
164 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
165 static GtkWidget *info_bar;
166 static GtkWidget *packets_bar = NULL;
167 static GtkWidget *welcome_pane;
168 static guint main_ctx, file_ctx, help_ctx;
169 static guint packets_ctx;
170 static gchar *packets_str = NULL;
171 GString *comp_info_str, *runtime_info_str;
172 gchar *ethereal_path = NULL;
173 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
175 gboolean capture_child; /* True if this is the child for "-S" */
177 static gboolean has_console; /* TRUE if app has console */
178 static void destroy_console(void);
180 static void console_log_handler(const char *log_domain,
181 GLogLevelFlags log_level, const char *message, gpointer user_data);
184 static gboolean list_link_layer_types;
185 capture_options global_capture_opts;
186 capture_options *capture_opts = &global_capture_opts;
190 static void create_main_window(gint, gint, gint, e_prefs*);
191 static void show_main_window(gboolean);
192 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
193 static void main_save_window_geometry(GtkWidget *widget);
195 #define E_DFILTER_CM_KEY "display_filter_combo"
196 #define E_DFILTER_FL_KEY "display_filter_list"
200 /* Match selected byte pattern */
202 match_selected_cb_do(gpointer data, int action, gchar *text)
204 GtkWidget *filter_te;
205 char *cur_filter, *new_filter;
210 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
213 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
215 switch (action&MATCH_SELECTED_MASK) {
217 case MATCH_SELECTED_REPLACE:
218 new_filter = g_strdup(text);
221 case MATCH_SELECTED_AND:
222 if ((!cur_filter) || (0 == strlen(cur_filter)))
223 new_filter = g_strdup(text);
225 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
228 case MATCH_SELECTED_OR:
229 if ((!cur_filter) || (0 == strlen(cur_filter)))
230 new_filter = g_strdup(text);
232 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
235 case MATCH_SELECTED_NOT:
236 new_filter = g_strconcat("!(", text, ")", NULL);
239 case MATCH_SELECTED_AND_NOT:
240 if ((!cur_filter) || (0 == strlen(cur_filter)))
241 new_filter = g_strconcat("!(", text, ")", NULL);
243 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
246 case MATCH_SELECTED_OR_NOT:
247 if ((!cur_filter) || (0 == strlen(cur_filter)))
248 new_filter = g_strconcat("!(", text, ")", NULL);
250 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
254 g_assert_not_reached();
259 /* Free up the copy we got of the old filter text. */
262 /* create a new one and set the display filter entry accordingly */
263 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
265 /* Run the display filter so it goes in effect. */
266 if (action&MATCH_SELECTED_APPLY_NOW)
267 main_filter_packets(&cfile, new_filter, FALSE);
269 /* Free up the new filter text. */
274 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
276 if (cfile.finfo_selected)
277 match_selected_cb_do((data ? data : w),
279 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
283 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
285 gchar *selected_proto_url;
286 gchar *proto_abbrev = data;
291 if (cfile.finfo_selected) {
292 /* open wiki page using the protocol abbreviation */
293 selected_proto_url = g_strdup_printf("http://wiki.ethereal.com/Protocols/%s", proto_abbrev);
294 browser_open_url(selected_proto_url);
295 g_free(selected_proto_url);
298 case(ESD_BTN_CANCEL):
301 g_assert_not_reached();
307 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
310 const gchar *proto_abbrev;
314 if (cfile.finfo_selected) {
315 /* convert selected field to protocol abbreviation */
316 /* XXX - could this conversion be simplified? */
317 field_id = cfile.finfo_selected->hfinfo->id;
318 /* if the selected field isn't a protocol, get it's parent */
319 if(!proto_registrar_is_protocol(field_id)) {
320 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
323 proto_abbrev = proto_registrar_get_abbrev(field_id);
325 /* ask the user if the wiki page really should be opened */
326 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
327 PRIMARY_TEXT_START "Open Ethereal Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
329 "This will open the \"%s\" related Ethereal Wiki page in your Web browser.\n"
331 "The Ethereal Wiki is a collaborative approach to provide information\n"
332 "about Ethereal in several ways (not limited to protocol specifics).\n"
334 "This Wiki is new, so the page of the selected protocol\n"
335 "may not exist and/or may not contain valuable information.\n"
337 "As everyone can edit the Wiki and add new content (or extend existing),\n"
338 "you are encouraged to add information if you can.\n"
340 "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
342 "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
343 "which will save you a lot of editing and will give a consistent look over the pages.",
344 proto_abbrev, proto_abbrev);
345 simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, (gpointer) proto_abbrev);
351 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
354 const gchar *proto_abbrev;
355 gchar *selected_proto_url;
358 if (cfile.finfo_selected) {
359 /* convert selected field to protocol abbreviation */
360 /* XXX - could this conversion be simplified? */
361 field_id = cfile.finfo_selected->hfinfo->id;
362 /* if the selected field isn't a protocol, get it's parent */
363 if(!proto_registrar_is_protocol(field_id)) {
364 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
367 proto_abbrev = proto_registrar_get_abbrev(field_id);
369 /* open reference page using the protocol abbreviation */
370 selected_proto_url = g_strdup_printf("http://www.ethereal.com/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
371 browser_open_url(selected_proto_url);
372 g_free(selected_proto_url);
378 get_text_from_packet_list(gpointer data)
380 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
381 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
382 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
390 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
391 cfile.pd, fdata->cap_len, &err, &err_info)) {
392 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
393 cf_read_error_message(err, err_info), cfile.filename);
397 edt = epan_dissect_new(FALSE, FALSE);
398 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
400 epan_dissect_fill_in_columns(edt);
402 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
403 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
404 len = strlen(cfile.cinfo.col_expr[column]) +
405 strlen(cfile.cinfo.col_expr_val[column]) + 5;
406 buf = ep_alloc0(len);
407 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
408 cfile.cinfo.col_expr_val[column]);
411 epan_dissect_free(edt);
418 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
420 match_selected_cb_do(data,
422 get_text_from_packet_list(data));
427 /* XXX: use a preference for this setting! */
428 static guint dfilter_combo_max_recent = 10;
430 /* add a display filter to the combo box */
431 /* Note: a new filter string will replace an old identical one */
433 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
435 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
438 /* GtkCombos don't let us get at their list contents easily, so we maintain
439 our own filter list, and feed it to gtk_combo_set_popdown_strings when
440 a new filter is added. */
441 li = g_list_first(dfilter_list);
443 /* If the filter is already in the list, remove the old one and
444 * append the new one at the latest position (at g_list_append() below) */
445 if (li->data && strcmp(s, li->data) == 0) {
446 dfilter_list = g_list_remove(dfilter_list, li->data);
452 dfilter_list = g_list_append(dfilter_list, s);
453 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
454 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), dfilter_list);
455 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(dfilter_list)->data);
461 /* write all non empty display filters (until maximum count)
462 * of the combo box GList to the user's recent file */
464 dfilter_recent_combo_write_all(FILE *rf) {
465 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
466 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
471 /* write all non empty display filter strings to the recent file (until max count) */
472 li = g_list_first(dfilter_list);
473 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
474 if (strlen(li->data)) {
475 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
481 /* empty the combobox entry field */
483 dfilter_combo_add_empty(void) {
484 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
486 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
490 /* add a display filter coming from the user's recent file to the dfilter combo box */
492 dfilter_combo_add_recent(gchar *s) {
493 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
497 if (!dfilter_combo_add(filter_cm, dup)) {
506 /* call cf_filter_packets() and add this filter string to the recent filter list */
508 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
510 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
511 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
513 gboolean add_filter = TRUE;
514 gboolean free_filter = TRUE;
516 cf_status_t cf_status;
518 /* we'll crash later on if dftext is NULL */
519 g_assert(dftext != NULL);
521 s = g_strdup(dftext);
523 /* GtkCombos don't let us get at their list contents easily, so we maintain
524 our own filter list, and feed it to gtk_combo_set_popdown_strings when
525 a new filter is added. */
526 cf_status = cf_filter_packets(cf, s, force);
527 if (cf_status == CF_OK) {
528 li = g_list_first(dfilter_list);
530 if (li->data && strcmp(s, li->data) == 0)
536 /* trim list size first */
537 while (g_list_length(dfilter_list) >= dfilter_combo_max_recent) {
538 dfilter_list = g_list_remove(dfilter_list, g_list_first(dfilter_list)->data);
542 dfilter_list = g_list_append(dfilter_list, s);
543 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
544 gtk_combo_set_popdown_strings(filter_cm, dfilter_list);
545 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(dfilter_list)->data);
551 return (cf_status == CF_OK);
555 /* Run the current display filter on the current packet set, and
558 filter_activate_cb(GtkWidget *w _U_, gpointer data)
562 s = gtk_entry_get_text(GTK_ENTRY(data));
564 main_filter_packets(&cfile, s, FALSE);
567 /* redisplay with no display filter */
569 filter_reset_cb(GtkWidget *w, gpointer data _U_)
571 GtkWidget *filter_te = NULL;
573 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
574 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
576 main_filter_packets(&cfile, "", FALSE);
579 /* mark as reference time frame */
581 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
585 frame->flags.ref_time=1;
587 frame->flags.ref_time=0;
589 cf_reftime_packets(&cfile);
593 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
598 if (cfile.current_frame) {
599 /* XXX hum, should better have a "cfile->current_row" here ... */
600 set_frame_reftime(!cfile.current_frame->flags.ref_time,
602 packet_list_find_row_from_data(cfile.current_frame));
605 case REFTIME_FIND_NEXT:
606 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
608 case REFTIME_FIND_PREV:
609 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
614 #if GTK_MAJOR_VERSION < 2
616 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
617 gpointer user_data _U_)
620 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
624 gchar *help_str = NULL;
625 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
627 gboolean has_blurb = FALSE;
628 guint length = 0, byte_len;
629 GtkWidget *byte_view;
630 const guint8 *byte_data;
631 #if GTK_MAJOR_VERSION >= 2
636 #if GTK_MAJOR_VERSION >= 2
637 /* if nothing is selected */
638 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
641 * Which byte view is displaying the current protocol tree
644 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
645 if (byte_view == NULL)
648 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
649 if (byte_data == NULL)
652 cf_unselect_field(&cfile);
653 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
654 cfile.current_frame, NULL, byte_len);
657 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
660 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
664 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
666 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
667 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
668 g_assert(byte_data != NULL);
670 cfile.finfo_selected = finfo;
671 set_menus_for_selected_tree_row(&cfile);
674 if (finfo->hfinfo->blurb != NULL &&
675 finfo->hfinfo->blurb[0] != '\0') {
677 length = strlen(finfo->hfinfo->blurb);
679 length = strlen(finfo->hfinfo->name);
681 if (finfo->length == 0) {
683 } else if (finfo->length == 1) {
684 strcpy (len_str, ", 1 byte");
686 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
688 statusbar_pop_field_msg(); /* get rid of current help msg */
690 help_str = g_strdup_printf("%s (%s)%s",
691 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
692 finfo->hfinfo->abbrev, len_str);
693 statusbar_push_field_msg(help_str);
697 * Don't show anything if the field name is zero-length;
698 * the pseudo-field for "proto_tree_add_text()" is such
699 * a field, and we don't want "Text (text)" showing up
700 * on the status line if you've selected such a field.
702 * XXX - there are zero-length fields for which we *do*
703 * want to show the field name.
705 * XXX - perhaps the name and abbrev field should be null
706 * pointers rather than null strings for that pseudo-field,
707 * but we'd have to add checks for null pointers in some
708 * places if we did that.
710 * Or perhaps protocol tree items added with
711 * "proto_tree_add_text()" should have -1 as the field index,
712 * with no pseudo-field being used, but that might also
713 * require special checks for -1 to be added.
715 statusbar_push_field_msg("");
719 #if GTK_MAJOR_VERSION < 2
720 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
723 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
728 #if GTK_MAJOR_VERSION < 2
730 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
731 gpointer user_data _U_)
733 GtkWidget *byte_view;
738 * Which byte view is displaying the current protocol tree
741 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
742 if (byte_view == NULL)
745 data = get_byte_view_data_and_length(byte_view, &len);
749 cf_unselect_field(&cfile);
750 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
755 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
757 collapse_all_tree(cfile.edt->tree, tree_view);
760 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
762 expand_all_tree(cfile.edt->tree, tree_view);
765 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
766 #if GTK_MAJOR_VERSION < 2
772 #if GTK_MAJOR_VERSION < 2
773 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
775 /* the mouse position is at an entry, expand that one */
776 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
779 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
781 /* the mouse position is at an entry, expand that one */
782 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
783 gtk_tree_path_free(path);
788 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
789 if (cfile.edt->tree) {
790 guint32 tmp = g_resolv_flags;
791 g_resolv_flags = RESOLV_ALL;
792 proto_tree_draw(cfile.edt->tree, tree_view);
793 g_resolv_flags = tmp;
798 * Push a message referring to file access onto the statusbar.
801 statusbar_push_file_msg(gchar *msg)
803 /*g_warning("statusbar_push: %s", msg);*/
804 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
808 * Pop a message referring to file access off the statusbar.
811 statusbar_pop_file_msg(void)
813 /*g_warning("statusbar_pop");*/
814 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
818 * XXX - do we need multiple statusbar contexts?
822 * Push a message referring to the currently-selected field onto the statusbar.
825 statusbar_push_field_msg(gchar *msg)
827 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
831 * Pop a message referring to the currently-selected field off the statusbar.
834 statusbar_pop_field_msg(void)
836 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
840 * update the packets statusbar to the current values
842 void packets_bar_update(void)
846 /* remove old status */
849 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
852 /* do we have any packets? */
854 if(cfile.drops_known) {
855 packets_str = g_strdup_printf(" P: %u D: %u M: %u Drops: %u",
856 cfile.count, cfile.displayed_count, cfile.marked_count, cfile.drops);
858 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
859 cfile.count, cfile.displayed_count, cfile.marked_count);
862 packets_str = g_strdup(" No Packets");
864 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
869 main_set_for_capture_file(gboolean have_capture_file_in)
871 have_capture_file = have_capture_file_in;
873 main_widgets_show_or_hide();
879 /* get the current geometry, before writing it to disk */
880 main_save_window_geometry(top_level);
882 /* write user's recent file to disk
883 * It is no problem to write this file, even if we do not quit */
886 /* XXX - should we check whether the capture file is an
887 unsaved temporary file for a live capture and, if so,
888 pop up a "do you want to exit without saving the capture
889 file?" dialog, and then just return, leaving said dialog
890 box to forcibly quit if the user clicks "OK"?
892 If so, note that this should be done in a subroutine that
893 returns TRUE if we do so, and FALSE otherwise, and if it
894 returns TRUE we should return TRUE without nuking anything.
896 Note that, if we do that, we might also want to check if
897 an "Update list of packets in real time" capture is in
898 progress and, if so, ask whether they want to terminate
899 the capture and discard it, and return TRUE, before nuking
900 any child capture, if they say they don't want to do so. */
903 /* Nuke any child capture in progress. */
904 capture_kill_child(capture_opts);
907 /* Are we in the middle of reading a capture? */
908 if (cfile.state == FILE_READ_IN_PROGRESS) {
909 /* Yes, so we can't just close the file and quit, as
910 that may yank the rug out from under the read in
911 progress; instead, just set the state to
912 "FILE_READ_ABORTED" and return - the code doing the read
913 will check for that and, if it sees that, will clean
915 cfile.state = FILE_READ_ABORTED;
917 /* Say that the window should *not* be deleted;
918 that'll be done by the code that cleans up. */
921 /* Close any capture file we have open; on some OSes, you
922 can't unlink a temporary capture file if you have it
924 "cf_close()" will unlink it after closing it if
925 it's a temporary file.
927 We do this here, rather than after the main loop returns,
928 as, after the main loop returns, the main window may have
929 been destroyed (if this is called due to a "destroy"
930 even on the main window rather than due to the user
931 selecting a menu item), and there may be a crash
932 or other problem when "cf_close()" tries to
933 clean up stuff in the main window.
935 XXX - is there a better place to put this?
936 Or should we have a routine that *just* closes the
937 capture file, and doesn't do anything with the UI,
938 which we'd call here, and another routine that
939 calls that routine and also cleans up the UI, which
940 we'd call elsewhere? */
943 /* Exit by leaving the main loop, so that any quit functions
944 we registered get called. */
947 /* Say that the window should be deleted. */
953 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
957 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
958 #if GTK_MAJOR_VERSION >= 2
959 gtk_window_present(GTK_WINDOW(top_level));
961 /* user didn't saved his current file, ask him */
962 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
963 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
964 "If you quit the program without saving, your capture data will be discarded.");
965 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
968 /* unchanged file, just exit */
969 /* "main_do_quit()" indicates whether the main window should be deleted. */
970 return main_do_quit();
977 main_load_window_geometry(GtkWidget *widget)
979 window_geometry_t geom;
981 geom.set_pos = prefs.gui_geometry_save_position;
982 geom.x = recent.gui_geometry_main_x;
983 geom.y = recent.gui_geometry_main_y;
984 geom.set_size = prefs.gui_geometry_save_size;
985 if (recent.gui_geometry_main_width > 0 &&
986 recent.gui_geometry_main_height > 0) {
987 geom.width = recent.gui_geometry_main_width;
988 geom.height = recent.gui_geometry_main_height;
989 geom.set_maximized = prefs.gui_geometry_save_maximized;
991 /* We assume this means the width and height weren't set in
992 the "recent" file (or that there is no "recent" file),
993 and weren't set to a default value, so we don't set the
994 size. (The "recent" file code rejects non-positive width
995 and height values.) */
996 geom.set_size = FALSE;
998 geom.maximized = recent.gui_geometry_main_maximized;
1000 window_set_geometry(widget, &geom);
1002 if (recent.has_gui_geometry_main_upper_pane && recent.gui_geometry_main_upper_pane)
1003 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
1004 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_main_lower_pane)
1005 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
1006 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_status_pane)
1007 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
1012 main_save_window_geometry(GtkWidget *widget)
1014 window_geometry_t geom;
1016 window_get_geometry(widget, &geom);
1018 if (prefs.gui_geometry_save_position) {
1019 recent.gui_geometry_main_x = geom.x;
1020 recent.gui_geometry_main_y = geom.y;
1023 if (prefs.gui_geometry_save_size) {
1024 recent.gui_geometry_main_width = geom.width,
1025 recent.gui_geometry_main_height = geom.height;
1028 #if GTK_MAJOR_VERSION >= 2
1029 if(prefs.gui_geometry_save_maximized) {
1030 recent.gui_geometry_main_maximized = geom.maximized;
1033 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
1034 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
1035 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
1039 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1043 /* save file first */
1044 file_save_as_cmd(after_save_exit, NULL);
1046 case(ESD_BTN_DONT_SAVE):
1049 case(ESD_BTN_CANCEL):
1052 g_assert_not_reached();
1057 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1061 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1062 /* user didn't saved his current file, ask him */
1063 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1064 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1065 "If you quit the program without saving, your capture data will be discarded.");
1066 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1068 /* unchanged file, just exit */
1074 print_usage(gboolean print_ver) {
1084 fprintf(output, "This is "PACKAGE " " VERSION "%s"
1085 "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
1087 svnversion, comp_info_str->str, runtime_info_str->str);
1092 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);
1093 fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
1094 fprintf(output, "\t[ -B capture buffer size (Win32 only) ]\n");
1095 fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
1096 fprintf(output, "\t[ -g <packet number> ]\n");
1097 fprintf(output, "\t[ -i <capture interface> ] [ -m <font> ] [ -N <name resolving flags> ]\n");
1098 fprintf(output, "\t[ -o <preference/recent setting> ] ...\n");
1099 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
1100 fprintf(output, "\t[ -t <time stamp format> ]\n");
1101 fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
1102 fprintf(output, "\t[ <infile> ]\n");
1104 fprintf(output, "\n%s [ -vh ] [ -n ] [ -g <packet number> ] [ -m <font> ]\n", PACKAGE);
1105 fprintf(output, "\t[ -N <resolving flags> ] [ -o <preference/recent setting> ...\n");
1106 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ]\n");
1107 fprintf(output, "\t[ -t <time stamp format> ]\n");
1108 fprintf(output, "\t[ -z <statistics ] [ <infile> ]\n");
1123 printf(PACKAGE " " VERSION "%s\n\n%s\n\n%s\n",
1124 svnversion, comp_info_str->str, runtime_info_str->str);
1131 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1133 Once every 3 seconds we get a callback here which we use to update
1134 the tap extensions. Since Gtk1 is single threaded we dont have to
1135 worry about any locking or critical regions.
1138 update_cb(gpointer data _U_)
1140 draw_tap_listeners(FALSE);
1145 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1146 use threads all updte_thread_mutex can be dropped and protect/unprotect
1147 would just be empty functions.
1149 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1150 gtk1-ethereal and it will just work.
1152 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1154 update_thread(gpointer data _U_)
1158 g_get_current_time(&tv1);
1159 g_static_mutex_lock(&update_thread_mutex);
1160 gdk_threads_enter();
1161 draw_tap_listeners(FALSE);
1162 gdk_threads_leave();
1163 g_static_mutex_unlock(&update_thread_mutex);
1165 g_get_current_time(&tv2);
1166 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1167 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1168 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1169 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1176 protect_thread_critical_region(void)
1178 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1179 g_static_mutex_lock(&update_thread_mutex);
1183 unprotect_thread_critical_region(void)
1185 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1186 g_static_mutex_unlock(&update_thread_mutex);
1190 /* Set the file name in the status line, in the name for the main window,
1191 and in the name for the main window's icon. */
1193 set_display_filename(capture_file *cf)
1195 const gchar *name_ptr;
1200 name_ptr = cf_get_display_name(cf);
1202 if (!cf->is_tempfile && cf->filename) {
1203 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1204 add_menu_recent_capture_file(cf->filename);
1207 /* convert file size */
1208 if (cf->f_datalen/1024/1024 > 10) {
1209 size_str = g_strdup_printf("%ld MB", cf->f_datalen/1024/1024);
1210 } else if (cf->f_datalen/1024 > 10) {
1211 size_str = g_strdup_printf("%ld KB", cf->f_datalen/1024);
1213 size_str = g_strdup_printf("%ld Bytes", cf->f_datalen);
1217 status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu",
1218 (cf->filename) ? cf->filename : "", size_str,
1219 (long)cf->elapsed_time.secs/3600,
1220 (long)cf->elapsed_time.secs%3600/60,
1221 (long)cf->elapsed_time.secs%60);
1223 statusbar_push_file_msg(status_msg);
1227 win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1228 set_main_window_name(win_name);
1232 GtkWidget *close_dlg = NULL;
1235 main_cf_cb_file_closing(capture_file *cf)
1238 /* if we have more than 10000 packets, show a splash screen while closing */
1239 /* XXX - don't know a better way to decide wether to show or not,
1240 * as most of the time is spend in a single eth_clist_clear function,
1241 * so we can't use a progress bar here! */
1242 if(cf->count > 10000) {
1243 close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sClosing file!%s\n\nPlease wait ...",
1244 simple_dialog_primary_start(), simple_dialog_primary_end());
1245 #if GTK_MAJOR_VERSION >= 2
1246 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1248 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
1252 /* Destroy all windows, which refer to the
1253 capture file we're closing. */
1254 destroy_cfile_wins();
1256 /* Clear any file-related status bar messages.
1257 XXX - should be "clear *ALL* file-related status bar messages;
1258 will there ever be more than one on the stack? */
1259 statusbar_pop_file_msg();
1261 /* go back to "No packets" */
1262 packets_bar_update();
1264 /* Restore the standard title bar message. */
1265 set_main_window_name("The Ethereal Network Analyzer");
1267 /* Disable all menu items that make sense only if you have a capture. */
1268 set_menus_for_capture_file(FALSE);
1269 set_menus_for_unsaved_capture_file(FALSE);
1270 set_menus_for_captured_packets(FALSE);
1271 set_menus_for_selected_packet(cf);
1272 set_menus_for_capture_in_progress(FALSE);
1273 set_menus_for_selected_tree_row(cf);
1275 /* Set up main window for no capture file. */
1276 main_set_for_capture_file(FALSE);
1278 main_window_update();
1282 main_cf_cb_file_closed(capture_file *cf _U_)
1284 if(close_dlg != NULL) {
1285 splash_destroy(close_dlg);
1291 main_cf_cb_file_read_start(capture_file *cf)
1293 const gchar *name_ptr;
1296 name_ptr = get_basename(cf->filename);
1298 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1299 statusbar_push_file_msg(load_msg);
1304 main_cf_cb_file_read_finished(capture_file *cf)
1306 statusbar_pop_file_msg();
1307 set_display_filename(cf);
1309 /* Enable menu items that make sense if you have a capture file you've
1310 finished reading. */
1311 set_menus_for_capture_file(TRUE);
1312 set_menus_for_unsaved_capture_file(!cf->user_saved);
1314 /* Enable menu items that make sense if you have some captured packets. */
1315 set_menus_for_captured_packets(TRUE);
1317 /* Set up main window for a capture file. */
1318 main_set_for_capture_file(TRUE);
1323 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1328 if(capture_opts->iface) {
1329 title = g_strdup_printf("%s: Capturing - Ethereal",
1330 get_interface_descriptive_name(capture_opts->iface));
1332 title = g_strdup_printf("Capturing - Ethereal");
1334 set_main_window_name(title);
1337 /* Disable menu items that make no sense if you're currently running
1339 set_menus_for_capture_in_progress(TRUE);
1341 /* update statusbar */
1342 statusbar_push_file_msg("Waiting for capture input data ...");
1344 /* Don't set up main window for a capture file. */
1345 main_set_for_capture_file(FALSE);
1349 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1354 /* Enable menu items that make sense if you have some captured
1355 packets (yes, I know, we don't have any *yet*). */
1356 set_menus_for_captured_packets(TRUE);
1358 statusbar_pop_file_msg();
1360 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1361 get_interface_descriptive_name(capture_opts->iface),
1362 (capture_opts->save_file) ? capture_opts->save_file : "");
1364 statusbar_push_file_msg(capture_msg);
1366 g_free(capture_msg);
1368 /* Set up main window for a capture file. */
1369 main_set_for_capture_file(TRUE);
1373 main_cf_cb_live_capture_update_continue(capture_file *cf)
1378 statusbar_pop_file_msg();
1380 if (cf->f_datalen/1024/1024 > 10) {
1381 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB",
1382 get_interface_descriptive_name(capture_opts->iface),
1383 capture_opts->save_file,
1384 cf->f_datalen/1024/1024);
1385 } else if (cf->f_datalen/1024 > 10) {
1386 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB",
1387 get_interface_descriptive_name(capture_opts->iface),
1388 capture_opts->save_file,
1389 cf->f_datalen/1024);
1391 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes",
1392 get_interface_descriptive_name(capture_opts->iface),
1393 capture_opts->save_file,
1397 statusbar_push_file_msg(capture_msg);
1400 GtkWidget * stop_dlg = NULL;
1403 main_cf_cb_live_capture_update_finished(capture_file *cf)
1405 if(stop_dlg != NULL) {
1406 simple_dialog_close(stop_dlg);
1410 /* Pop the "<live capture in progress>" message off the status bar. */
1411 statusbar_pop_file_msg();
1413 set_display_filename(cf);
1415 /* Enable menu items that make sense if you're not currently running
1417 set_menus_for_capture_in_progress(FALSE);
1419 /* Enable menu items that make sense if you have a capture file
1420 you've finished reading. */
1421 set_menus_for_capture_file(TRUE);
1422 set_menus_for_unsaved_capture_file(!cf->user_saved);
1424 /* Set up main window for a capture file. */
1425 main_set_for_capture_file(TRUE);
1429 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1434 /* Enable menu items that make sense if you have some captured
1435 packets (yes, I know, we don't have any *yet*). */
1436 /*set_menus_for_captured_packets(TRUE);*/
1438 statusbar_pop_file_msg();
1440 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1441 get_interface_descriptive_name(capture_opts->iface),
1442 (capture_opts->save_file) ? capture_opts->save_file : "");
1444 statusbar_push_file_msg(capture_msg);
1445 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " <capturing>");
1447 g_free(capture_msg);
1449 /* Don't set up main window for a capture file. */
1450 main_set_for_capture_file(FALSE);
1454 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1456 if(stop_dlg != NULL) {
1457 simple_dialog_close(stop_dlg);
1461 /* Pop the "<live capture in progress>" message off the status bar. */
1462 statusbar_pop_file_msg();
1464 /* Pop the "<capturing>" message off the status bar */
1465 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1467 /*set_display_filename(cf);*/
1469 /* Enable menu items that make sense if you're not currently running
1471 set_menus_for_capture_in_progress(FALSE);
1473 /* We don't have loaded the capture file, this will be done later.
1474 * For now we still have simply a blank screen. */
1478 main_cf_cb_live_capture_stopping(capture_file *cf _U_)
1480 stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...",
1481 simple_dialog_primary_start(), simple_dialog_primary_end());
1482 #if GTK_MAJOR_VERSION >= 2
1483 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1485 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1492 main_cf_cb_packet_selected(gpointer data)
1494 capture_file *cf = data;
1496 /* Display the GUI protocol tree and hex dump.
1497 XXX - why do we dump core if we call "proto_tree_draw()"
1498 before calling "add_byte_views()"? */
1499 add_main_byte_views(cf->edt);
1500 main_proto_tree_draw(cf->edt->tree);
1502 /* A packet is selected. */
1503 set_menus_for_selected_packet(cf);
1507 main_cf_cb_packet_unselected(capture_file *cf)
1509 /* Clear out the display of that packet. */
1510 clear_tree_and_hex_views();
1512 /* No packet is selected. */
1513 set_menus_for_selected_packet(cf);
1517 main_cf_cb_field_unselected(capture_file *cf)
1519 statusbar_pop_field_msg();
1520 set_menus_for_selected_tree_row(cf);
1524 main_cf_cb_file_safe_started(gchar * filename)
1526 const gchar *name_ptr;
1529 name_ptr = get_basename(filename);
1531 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1533 statusbar_push_file_msg(save_msg);
1538 main_cf_cb_file_safe_finished(gpointer data _U_)
1540 /* Pop the "Saving:" message off the status bar. */
1541 statusbar_pop_file_msg();
1545 main_cf_cb_file_safe_failed(gpointer data _U_)
1547 /* Pop the "Saving:" message off the status bar. */
1548 statusbar_pop_file_msg();
1552 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1554 set_menus_for_unsaved_capture_file(FALSE);
1557 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1560 case(cf_cb_file_closing):
1561 main_cf_cb_file_closing(data);
1563 case(cf_cb_file_closed):
1564 main_cf_cb_file_closed(data);
1566 case(cf_cb_file_read_start):
1567 main_cf_cb_file_read_start(data);
1569 case(cf_cb_file_read_finished):
1570 main_cf_cb_file_read_finished(data);
1573 case(cf_cb_live_capture_prepared):
1574 main_cf_cb_live_capture_prepared(data);
1576 case(cf_cb_live_capture_update_started):
1577 main_cf_cb_live_capture_update_started(data);
1579 case(cf_cb_live_capture_update_continue):
1580 main_cf_cb_live_capture_update_continue(data);
1582 case(cf_cb_live_capture_fixed_started):
1583 main_cf_cb_live_capture_fixed_started(data);
1585 case(cf_cb_live_capture_update_finished):
1586 main_cf_cb_live_capture_update_finished(data);
1588 case(cf_cb_live_capture_fixed_finished):
1589 main_cf_cb_live_capture_fixed_finished(data);
1591 case(cf_cb_live_capture_stopping):
1592 main_cf_cb_live_capture_stopping(data);
1595 case(cf_cb_packet_selected):
1596 main_cf_cb_packet_selected(data);
1598 case(cf_cb_packet_unselected):
1599 main_cf_cb_packet_unselected(data);
1601 case(cf_cb_field_unselected):
1602 main_cf_cb_field_unselected(data);
1604 case(cf_cb_file_safe_started):
1605 main_cf_cb_file_safe_started(data);
1607 case(cf_cb_file_safe_finished):
1608 main_cf_cb_file_safe_finished(data);
1610 case(cf_cb_file_safe_reload_finished):
1611 main_cf_cb_file_safe_reload_finished(data);
1613 case(cf_cb_file_safe_failed):
1614 main_cf_cb_file_safe_failed(data);
1617 g_warning("main_cf_callback: event %u unknown", event);
1618 g_assert_not_reached();
1622 /* And now our feature presentation... [ fade to music ] */
1624 main(int argc, char *argv[])
1627 const char *command_name;
1632 extern char *optarg;
1633 gboolean arg_error = FALSE;
1641 char *gpf_path, *pf_path;
1642 char *cf_path, *df_path;
1643 char *gdp_path, *dp_path;
1644 int gpf_open_errno, gpf_read_errno;
1645 int pf_open_errno, pf_read_errno;
1646 int cf_open_errno, df_open_errno;
1647 int gdp_open_errno, gdp_read_errno;
1648 int dp_open_errno, dp_read_errno;
1651 gboolean start_capture = FALSE;
1654 GList *lt_list, *lt_entry;
1655 data_link_info_t *data_link_info;
1656 gchar err_str[PCAP_ERRBUF_SIZE];
1657 gchar *cant_get_if_list_errstr;
1658 gboolean stats_known;
1659 struct pcap_stat stats;
1661 gboolean capture_option_specified = FALSE;
1663 gint pl_size = 280, tv_size = 95, bv_size = 75;
1664 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1665 dfilter_t *rfcode = NULL;
1666 gboolean rfilter_parse_failed = FALSE;
1669 GtkWidget *splash_win = NULL;
1670 GLogLevelFlags log_flags;
1671 guint go_to_packet = 0;
1674 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1678 #define OPTSTRING_CHILD "W:Z:"
1679 #define OPTSTRING_WIN32 "B:"
1681 #define OPTSTRING_CHILD "W:"
1682 #define OPTSTRING_WIN32 ""
1685 #define OPTSTRING_CHILD ""
1686 #define OPTSTRING_WIN32 ""
1687 #endif /* HAVE_LIBPCAP */
1689 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1690 OPTSTRING_INIT OPTSTRING_WIN32;
1692 /* initialize memory allocation subsystem */
1696 /*** create the compile and runtime version strings ***/
1698 /* Load wpcap if possible. Do this before collecting the run-time version information */
1701 /* ... and also load the packet.dll from wpcap */
1702 wpcap_packet_load();
1704 /* Start windows sockets */
1705 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1708 /* Assemble the compile-time version information string */
1709 comp_info_str = g_string_new("Compiled ");
1710 g_string_append(comp_info_str, "with ");
1711 g_string_sprintfa(comp_info_str,
1712 #ifdef GTK_MAJOR_VERSION
1713 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1716 "GTK+ (version unknown)");
1719 g_string_append(comp_info_str, ", ");
1720 get_compiled_version_info(comp_info_str);
1722 /* Assemble the run-time version information string */
1723 runtime_info_str = g_string_new("Running ");
1724 get_runtime_version_info(runtime_info_str);
1727 /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1728 /* (e.g. don't start GTK+, if we only have to show the command line help) */
1729 optind_initial = optind;
1730 while ((opt = getopt(argc, argv, optstring)) != -1) {
1732 case 'h': /* Print help and exit */
1736 case 'v': /* Show version and exit */
1740 case 'G': /* dump various field or other infos, see handle_dashG_option() */
1741 /* If invoked with the "-G" flag, we dump out information based on
1742 the argument to the "-G" flag; if no argument is specified,
1743 for backwards compatibility we dump out a glossary of display
1746 We must do this before calling "gtk_init()", because "gtk_init()"
1747 tries to open an X display, and we don't want to have to do any X
1748 stuff just to do a build.
1750 Given that we call "gtk_init()" before doing the regular argument
1751 list processing, so that it can handle X and GTK+ arguments and
1752 remove them from the list at which we look, this means we must do
1753 this before doing the regular argument list processing, as well.
1757 you must give the "-G" flag as the first flag on the command line;
1759 you must give it as "-G", nothing more, nothing less;
1761 the first argument after the "-G" flag, if present, will be used
1762 to specify the information to dump;
1764 arguments after that will not be used. */
1765 handle_dashG_option(argc, argv, "ethereal");
1766 /* will never return! */
1772 /* set getopt index back to initial value, so it will start with the first command line parameter again */
1773 /* (XXX - this seems to be portable, but time will tell) */
1774 optind = optind_initial;
1777 /* Set the current locale according to the program environment.
1778 * We haven't localized anything, but some GTK widgets are localized
1779 * (the file selection dialogue, for example).
1780 * This also sets the C-language locale to the native environment. */
1783 /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1784 gtk_init (&argc, &argv);
1786 cf_callback_add(main_cf_callback, NULL);
1788 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1789 /* initialize our GTK eth_clist_type */
1790 init_eth_clist_type();
1793 ethereal_path = argv[0];
1795 /* Arrange that if we have no console window, and a GLib message logging
1796 routine is called to log a message, we pop up a console window.
1798 We do that by inserting our own handler for all messages logged
1799 to the default domain; that handler pops up a console if necessary,
1800 and then calls the default handler. */
1802 /* We might want to have component specific log levels later ... */
1804 /* the default_log_handler will use stdout, which makes trouble with the */
1805 /* capture child, as it uses stdout for it's sync_pipe */
1806 /* so do the filtering in the console_log_handler and not here */
1809 G_LOG_LEVEL_CRITICAL|
1810 G_LOG_LEVEL_WARNING|
1811 G_LOG_LEVEL_MESSAGE|
1814 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1816 g_log_set_handler(NULL,
1818 console_log_handler, NULL /* user_data */);
1821 g_log_set_handler(LOG_DOMAIN_CAPTURE,
1823 console_log_handler, NULL /* user_data */);
1824 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1826 console_log_handler, NULL /* user_data */);
1828 /* Set the initial values in the capture_opts. This might be overwritten
1829 by preference settings and then again by the command line parameters. */
1830 capture_opts_init(capture_opts, &cfile);
1832 capture_opts->snaplen = MIN_PACKET_SIZE;
1833 capture_opts->has_ring_num_files = TRUE;
1835 command_name = get_basename(ethereal_path);
1836 /* Set "capture_child" to indicate whether this is going to be a child
1837 process for a "-S" capture. */
1838 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1839 if (capture_child) {
1840 strcat(optstring, OPTSTRING_CHILD);
1844 /* We want a splash screen only if we're not a child process.
1845 We won't come till here, if we had a "console only" command line parameter. */
1849 splash_win = splash_new("Loading Ethereal ...");
1851 splash_update(splash_win, "Registering dissectors ...");
1853 /* Register all dissectors; we must do this before checking for the
1854 "-G" flag, as the "-G" flag dumps information registered by the
1855 dissectors, and we must do it before we read the preferences, in
1856 case any dissectors register preferences. */
1857 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1858 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1860 splash_update(splash_win, "Registering tap listeners ...");
1862 /* Register all tap listeners; we do this before we parse the arguments,
1863 as the "-z" argument can specify a registered tap. */
1865 /* we register the plugin taps before the other taps because
1866 stats_tree taps plugins will be registered as tap listeners
1867 by stats_tree_stat.c and need to registered before that */
1870 register_all_plugin_tap_listeners();
1873 register_all_tap_listeners();
1875 splash_update(splash_win, "Loading module preferences ...");
1877 /* Now register the preferences for any non-dissector modules.
1878 We must do that before we read the preferences as well. */
1879 prefs_register_modules();
1881 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1882 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1885 g_thread_init(NULL);
1887 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1888 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1890 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1891 /* this is to keep tap extensions updating once every 3 seconds */
1892 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1893 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1896 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1899 splash_update(splash_win, "Loading configuration files ...");
1901 /* Read the preference files. */
1902 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1903 &pf_open_errno, &pf_read_errno, &pf_path);
1904 if (gpf_path != NULL) {
1905 if (gpf_open_errno != 0) {
1906 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1907 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1908 strerror(gpf_open_errno));
1910 if (gpf_read_errno != 0) {
1911 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1912 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1913 strerror(gpf_read_errno));
1916 if (pf_path != NULL) {
1917 if (pf_open_errno != 0) {
1918 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1919 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1920 strerror(pf_open_errno));
1922 if (pf_read_errno != 0) {
1923 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1924 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1925 strerror(pf_read_errno));
1932 /* if the user wants a console to be always there, well, we should open one for him */
1933 if (prefs->gui_console_open == console_open_always) {
1939 /* If this is a capture child process, it should pay no attention
1940 to the "prefs.capture_prom_mode" setting in the preferences file;
1941 it should do what the parent process tells it to do, and if
1942 the parent process wants it not to run in promiscuous mode, it'll
1943 tell it so with a "-p" flag.
1945 Otherwise, set promiscuous mode from the preferences setting. */
1946 /* the same applies to other preferences settings as well. */
1947 if (capture_child) {
1948 auto_scroll_live = FALSE;
1950 capture_opts->promisc_mode = prefs->capture_prom_mode;
1951 capture_opts->show_info = prefs->capture_show_info;
1952 capture_opts->real_time_mode = prefs->capture_real_time;
1953 auto_scroll_live = prefs->capture_auto_scroll;
1956 #endif /* HAVE_LIBPCAP */
1958 /* Set the name resolution code's flags from the preferences. */
1959 g_resolv_flags = prefs->name_resolve;
1961 /* Read the capture filter file. */
1962 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1963 if (cf_path != NULL) {
1964 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1965 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1966 strerror(cf_open_errno));
1970 /* Read the display filter file. */
1971 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1972 if (df_path != NULL) {
1973 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1974 "Could not open your display filter file\n\"%s\": %s.", df_path,
1975 strerror(df_open_errno));
1979 /* Read the disabled protocols file. */
1980 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1981 &dp_path, &dp_open_errno, &dp_read_errno);
1982 if (gdp_path != NULL) {
1983 if (gdp_open_errno != 0) {
1984 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1985 "Could not open global disabled protocols file\n\"%s\": %s.",
1986 gdp_path, strerror(gdp_open_errno));
1988 if (gdp_read_errno != 0) {
1989 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1990 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1991 gdp_path, strerror(gdp_read_errno));
1995 if (dp_path != NULL) {
1996 if (dp_open_errno != 0) {
1997 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1998 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1999 strerror(dp_open_errno));
2001 if (dp_read_errno != 0) {
2002 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2003 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2004 strerror(dp_read_errno));
2009 /* Read the (static part) of the recent file. Only the static part of it will be read, */
2010 /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2011 /* We have to do this already here, so command line parameters can overwrite these values. */
2012 recent_read_static(&rf_path, &rf_open_errno);
2014 init_cap_file(&cfile);
2016 /* Now get our args */
2017 while ((opt = getopt(argc, argv, optstring)) != -1) {
2019 /*** capture option specific ***/
2020 case 'a': /* autostop criteria */
2021 case 'b': /* Ringbuffer option */
2022 case 'c': /* Capture xxx packets */
2023 case 'f': /* capture filter */
2024 case 'k': /* Start capture immediately */
2025 case 'H': /* Hide capture info dialog box */
2026 case 'i': /* Use interface xxx */
2027 case 'p': /* Don't capture in promiscuous mode */
2028 case 'Q': /* Quit after capture (just capture to file) */
2029 case 's': /* Set the snapshot (capture) length */
2030 case 'S': /* "Sync" mode: used for following file ala tail -f */
2031 case 'w': /* Write to capture file xxx */
2032 case 'y': /* Set the pcap data link type */
2034 case 'B': /* Buffer size */
2035 /* Hidden option supporting Sync mode */
2036 case 'Z': /* Write to pipe FD XXX */
2039 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2041 capture_option_specified = TRUE;
2046 /* This is a hidden option supporting Sync mode, so we don't set
2047 * the error flags for the user in the non-libpcap case.
2049 case 'W': /* Write to capture file FD xxx */
2050 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2054 /*** all non capture option specific ***/
2055 case 'g': /* Go to packet */
2056 go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2058 case 'l': /* Automatic scrolling in live capture mode */
2060 auto_scroll_live = TRUE;
2062 capture_option_specified = TRUE;
2066 case 'L': /* Print list of link-layer types and exit */
2068 list_link_layer_types = TRUE;
2070 capture_option_specified = TRUE;
2074 case 'm': /* Fixed-width font for the display */
2075 if (prefs->PREFS_GUI_FONT_NAME != NULL)
2076 g_free(prefs->PREFS_GUI_FONT_NAME);
2077 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2079 case 'n': /* No name resolution */
2080 g_resolv_flags = RESOLV_NONE;
2082 case 'N': /* Select what types of addresses/port #s to resolve */
2083 if (g_resolv_flags == RESOLV_ALL)
2084 g_resolv_flags = RESOLV_NONE;
2085 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2086 if (badopt != '\0') {
2087 g_warning("ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2092 case 'o': /* Override preference from command line */
2093 switch (prefs_set_pref(optarg)) {
2096 case PREFS_SET_SYNTAX_ERR:
2097 g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2100 case PREFS_SET_NO_SUCH_PREF:
2101 /* not a preference, might be a recent setting */
2102 switch (recent_set_arg(optarg)) {
2105 case PREFS_SET_SYNTAX_ERR:
2106 /* shouldn't happen, checked already above */
2107 g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2110 case PREFS_SET_NO_SUCH_PREF:
2111 case PREFS_SET_OBSOLETE:
2112 g_warning("ethereal: -o flag \"%s\" specifies unknown preference/recent value",
2117 g_assert_not_reached();
2120 case PREFS_SET_OBSOLETE:
2121 g_warning("ethereal: -o flag \"%s\" specifies obsolete preference",
2126 g_assert_not_reached();
2129 case 'r': /* Read capture file xxx */
2130 /* We may set "last_open_dir" to "cf_name", and if we change
2131 "last_open_dir" later, we free the old value, so we have to
2132 set "cf_name" to something that's been allocated. */
2133 cf_name = g_strdup(optarg);
2135 case 'R': /* Read file filter */
2138 case 't': /* Time stamp type */
2139 if (strcmp(optarg, "r") == 0)
2140 timestamp_set_type(TS_RELATIVE);
2141 else if (strcmp(optarg, "a") == 0)
2142 timestamp_set_type(TS_ABSOLUTE);
2143 else if (strcmp(optarg, "ad") == 0)
2144 timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2145 else if (strcmp(optarg, "d") == 0)
2146 timestamp_set_type(TS_DELTA);
2148 g_warning("ethereal: Invalid time stamp type \"%s\"",
2150 g_warning("It must be \"r\" for relative, \"a\" for absolute,");
2151 g_warning("\"ad\" for absolute with date, or \"d\" for delta.");
2156 /* We won't call the init function for the stat this soon
2157 as it would disallow MATE's fields (which are registered
2158 by the preferences set callback) from being used as
2159 part of a tap filter. Instead, we just add the argument
2160 to a list of stat arguments. */
2161 if (!process_stat_cmd_arg(optarg)) {
2162 g_warning("ethereal: invalid -z argument.");
2163 g_warning(" -z argument must be one of :");
2164 list_stat_cmd_args();
2169 case '?': /* Bad flag - print usage message */
2170 g_warning("Bad flag");
2178 if (cf_name != NULL) {
2180 * Input file name specified with "-r" *and* specified as a regular
2181 * command-line argument.
2183 g_warning("File name specified both with -r and regular argument");
2187 * Input file name not specified with "-r", and a command-line argument
2188 * was specified; treat it as the input file name.
2190 * Yes, this is different from tethereal, where non-flag command-line
2191 * arguments are a filter, but this works better on GUI desktops
2192 * where a command can be specified to be run to open a particular
2193 * file - yes, you could have "-r" as the last part of the command,
2194 * but that's a bit ugly.
2196 cf_name = g_strdup(argv[0]);
2206 * Extra command line arguments were specified; complain.
2208 g_warning("Invalid argument: %s", argv[0]);
2213 #ifndef HAVE_LIBPCAP
2214 if (capture_option_specified) {
2215 g_warning("This version of Ethereal was not built with support for capturing packets.");
2223 if (start_capture && list_link_layer_types) {
2224 /* Specifying *both* is bogus. */
2225 g_warning("ethereal: You can't specify both -L and a live capture.");
2229 if (list_link_layer_types) {
2230 /* We're supposed to list the link-layer types for an interface;
2231 did the user also specify a capture file to be read? */
2233 /* Yes - that's bogus. */
2234 g_warning("ethereal: You can't specify -L and a capture file to be read.");
2237 /* No - did they specify a ring buffer option? */
2238 if (capture_opts->multi_files_on) {
2239 g_warning("ethereal: Ring buffer requested, but a capture isn't being done.");
2243 /* We're supposed to do a live capture; did the user also specify
2244 a capture file to be read? */
2245 if (start_capture && cf_name) {
2246 /* Yes - that's bogus. */
2247 g_warning("ethereal: You can't specify both a live capture and a capture file to be read.");
2251 /* No - was the ring buffer option specified and, if so, does it make
2253 if (capture_opts->multi_files_on) {
2254 /* Ring buffer works only under certain conditions:
2255 a) ring buffer does not work with temporary files;
2256 b) real_time_mode and multi_files_on are mutually exclusive -
2257 real_time_mode takes precedence;
2258 c) it makes no sense to enable the ring buffer if the maximum
2259 file size is set to "infinite". */
2260 if (capture_opts->save_file == NULL) {
2261 g_warning("ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.");
2262 capture_opts->multi_files_on = FALSE;
2264 /* if (capture_opts->real_time_mode) {
2265 g_warning("ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2266 capture_opts->multi_files_on = FALSE;
2268 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2269 g_warning("ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.");
2270 /* XXX - this must be redesigned as the conditions changed */
2271 /* capture_opts->multi_files_on = FALSE;*/
2276 if (start_capture || list_link_layer_types) {
2277 /* Did the user specify an interface to use? */
2278 if (capture_opts->iface == NULL) {
2279 /* No - is a default specified in the preferences file? */
2280 if (prefs->capture_device != NULL) {
2282 capture_opts->iface = g_strdup(get_if_name(prefs->capture_device));
2284 /* No - pick the first one from the list of interfaces. */
2285 if_list = get_interface_list(&err, err_str);
2286 if (if_list == NULL) {
2289 case CANT_GET_INTERFACE_LIST:
2290 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2291 g_warning("%s", cant_get_if_list_errstr);
2292 g_free(cant_get_if_list_errstr);
2295 case NO_INTERFACES_FOUND:
2296 g_warning("ethereal: There are no interfaces on which a capture can be done");
2301 if_info = if_list->data; /* first interface */
2302 capture_opts->iface = g_strdup(if_info->name);
2303 free_interface_list(if_list);
2308 if (list_link_layer_types) {
2309 /* Get the list of link-layer types for the capture device. */
2310 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2311 if (lt_list == NULL) {
2312 if (err_str[0] != '\0') {
2313 g_warning("ethereal: The list of data link types for the capture device could not be obtained (%s)."
2314 "Please check to make sure you have sufficient permissions, and that\n"
2315 "you have the proper interface or pipe specified.\n", err_str);
2317 g_warning("ethereal: The capture device has no data link types.");
2320 g_warning("Data link types (use option -y to set):");
2321 for (lt_entry = lt_list; lt_entry != NULL;
2322 lt_entry = g_list_next(lt_entry)) {
2323 data_link_info = lt_entry->data;
2324 g_warning(" %s", data_link_info->name);
2325 if (data_link_info->description != NULL)
2326 g_warning(" (%s)", data_link_info->description);
2328 g_warning(" (not supported)");
2331 free_pcap_linktype_list(lt_list);
2335 if (capture_opts->has_snaplen) {
2336 if (capture_opts->snaplen < 1)
2337 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2338 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2339 capture_opts->snaplen = MIN_PACKET_SIZE;
2342 /* Check the value range of the ringbuffer_num_files parameter */
2343 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2344 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2345 #if RINGBUFFER_MIN_NUM_FILES > 0
2346 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2347 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2349 #endif /* HAVE_LIBPCAP */
2351 /* Notify all registered modules that have had any of their preferences
2352 changed either from one of the preferences file or from the command
2353 line that their preferences have changed. */
2356 /* disabled protocols as per configuration file */
2357 if (gdp_path == NULL && dp_path == NULL) {
2358 set_disabled_protos_list();
2361 /* Build the column format array */
2362 col_setup(&cfile.cinfo, prefs->num_cols);
2363 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2364 cfile.cinfo.col_fmt[i] = get_column_format(i);
2365 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2366 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2368 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2369 cfile.cinfo.col_data[i] = NULL;
2370 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2371 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2373 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2374 cfile.cinfo.col_fence[i] = 0;
2375 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2376 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2379 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2382 for (j = 0; j < NUM_COL_FMTS; j++) {
2383 if (!cfile.cinfo.fmt_matx[i][j])
2386 if (cfile.cinfo.col_first[j] == -1)
2387 cfile.cinfo.col_first[j] = i;
2388 cfile.cinfo.col_last[j] = i;
2392 /* read in rc file from global and personal configuration paths. */
2393 rc_file = get_datafile_path(RC_FILE);
2394 gtk_rc_parse(rc_file);
2395 rc_file = get_persconffile_path(RC_FILE, FALSE);
2396 gtk_rc_parse(rc_file);
2399 font_init(capture_child);
2404 /* close the splash screen, as we are going to open the main window now */
2405 splash_destroy(splash_win);
2409 /* Is this a "child" ethereal, which is only supposed to pop up a
2410 capture box to let us stop the capture, and run a capture
2411 to a file that our parent will read? */
2412 if (capture_child) {
2413 /* This is the child process of a capture session,
2414 so just do the low-level work of a capture - don't create
2415 a temporary file and fork off *another* child process (so don't
2416 call "capture_start()"). */
2418 /* Pop up any queued-up alert boxes. */
2419 display_queued_messages();
2421 /* Now start the capture.
2422 After the capture is done; there's nothing more for us to do. */
2424 /* XXX - hand these stats to the parent process */
2425 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2429 /* capture failed */
2435 /***********************************************************************/
2436 /* Everything is prepared now, preferences and command line was read in,
2437 we are NOT a child window for a synced capture. */
2439 /* Pop up the main window. */
2440 create_main_window(pl_size, tv_size, bv_size, prefs);
2442 /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2443 recent_read_dynamic(&rf_path, &rf_open_errno);
2444 color_filters_enable(recent.packet_list_colorize);
2446 /* rearrange all the widgets as we now have all recent settings ready for this */
2447 main_widgets_rearrange();
2449 /* Fill in column titles. This must be done after the top level window
2452 XXX - is that still true, with fixed-width columns? */
2453 packet_list_set_column_titles();
2455 menu_recent_read_finished();
2457 switch (user_font_apply()) {
2460 case FA_FONT_NOT_RESIZEABLE:
2461 /* "user_font_apply()" popped up an alert box. */
2462 /* turn off zooming - font can't be resized */
2463 case FA_FONT_NOT_AVAILABLE:
2464 /* XXX - did we successfully load the un-zoomed version earlier?
2465 If so, this *probably* means the font is available, but not at
2466 this particular zoom level, but perhaps some other failure
2467 occurred; I'm not sure you can determine which is the case,
2469 /* turn off zooming - zoom level is unavailable */
2471 /* in any other case than FA_SUCCESS, turn off zooming */
2472 recent.gui_zoom_level = 0;
2473 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2476 dnd_init(top_level);
2479 color_filters_init();
2482 /* the window can be sized only, if it's not already shown, so do it now! */
2483 main_load_window_geometry(top_level);
2485 /* If we were given the name of a capture file, read it in now;
2486 we defer it until now, so that, if we can't open it, and pop
2487 up an alert box, the alert box is more likely to come up on
2488 top of the main window - but before the preference-file-error
2489 alert box, so, if we get one of those, it's more likely to come
2492 show_main_window(TRUE);
2493 if (rfilter != NULL) {
2494 if (!dfilter_compile(rfilter, &rfcode)) {
2495 bad_dfilter_alert_box(rfilter);
2496 rfilter_parse_failed = TRUE;
2499 if (!rfilter_parse_failed) {
2500 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2501 /* "cf_open()" succeeded, so it closed the previous
2502 capture file, and thus destroyed any previous read filter
2503 attached to "cf". */
2505 cfile.rfcode = rfcode;
2506 /* Open stat windows; we do so after creating the main window,
2507 to avoid GTK warnings, and after successfully opening the
2508 capture file, so we know we have something to compute stats
2509 on, and after registering all dissectors, so that MATE will
2510 have registered its field array and we can have a tap filter
2511 with one of MATE's late-registered fields as part of the
2513 start_requested_stats();
2515 /* Read the capture file. */
2516 switch (cf_read(&cfile)) {
2520 /* Just because we got an error, that doesn't mean we were unable
2521 to read any of the file; we handle what we could get from the
2523 /* if the user told us to jump to a specific packet, do it now */
2524 if(go_to_packet != 0) {
2525 cf_goto_frame(&cfile, go_to_packet);
2529 case CF_READ_ABORTED:
2534 /* Save the name of the containing directory specified in the
2535 path name, if any; we can write over cf_name, which is a
2536 good thing, given that "get_dirname()" does write over its
2538 s = get_dirname(cf_name);
2539 /* we might already set this from the recent file, don't overwrite this */
2540 if(get_last_open_dir() == NULL)
2541 set_last_open_dir(s);
2546 dfilter_free(rfcode);
2547 cfile.rfcode = NULL;
2548 set_menus_for_capture_in_progress(FALSE);
2553 if (start_capture) {
2554 if (capture_opts->save_file != NULL) {
2555 /* Save the directory name for future file dialogs. */
2556 /* (get_dirname overwrites filename) */
2557 s = get_dirname(g_strdup(capture_opts->save_file));
2558 set_last_open_dir(s);
2561 /* "-k" was specified; start a capture. */
2562 show_main_window(TRUE);
2563 if (capture_start(capture_opts)) {
2564 /* The capture started. Open stat windows; we do so after creating
2565 the main window, to avoid GTK warnings, and after successfully
2566 opening the capture file, so we know we have something to compute
2567 stats on, and after registering all dissectors, so that MATE will
2568 have registered its field array and we can have a tap filter with
2569 one of MATE's late-registered fields as part of the filter. */
2570 start_requested_stats();
2574 show_main_window(FALSE);
2575 set_menus_for_capture_in_progress(FALSE);
2578 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2579 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2580 if (capture_opts->cfilter) {
2581 g_free(capture_opts->cfilter);
2583 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2585 #else /* HAVE_LIBPCAP */
2586 show_main_window(FALSE);
2587 set_menus_for_capture_in_progress(FALSE);
2588 #endif /* HAVE_LIBPCAP */
2591 /* we'll enter the GTK loop now and hand the control over to GTK ... */
2593 /* ... back from GTK, we're going down now! */
2599 /* hide the (unresponsive) main window, while asking the user to close the console window */
2600 gtk_widget_hide(top_level);
2602 /* Shutdown windows sockets */
2605 /* For some unknown reason, the "atexit()" call in "create_console()"
2606 doesn't arrange that "destroy_console()" be called when we exit,
2607 so we call it here if a console was created. */
2613 /* This isn't reached, but we need it to keep GCC from complaining
2614 that "main()" returns without returning a value - it knows that
2615 "exit()" never returns, but it doesn't know that "gtk_exit()"
2616 doesn't, as GTK+ doesn't declare it with the attribute
2618 return 0; /* not reached */
2623 /* We build this as a GUI subsystem application on Win32, so
2624 "WinMain()", not "main()", gets called.
2626 Hack shamelessly stolen from the Win32 port of the GIMP. */
2628 #define _stdcall __attribute__((stdcall))
2632 WinMain (struct HINSTANCE__ *hInstance,
2633 struct HINSTANCE__ *hPrevInstance,
2637 has_console = FALSE;
2638 return main (__argc, __argv);
2642 * If this application has no console window to which its standard output
2643 * would go, create one.
2646 create_console(void)
2649 /* We have no console to which to print the version string, so
2650 create one and make it the standard input, output, and error. */
2651 if (!AllocConsole())
2652 return; /* couldn't create console */
2653 freopen("CONIN$", "r", stdin);
2654 freopen("CONOUT$", "w", stdout);
2655 freopen("CONOUT$", "w", stderr);
2657 /* Well, we have a console now. */
2660 /* Now register "destroy_console()" as a routine to be called just
2661 before the application exits, so that we can destroy the console
2662 after the user has typed a key (so that the console doesn't just
2663 disappear out from under them, giving the user no chance to see
2664 the message(s) we put in there). */
2665 atexit(destroy_console);
2668 SetConsoleTitle("Ethereal Capture Child Debug Console");
2670 SetConsoleTitle("Ethereal Debug Console");
2676 destroy_console(void)
2678 if (has_console && !capture_child) {
2679 printf("\n\nPress any key to exit\n");
2687 /* This routine should not be necessary, at least as I read the GLib
2688 source code, as it looks as if GLib is, on Win32, *supposed* to
2689 create a console window into which to display its output.
2691 That doesn't happen, however. I suspect there's something completely
2692 broken about that code in GLib-for-Win32, and that it may be related
2693 to the breakage that forces us to just call "printf()" on the message
2694 rather than passing the message on to "g_log_default_handler()"
2695 (which is the routine that does the aforementioned non-functional
2696 console window creation). */
2698 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2699 const char *message, gpointer user_data _U_)
2706 /* change this, if you want to see more verbose log output */
2707 /* XXX - make this a pref value */
2708 if( (log_level & G_LOG_LEVEL_MASK) > G_LOG_LEVEL_WARNING) {
2712 /* create a "timestamp" */
2714 today = localtime(&curr);
2717 if (prefs.gui_console_open != console_open_never) {
2721 /* For some unknown reason, the above doesn't appear to actually cause
2722 anything to be sent to the standard output, so we'll just splat the
2723 message out directly, just to make sure it gets out. */
2725 switch(log_level & G_LOG_LEVEL_MASK) {
2726 case G_LOG_LEVEL_ERROR:
2729 case G_LOG_LEVEL_CRITICAL:
2732 case G_LOG_LEVEL_WARNING:
2735 case G_LOG_LEVEL_MESSAGE:
2738 case G_LOG_LEVEL_INFO:
2741 case G_LOG_LEVEL_DEBUG:
2745 fprintf(stderr, "unknown log_level %u\n", log_level);
2747 g_assert_not_reached();
2750 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2751 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2752 today->tm_hour, today->tm_min, today->tm_sec,
2753 log_domain != NULL ? log_domain : "",
2757 g_log_default_handler(log_domain, log_level, message, user_data);
2763 static GtkWidget *info_bar_new(void)
2765 /* tip: tooltips don't work on statusbars! */
2766 info_bar = gtk_statusbar_new();
2767 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2768 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2769 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2770 #if GTK_MAJOR_VERSION >= 2
2771 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2773 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2778 static GtkWidget *packets_bar_new(void)
2780 /* tip: tooltips don't work on statusbars! */
2781 packets_bar = gtk_statusbar_new();
2782 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2783 packets_bar_update();
2790 * Helper for main_widgets_rearrange()
2792 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2793 gtk_container_remove(GTK_CONTAINER(data), widget);
2796 static GtkWidget *main_widget_layout(gint layout_content)
2798 switch(layout_content) {
2799 case(layout_pane_content_none):
2802 case(layout_pane_content_plist):
2805 case(layout_pane_content_pdetails):
2808 case(layout_pane_content_pbytes):
2812 g_assert_not_reached();
2819 * Rearrange the main window widgets
2821 void main_widgets_rearrange(void) {
2822 GtkWidget *first_pane_widget1, *first_pane_widget2;
2823 GtkWidget *second_pane_widget1, *second_pane_widget2;
2824 gboolean split_top_left;
2826 /* be a bit faster */
2827 gtk_widget_hide(main_vbox);
2829 /* be sure, we don't loose a widget while rearranging */
2830 gtk_widget_ref(menubar);
2831 gtk_widget_ref(main_tb);
2832 gtk_widget_ref(filter_tb);
2833 gtk_widget_ref(pkt_scrollw);
2834 gtk_widget_ref(tv_scrollw);
2835 gtk_widget_ref(byte_nb_ptr);
2836 gtk_widget_ref(stat_hbox);
2837 gtk_widget_ref(info_bar);
2838 gtk_widget_ref(packets_bar);
2839 gtk_widget_ref(status_pane);
2840 gtk_widget_ref(main_pane_v1);
2841 gtk_widget_ref(main_pane_v2);
2842 gtk_widget_ref(main_pane_h1);
2843 gtk_widget_ref(main_pane_h2);
2844 gtk_widget_ref(welcome_pane);
2846 /* empty all containers participating */
2847 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2848 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2849 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2850 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2851 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2852 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2853 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2855 /* add the menubar always at the top */
2856 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2859 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2861 /* filter toolbar in toolbar area */
2862 if (!prefs.filter_toolbar_show_in_statusbar) {
2863 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2866 /* fill the main layout panes */
2867 switch(prefs.gui_layout_type) {
2868 case(layout_type_5):
2869 main_first_pane = main_pane_v1;
2870 main_second_pane = main_pane_v2;
2871 split_top_left = FALSE;
2873 case(layout_type_2):
2874 main_first_pane = main_pane_v1;
2875 main_second_pane = main_pane_h1;
2876 split_top_left = FALSE;
2878 case(layout_type_1):
2879 main_first_pane = main_pane_v1;
2880 main_second_pane = main_pane_h1;
2881 split_top_left = TRUE;
2883 case(layout_type_4):
2884 main_first_pane = main_pane_h1;
2885 main_second_pane = main_pane_v1;
2886 split_top_left = FALSE;
2888 case(layout_type_3):
2889 main_first_pane = main_pane_h1;
2890 main_second_pane = main_pane_v1;
2891 split_top_left = TRUE;
2893 case(layout_type_6):
2894 main_first_pane = main_pane_h1;
2895 main_second_pane = main_pane_h2;
2896 split_top_left = FALSE;
2899 main_first_pane = NULL;
2900 main_second_pane = NULL;
2901 split_top_left = FALSE;
2902 g_assert_not_reached();
2904 if (split_top_left) {
2905 first_pane_widget1 = main_second_pane;
2906 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2907 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2908 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2910 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2911 first_pane_widget2 = main_second_pane;
2912 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2913 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2915 if (first_pane_widget1 != NULL)
2916 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2917 if (first_pane_widget2 != NULL)
2918 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2919 if (second_pane_widget1 != NULL)
2920 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2921 if (second_pane_widget2 != NULL)
2922 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2924 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2927 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2929 /* statusbar hbox */
2930 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2932 /* filter toolbar in statusbar hbox */
2933 if (prefs.filter_toolbar_show_in_statusbar) {
2934 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2938 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2939 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2940 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2942 /* hide widgets on users recent settings */
2943 main_widgets_show_or_hide();
2945 gtk_widget_show(main_vbox);
2949 is_widget_visible(GtkWidget *widget, gpointer data)
2951 gboolean *is_visible = data;
2954 if (GTK_WIDGET_VISIBLE(widget))
2961 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2962 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2964 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2966 GtkWidget *w, *item_hb;
2967 #if GTK_MAJOR_VERSION >= 2
2968 gchar *formatted_message;
2972 item_hb = gtk_hbox_new(FALSE, 1);
2974 w = BUTTON_NEW_FROM_STOCK(stock_item);
2975 WIDGET_SET_SIZE(w, 60, 60);
2976 #if GTK_MAJOR_VERSION >= 2
2977 gtk_button_set_label(GTK_BUTTON(w), label);
2979 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
2980 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
2982 w = gtk_label_new(message);
2983 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2984 #if GTK_MAJOR_VERSION >= 2
2985 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
2986 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
2987 g_free(formatted_message);
2990 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
2996 /* XXX - the layout has to be improved */
3000 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
3001 GtkWidget *w, *icon;
3005 welcome_scrollw = scrolled_window_new(NULL, NULL);
3007 welcome_hb = gtk_hbox_new(FALSE, 1);
3008 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
3010 welcome_vb = gtk_vbox_new(FALSE, 1);
3012 item_hb = gtk_hbox_new(FALSE, 1);
3014 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
3015 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
3017 #if GTK_MAJOR_VERSION < 2
3018 message = "Welcome to Ethereal!";
3020 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
3022 w = gtk_label_new(message);
3023 #if GTK_MAJOR_VERSION >= 2
3024 gtk_label_set_markup(GTK_LABEL(w), message);
3026 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3027 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3029 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3031 w = gtk_label_new("What would you like to do?");
3032 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
3033 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3036 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
3038 "Capture live data from your network",
3039 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
3040 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3043 item_hb = welcome_item(GTK_STOCK_OPEN,
3045 "Open a previously captured file",
3046 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
3047 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3049 #if (GLIB_MAJOR_VERSION >= 2)
3050 item_hb = welcome_item(GTK_STOCK_HOME,
3052 "Visit the Ethereal homepage",
3053 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
3054 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3058 w = gtk_label_new("");
3059 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
3061 w = gtk_label_new("");
3062 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3064 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3066 w = gtk_label_new("");
3067 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3069 gtk_widget_show_all(welcome_hb);
3071 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3073 gtk_widget_show_all(welcome_scrollw);
3075 return welcome_scrollw;
3082 /* this is just a dummy to fill up window space, simply showing nothing */
3083 return scrolled_window_new(NULL, NULL);
3089 * XXX - this doesn't appear to work with the paned widgets in
3090 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3091 * and the other pane doesn't grow to take up the rest of the pane.
3092 * It does appear to work with GTK+ 2.x.
3095 main_widgets_show_or_hide(void)
3097 gboolean main_second_pane_show;
3099 if (recent.main_toolbar_show) {
3100 gtk_widget_show(main_tb);
3102 gtk_widget_hide(main_tb);
3106 * Show the status hbox if either:
3108 * 1) we're showing the filter toolbar and we want it in the status
3113 * 2) we're showing the status bar.
3115 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3116 recent.statusbar_show) {
3117 gtk_widget_show(stat_hbox);
3119 gtk_widget_hide(stat_hbox);
3122 if (recent.statusbar_show) {
3123 gtk_widget_show(status_pane);
3125 gtk_widget_hide(status_pane);
3128 if (recent.filter_toolbar_show) {
3129 gtk_widget_show(filter_tb);
3131 gtk_widget_hide(filter_tb);
3134 if (recent.packet_list_show && have_capture_file) {
3135 gtk_widget_show(pkt_scrollw);
3137 gtk_widget_hide(pkt_scrollw);
3140 if (recent.tree_view_show && have_capture_file) {
3141 gtk_widget_show(tv_scrollw);
3143 gtk_widget_hide(tv_scrollw);
3146 if (recent.byte_view_show && have_capture_file) {
3147 gtk_widget_show(byte_nb_ptr);
3149 gtk_widget_hide(byte_nb_ptr);
3152 if (have_capture_file) {
3153 gtk_widget_show(main_first_pane);
3155 gtk_widget_hide(main_first_pane);
3159 * Is anything in "main_second_pane" visible?
3160 * If so, show it, otherwise hide it.
3162 main_second_pane_show = FALSE;
3163 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3164 &main_second_pane_show);
3165 if (main_second_pane_show) {
3166 gtk_widget_show(main_second_pane);
3168 gtk_widget_hide(main_second_pane);
3171 if (!have_capture_file) {
3173 gtk_widget_show(welcome_pane);
3176 gtk_widget_hide(welcome_pane);
3181 #if GTK_MAJOR_VERSION >= 2
3182 /* called, when the window state changes (minimized, maximized, ...) */
3184 window_state_event_cb (GtkWidget *widget _U_,
3188 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3190 if( (event->type) == (GDK_WINDOW_STATE)) {
3191 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3192 /* we might have dialogs popped up while we where iconified,
3194 display_queued_messages();
3203 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3206 *filter_bt, *filter_cm, *filter_te,
3207 *filter_add_expr_bt,
3210 GList *dfilter_list = NULL;
3211 GtkTooltips *tooltips;
3212 GtkAccelGroup *accel;
3214 /* Display filter construct dialog has an Apply button, and "OK" not
3215 only sets our text widget, it activates it (i.e., it causes us to
3216 filter the capture). */
3217 static construct_args_t args = {
3218 "Ethereal: Display Filter",
3223 /* use user-defined title if preference is set */
3224 title = create_user_window_title("The Ethereal Network Analyzer");
3227 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3230 tooltips = gtk_tooltips_new();
3233 #if GTK_MAJOR_VERSION < 2
3234 /* has to be done, after top_level window is created */
3235 app_font_gtk1_init(top_level);
3239 gtk_widget_set_name(top_level, "main window");
3240 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3242 #if GTK_MAJOR_VERSION >= 2
3243 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3244 G_CALLBACK (window_state_event_cb), NULL);
3247 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3249 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3250 main_vbox = gtk_vbox_new(FALSE, 1);
3251 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3252 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3253 gtk_widget_show(main_vbox);
3256 menubar = main_menu_new(&accel);
3257 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3258 gtk_widget_show(menubar);
3261 main_tb = toolbar_new();
3262 gtk_widget_show (main_tb);
3265 pkt_scrollw = packet_list_new(prefs);
3266 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3267 gtk_widget_show(pkt_scrollw);
3270 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3271 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3272 gtk_widget_show(tv_scrollw);
3274 #if GTK_MAJOR_VERSION < 2
3275 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3276 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3279 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3280 "changed", tree_view_selection_changed_cb, NULL);
3282 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3283 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3284 gtk_widget_show(tree_view);
3287 byte_nb_ptr = byte_view_new();
3288 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3289 gtk_widget_show(byte_nb_ptr);
3291 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3292 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3295 /* Panes for the packet list, tree, and byte view */
3296 main_pane_v1 = gtk_vpaned_new();
3297 gtk_widget_show(main_pane_v1);
3298 main_pane_v2 = gtk_vpaned_new();
3299 gtk_widget_show(main_pane_v2);
3300 main_pane_h1 = gtk_hpaned_new();
3301 gtk_widget_show(main_pane_h1);
3302 main_pane_h2 = gtk_hpaned_new();
3303 gtk_widget_show(main_pane_h2);
3305 /* filter toolbar */
3306 #if GTK_MAJOR_VERSION < 2
3307 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3310 filter_tb = gtk_toolbar_new();
3311 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3312 GTK_ORIENTATION_HORIZONTAL);
3313 #endif /* GTK_MAJOR_VERSION */
3314 gtk_widget_show(filter_tb);
3316 /* Create the "Filter:" button */
3317 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3318 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3319 gtk_widget_show(filter_bt);
3320 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3322 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3323 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3325 /* Create the filter combobox */
3326 filter_cm = gtk_combo_new();
3327 dfilter_list = NULL;
3328 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3329 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3330 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3331 filter_te = GTK_COMBO(filter_cm)->entry;
3332 main_display_filter_widget=filter_te;
3333 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3334 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3335 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3336 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3337 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3338 WIDGET_SET_SIZE(filter_cm, 400, -1);
3339 gtk_widget_show(filter_cm);
3340 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3342 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3343 gtk_tooltips_set_tip(tooltips, filter_te,
3344 "Enter a display filter, or choose one of your recently used filters. "
3345 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3348 /* Create the "Add Expression..." button, to pop up a dialog
3349 for constructing filter comparison expressions. */
3350 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3351 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3352 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3353 gtk_widget_show(filter_add_expr_bt);
3354 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3355 "Add an expression to this filter string", "Private");
3357 /* Create the "Clear" button */
3358 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3359 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3360 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3361 gtk_widget_show(filter_reset);
3362 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3363 "Clear this filter string and update the display", "Private");
3365 /* Create the "Apply" button */
3366 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3367 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3368 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3369 gtk_widget_show(filter_apply);
3370 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3371 "Apply this filter string to the display", "Private");
3373 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3374 * of any widget that ends up calling a callback which needs
3375 * that text entry pointer */
3376 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3377 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3379 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3381 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3383 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3385 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3387 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3389 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3391 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3393 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3395 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3397 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3399 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3401 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3403 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3405 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3406 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3407 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3409 /* info (main) statusbar */
3410 info_bar = info_bar_new();
3411 gtk_widget_show(info_bar);
3413 /* packets statusbar */
3414 packets_bar = packets_bar_new();
3415 gtk_widget_show(packets_bar);
3417 /* Filter/status hbox */
3418 stat_hbox = gtk_hbox_new(FALSE, 1);
3419 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3420 gtk_widget_show(stat_hbox);
3422 /* Pane for the statusbar */
3423 status_pane = gtk_hpaned_new();
3424 gtk_widget_show(status_pane);
3426 /* Pane for the welcome screen */
3427 welcome_pane = welcome_new();
3428 gtk_widget_show(welcome_pane);
3432 show_main_window(gboolean doing_work)
3434 main_set_for_capture_file(doing_work);
3436 /*** we have finished all init things, show the main window ***/
3437 gtk_widget_show(top_level);
3439 /* the window can be maximized only, if it's visible, so do it after show! */
3440 main_load_window_geometry(top_level);
3442 /* process all pending GUI events before continue */
3443 while (gtk_events_pending()) gtk_main_iteration();
3445 /* Pop up any queued-up alert boxes. */
3446 display_queued_messages();