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>
69 /* general (not GTK specific) */
70 #include "svnversion.h"
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" /* beware: ui_util.h exists twice! */
88 #include "clopts_common.h"
89 #include "version_info.h"
94 #include "pcap-util.h"
99 #include "capture-wpcap.h"
100 #include "capture_wpcap_packet.h"
103 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
104 #include "ethclist.h"
108 #include "statusbar.h"
109 #include "alert_box.h"
110 #include "dlg_utils.h"
111 #include "gtkglobals.h"
113 #include "ui_util.h" /* beware: ui_util.h exists twice! */
114 #include "compat_macros.h"
118 #include "../main_window.h"
120 #include "file_dlg.h"
121 #include <epan/column.h>
122 #include "proto_draw.h"
124 #include "packet_win.h"
126 #include "find_dlg.h"
127 #include "packet_list.h"
129 #include "follow_dlg.h"
130 #include "font_utils.h"
131 #include "about_dlg.h"
132 #include "help_dlg.h"
133 #include "decode_as_dlg.h"
134 #include "webbrowser.h"
135 #include "capture_dlg.h"
137 #include "../image/eicon3d64.xpm"
139 #include "capture_ui_utils.h"
145 * Files under personal and global preferences directories in which
146 * GTK settings for Ethereal are stored.
148 #define RC_FILE "gtkrc"
151 #define DEF_READY_MESSAGE " Ready to load or capture"
153 #define DEF_READY_MESSAGE " Ready to load file"
157 GtkWidget *main_display_filter_widget=NULL;
158 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
159 static GtkWidget *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
160 static GtkWidget *main_first_pane, *main_second_pane;
161 static GtkWidget *status_pane;
162 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
163 static GtkWidget *info_bar;
164 static GtkWidget *packets_bar = NULL;
165 static GtkWidget *welcome_pane;
166 static guint main_ctx, file_ctx, help_ctx;
167 static guint packets_ctx;
168 static gchar *packets_str = NULL;
169 GString *comp_info_str, *runtime_info_str;
170 gchar *ethereal_path = NULL;
171 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
174 static gboolean has_console; /* TRUE if app has console */
175 static void destroy_console(void);
177 static void console_log_handler(const char *log_domain,
178 GLogLevelFlags log_level, const char *message, gpointer user_data);
181 static gboolean list_link_layer_types;
182 capture_options global_capture_opts;
183 capture_options *capture_opts = &global_capture_opts;
187 static void create_main_window(gint, gint, gint, e_prefs*);
188 static void show_main_window(gboolean);
189 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
190 static void main_save_window_geometry(GtkWidget *widget);
192 #define E_DFILTER_CM_KEY "display_filter_combo"
193 #define E_DFILTER_FL_KEY "display_filter_list"
197 /* Match selected byte pattern */
199 match_selected_cb_do(gpointer data, int action, gchar *text)
201 GtkWidget *filter_te;
202 char *cur_filter, *new_filter;
207 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
210 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
212 switch (action&MATCH_SELECTED_MASK) {
214 case MATCH_SELECTED_REPLACE:
215 new_filter = g_strdup(text);
218 case MATCH_SELECTED_AND:
219 if ((!cur_filter) || (0 == strlen(cur_filter)))
220 new_filter = g_strdup(text);
222 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
225 case MATCH_SELECTED_OR:
226 if ((!cur_filter) || (0 == strlen(cur_filter)))
227 new_filter = g_strdup(text);
229 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
232 case MATCH_SELECTED_NOT:
233 new_filter = g_strconcat("!(", text, ")", NULL);
236 case MATCH_SELECTED_AND_NOT:
237 if ((!cur_filter) || (0 == strlen(cur_filter)))
238 new_filter = g_strconcat("!(", text, ")", NULL);
240 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
243 case MATCH_SELECTED_OR_NOT:
244 if ((!cur_filter) || (0 == strlen(cur_filter)))
245 new_filter = g_strconcat("!(", text, ")", NULL);
247 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
251 g_assert_not_reached();
256 /* Free up the copy we got of the old filter text. */
259 /* create a new one and set the display filter entry accordingly */
260 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
262 /* Run the display filter so it goes in effect. */
263 if (action&MATCH_SELECTED_APPLY_NOW)
264 main_filter_packets(&cfile, new_filter, FALSE);
266 /* Free up the new filter text. */
269 /* Free up the generated text we were handed. */
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 = g_malloc0(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
1088 "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
1090 comp_info_str->str, runtime_info_str->str);
1095 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);
1096 fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
1097 fprintf(output, "\t[ -B capture buffer size (Win32 only) ]\n");
1098 fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
1099 fprintf(output, "\t[ -g <packet number> ]\n");
1100 fprintf(output, "\t[ -i <capture interface> ] [ -m <font> ] [ -N <name resolving flags> ]\n");
1101 fprintf(output, "\t[ -o <preference/recent setting> ] ...\n");
1102 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
1103 fprintf(output, "\t[ -t <time stamp format> ]\n");
1104 fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
1105 fprintf(output, "\t[ <infile> ]\n");
1107 fprintf(output, "\n%s [ -vh ] [ -n ] [ -g <packet number> ] [ -m <font> ]\n", PACKAGE);
1108 fprintf(output, "\t[ -N <resolving flags> ] [ -o <preference/recent setting> ...\n");
1109 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ]\n");
1110 fprintf(output, "\t[ -t <time stamp format> ]\n");
1111 fprintf(output, "\t[ -z <statistics ] [ <infile> ]\n");
1126 printf(PACKAGE " " VERSION
1131 comp_info_str->str, runtime_info_str->str);
1138 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1140 Once every 3 seconds we get a callback here which we use to update
1141 the tap extensions. Since Gtk1 is single threaded we dont have to
1142 worry about any locking or critical regions.
1145 update_cb(gpointer data _U_)
1147 draw_tap_listeners(FALSE);
1152 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1153 use threads all updte_thread_mutex can be dropped and protect/unprotect
1154 would just be empty functions.
1156 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1157 gtk1-ethereal and it will just work.
1159 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1161 update_thread(gpointer data _U_)
1165 g_get_current_time(&tv1);
1166 g_static_mutex_lock(&update_thread_mutex);
1167 gdk_threads_enter();
1168 draw_tap_listeners(FALSE);
1169 gdk_threads_leave();
1170 g_static_mutex_unlock(&update_thread_mutex);
1172 g_get_current_time(&tv2);
1173 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1174 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1175 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1176 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1183 protect_thread_critical_region(void)
1185 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1186 g_static_mutex_lock(&update_thread_mutex);
1190 unprotect_thread_critical_region(void)
1192 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1193 g_static_mutex_unlock(&update_thread_mutex);
1197 /* Set the file name in the status line, in the name for the main window,
1198 and in the name for the main window's icon. */
1200 set_display_filename(capture_file *cf)
1202 const gchar *name_ptr;
1207 name_ptr = cf_get_display_name(cf);
1209 if (!cf->is_tempfile && cf->filename) {
1210 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1211 add_menu_recent_capture_file(cf->filename);
1214 /* convert file size */
1215 if (cf->f_len/1024/1024 > 10) {
1216 size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
1217 } else if (cf->f_len/1024 > 10) {
1218 size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
1220 size_str = g_strdup_printf("%ld Bytes", cf->f_len);
1224 status_msg = g_strdup_printf(" File: \"%s\" %s %02u:%02u:%02u",
1225 (cf->filename) ? cf->filename : "", size_str,
1226 cf->esec/3600, cf->esec%3600/60, cf->esec%60);
1228 statusbar_push_file_msg(status_msg);
1232 win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1233 set_main_window_name(win_name);
1239 main_cf_cb_file_closed(capture_file *cf)
1241 /* Destroy all windows, which refer to the
1242 capture file we're closing. */
1243 destroy_cfile_wins();
1245 /* Clear any file-related status bar messages.
1246 XXX - should be "clear *ALL* file-related status bar messages;
1247 will there ever be more than one on the stack? */
1248 statusbar_pop_file_msg();
1250 /* go back to "No packets" */
1251 packets_bar_update();
1253 /* Restore the standard title bar message. */
1254 set_main_window_name("The Ethereal Network Analyzer");
1256 /* Disable all menu items that make sense only if you have a capture. */
1257 set_menus_for_capture_file(FALSE);
1258 set_menus_for_unsaved_capture_file(FALSE);
1259 set_menus_for_captured_packets(FALSE);
1260 set_menus_for_selected_packet(cf);
1261 set_menus_for_capture_in_progress(FALSE);
1262 set_menus_for_selected_tree_row(cf);
1264 /* Set up main window for no capture file. */
1265 main_set_for_capture_file(FALSE);
1269 main_cf_cb_file_read_start(capture_file *cf)
1271 const gchar *name_ptr;
1274 name_ptr = get_basename(cf->filename);
1276 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1277 statusbar_push_file_msg(load_msg);
1282 main_cf_cb_file_read_finished(capture_file *cf)
1284 statusbar_pop_file_msg();
1285 set_display_filename(cf);
1287 /* Enable menu items that make sense if you have a capture file you've
1288 finished reading. */
1289 set_menus_for_capture_file(TRUE);
1290 set_menus_for_unsaved_capture_file(!cf->user_saved);
1292 /* Enable menu items that make sense if you have some captured packets. */
1293 set_menus_for_captured_packets(TRUE);
1295 /* Set up main window for a capture file. */
1296 main_set_for_capture_file(TRUE);
1301 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1306 if(capture_opts->iface) {
1307 title = g_strdup_printf("%s: Capturing - Ethereal",
1308 get_interface_descriptive_name(capture_opts->iface));
1310 title = g_strdup_printf("Capturing - Ethereal");
1312 set_main_window_name(title);
1315 /* Disable menu items that make no sense if you're currently running
1317 set_menus_for_capture_in_progress(TRUE);
1319 /* update statusbar */
1320 statusbar_push_file_msg("Waiting for capture input data ...");
1322 /* Don't set up main window for a capture file. */
1323 main_set_for_capture_file(FALSE);
1327 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1332 /* Enable menu items that make sense if you have some captured
1333 packets (yes, I know, we don't have any *yet*). */
1334 set_menus_for_captured_packets(TRUE);
1336 statusbar_pop_file_msg();
1338 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1339 get_interface_descriptive_name(capture_opts->iface),
1340 (capture_opts->save_file) ? capture_opts->save_file : "");
1342 statusbar_push_file_msg(capture_msg);
1344 g_free(capture_msg);
1346 /* Set up main window for a capture file. */
1347 main_set_for_capture_file(TRUE);
1351 main_cf_cb_live_capture_update_continue(capture_file *cf)
1356 statusbar_pop_file_msg();
1358 if (cf->f_len/1024/1024 > 10) {
1359 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB",
1360 get_interface_descriptive_name(capture_opts->iface),
1361 capture_opts->save_file,
1362 cf->f_len/1024/1024);
1363 } else if (cf->f_len/1024 > 10) {
1364 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB",
1365 get_interface_descriptive_name(capture_opts->iface),
1366 capture_opts->save_file,
1369 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes",
1370 get_interface_descriptive_name(capture_opts->iface),
1371 capture_opts->save_file,
1375 statusbar_push_file_msg(capture_msg);
1379 main_cf_cb_live_capture_update_finished(capture_file *cf)
1381 /* Pop the "<live capture in progress>" message off the status bar. */
1382 statusbar_pop_file_msg();
1384 set_display_filename(cf);
1386 /* Enable menu items that make sense if you're not currently running
1388 set_menus_for_capture_in_progress(FALSE);
1390 /* Enable menu items that make sense if you have a capture file
1391 you've finished reading. */
1392 set_menus_for_capture_file(TRUE);
1393 set_menus_for_unsaved_capture_file(!cf->user_saved);
1395 /* Set up main window for a capture file. */
1396 main_set_for_capture_file(TRUE);
1400 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1405 /* Enable menu items that make sense if you have some captured
1406 packets (yes, I know, we don't have any *yet*). */
1407 /*set_menus_for_captured_packets(TRUE);*/
1409 statusbar_pop_file_msg();
1411 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1412 get_interface_descriptive_name(capture_opts->iface),
1413 (capture_opts->save_file) ? capture_opts->save_file : "");
1415 statusbar_push_file_msg(capture_msg);
1416 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " <capturing>");
1418 g_free(capture_msg);
1420 /* Don't set up main window for a capture file. */
1421 main_set_for_capture_file(FALSE);
1425 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1427 /* Pop the "<live capture in progress>" message off the status bar. */
1428 statusbar_pop_file_msg();
1430 /* Pop the "<capturing>" message off the status bar */
1431 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1433 /*set_display_filename(cf);*/
1435 /* Enable menu items that make sense if you're not currently running
1437 set_menus_for_capture_in_progress(FALSE);
1439 /* We don't have loaded the capture file, this will be done later.
1440 * For now we still have simply a blank screen. */
1445 main_cf_cb_packet_selected(gpointer data)
1447 capture_file *cf = data;
1449 /* Display the GUI protocol tree and hex dump.
1450 XXX - why do we dump core if we call "proto_tree_draw()"
1451 before calling "add_byte_views()"? */
1452 add_main_byte_views(cf->edt);
1453 main_proto_tree_draw(cf->edt->tree);
1455 /* A packet is selected. */
1456 set_menus_for_selected_packet(cf);
1460 main_cf_cb_packet_unselected(capture_file *cf)
1462 /* Clear out the display of that packet. */
1463 clear_tree_and_hex_views();
1465 /* No packet is selected. */
1466 set_menus_for_selected_packet(cf);
1470 main_cf_cb_field_unselected(capture_file *cf)
1472 statusbar_pop_field_msg();
1473 set_menus_for_selected_tree_row(cf);
1477 main_cf_cb_file_safe_started(gchar * filename)
1479 const gchar *name_ptr;
1482 name_ptr = get_basename(filename);
1484 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1486 statusbar_push_file_msg(save_msg);
1491 main_cf_cb_file_safe_finished(gpointer data _U_)
1493 /* Pop the "Saving:" message off the status bar. */
1494 statusbar_pop_file_msg();
1498 main_cf_cb_file_safe_failed(gpointer data _U_)
1500 /* Pop the "Saving:" message off the status bar. */
1501 statusbar_pop_file_msg();
1505 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1507 set_menus_for_unsaved_capture_file(FALSE);
1510 void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1513 case(cf_cb_file_closed):
1514 main_cf_cb_file_closed(data);
1516 case(cf_cb_file_read_start):
1517 main_cf_cb_file_read_start(data);
1519 case(cf_cb_file_read_finished):
1520 main_cf_cb_file_read_finished(data);
1523 case(cf_cb_live_capture_prepared):
1524 main_cf_cb_live_capture_prepared(data);
1526 case(cf_cb_live_capture_update_started):
1527 main_cf_cb_live_capture_update_started(data);
1529 case(cf_cb_live_capture_update_continue):
1530 main_cf_cb_live_capture_update_continue(data);
1532 case(cf_cb_live_capture_fixed_started):
1533 main_cf_cb_live_capture_fixed_started(data);
1535 case(cf_cb_live_capture_update_finished):
1536 main_cf_cb_live_capture_update_finished(data);
1538 case(cf_cb_live_capture_fixed_finished):
1539 main_cf_cb_live_capture_fixed_finished(data);
1542 case(cf_cb_packet_selected):
1543 main_cf_cb_packet_selected(data);
1545 case(cf_cb_packet_unselected):
1546 main_cf_cb_packet_unselected(data);
1548 case(cf_cb_field_unselected):
1549 main_cf_cb_field_unselected(data);
1551 case(cf_cb_file_safe_started):
1552 main_cf_cb_file_safe_started(data);
1554 case(cf_cb_file_safe_finished):
1555 main_cf_cb_file_safe_finished(data);
1557 case(cf_cb_file_safe_reload_finished):
1558 main_cf_cb_file_safe_reload_finished(data);
1560 case(cf_cb_file_safe_failed):
1561 main_cf_cb_file_safe_failed(data);
1564 g_warning("main_cf_callback: event %u unknown", event);
1565 g_assert_not_reached();
1569 /* And now our feature presentation... [ fade to music ] */
1571 main(int argc, char *argv[])
1574 const char *command_name;
1579 extern char *optarg;
1580 gboolean arg_error = FALSE;
1588 char *gpf_path, *pf_path;
1589 char *cf_path, *df_path;
1590 char *gdp_path, *dp_path;
1591 int gpf_open_errno, gpf_read_errno;
1592 int pf_open_errno, pf_read_errno;
1593 int cf_open_errno, df_open_errno;
1594 int gdp_open_errno, gdp_read_errno;
1595 int dp_open_errno, dp_read_errno;
1598 gboolean start_capture = FALSE;
1601 GList *lt_list, *lt_entry;
1602 data_link_info_t *data_link_info;
1603 gchar err_str[PCAP_ERRBUF_SIZE];
1604 gchar *cant_get_if_list_errstr;
1605 gboolean stats_known;
1606 struct pcap_stat stats;
1608 gboolean capture_option_specified = FALSE;
1610 gint pl_size = 280, tv_size = 95, bv_size = 75;
1611 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1612 dfilter_t *rfcode = NULL;
1613 gboolean rfilter_parse_failed = FALSE;
1616 GtkWidget *splash_win = NULL;
1617 gboolean capture_child; /* True if this is the child for "-S" */
1618 GLogLevelFlags log_flags;
1619 guint go_to_packet = 0;
1622 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1626 #define OPTSTRING_CHILD "W:Z:"
1627 #define OPTSTRING_WIN32 "B:"
1629 #define OPTSTRING_CHILD "W:"
1630 #define OPTSTRING_WIN32 ""
1633 #define OPTSTRING_CHILD ""
1634 #define OPTSTRING_WIN32 ""
1635 #endif /* HAVE_LIBPCAP */
1637 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1638 OPTSTRING_INIT OPTSTRING_WIN32;
1641 /*** create the compile and runtime version strings ***/
1643 /* Load wpcap if possible. Do this before collecting the run-time version information */
1646 /* ... and also load the packet.dll from wpcap */
1647 wpcap_packet_load();
1649 /* Start windows sockets */
1650 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1653 /* Assemble the compile-time version information string */
1654 comp_info_str = g_string_new("Compiled ");
1655 g_string_append(comp_info_str, "with ");
1656 g_string_sprintfa(comp_info_str,
1657 #ifdef GTK_MAJOR_VERSION
1658 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1661 "GTK+ (version unknown)");
1664 g_string_append(comp_info_str, ", ");
1665 get_compiled_version_info(comp_info_str);
1667 /* Assemble the run-time version information string */
1668 runtime_info_str = g_string_new("Running ");
1669 get_runtime_version_info(runtime_info_str);
1672 /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1673 /* (e.g. don't start GTK+, if we only have to show the command line help) */
1674 optind_initial = optind;
1675 while ((opt = getopt(argc, argv, optstring)) != -1) {
1677 case 'h': /* Print help and exit */
1681 case 'v': /* Show version and exit */
1685 case 'G': /* dump various field or other infos, see handle_dashG_option() */
1686 /* If invoked with the "-G" flag, we dump out information based on
1687 the argument to the "-G" flag; if no argument is specified,
1688 for backwards compatibility we dump out a glossary of display
1691 We must do this before calling "gtk_init()", because "gtk_init()"
1692 tries to open an X display, and we don't want to have to do any X
1693 stuff just to do a build.
1695 Given that we call "gtk_init()" before doing the regular argument
1696 list processing, so that it can handle X and GTK+ arguments and
1697 remove them from the list at which we look, this means we must do
1698 this before doing the regular argument list processing, as well.
1702 you must give the "-G" flag as the first flag on the command line;
1704 you must give it as "-G", nothing more, nothing less;
1706 the first argument after the "-G" flag, if present, will be used
1707 to specify the information to dump;
1709 arguments after that will not be used. */
1710 handle_dashG_option(argc, argv, "ethereal");
1711 /* will never return! */
1717 /* set getopt index back to initial value, so it will start with the first command line parameter again */
1718 /* (XXX - this seems to be portable, but time will tell) */
1719 optind = optind_initial;
1722 /* Set the current locale according to the program environment.
1723 * We haven't localized anything, but some GTK widgets are localized
1724 * (the file selection dialogue, for example).
1725 * This also sets the C-language locale to the native environment. */
1728 /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1729 gtk_init (&argc, &argv);
1731 cf_callback_add(main_cf_callback, NULL);
1733 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1734 /* initialize our GTK eth_clist_type */
1735 init_eth_clist_type();
1738 ethereal_path = argv[0];
1740 /* Arrange that if we have no console window, and a GLib message logging
1741 routine is called to log a message, we pop up a console window.
1743 We do that by inserting our own handler for all messages logged
1744 to the default domain; that handler pops up a console if necessary,
1745 and then calls the default handler. */
1747 /* We might want to have component specific log levels later ... */
1749 /* the default_log_handler will use stdout, which makes trouble with the */
1750 /* capture child, as it uses stdout for it's sync_pipe */
1751 /* so do the filtering in the console_log_handler and not here */
1754 G_LOG_LEVEL_CRITICAL|
1755 G_LOG_LEVEL_WARNING|
1756 G_LOG_LEVEL_MESSAGE|
1759 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1761 g_log_set_handler(NULL,
1763 console_log_handler, NULL /* user_data */);
1766 g_log_set_handler(LOG_DOMAIN_CAPTURE,
1768 console_log_handler, NULL /* user_data */);
1769 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1771 console_log_handler, NULL /* user_data */);
1773 /* Set the initial values in the capture_opts. This might be overwritten
1774 by preference settings and then again by the command line parameters. */
1775 capture_opts_init(capture_opts, &cfile);
1777 capture_opts->snaplen = MIN_PACKET_SIZE;
1778 capture_opts->has_ring_num_files = TRUE;
1780 command_name = get_basename(ethereal_path);
1781 /* Set "capture_child" to indicate whether this is going to be a child
1782 process for a "-S" capture. */
1783 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1784 if (capture_child) {
1785 strcat(optstring, OPTSTRING_CHILD);
1789 /* We want a splash screen only if we're not a child process.
1790 We won't come till here, if we had a "console only" command line parameter. */
1794 splash_win = splash_new("Loading Ethereal ...");
1796 splash_update(splash_win, "Registering dissectors ...");
1798 /* Register all dissectors; we must do this before checking for the
1799 "-G" flag, as the "-G" flag dumps information registered by the
1800 dissectors, and we must do it before we read the preferences, in
1801 case any dissectors register preferences. */
1802 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1803 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1805 splash_update(splash_win, "Registering tap listeners ...");
1807 /* Register all tap listeners; we do this before we parse the arguments,
1808 as the "-z" argument can specify a registered tap. */
1810 /* we register the plugin taps before the other taps because
1811 stats_tree taps plugins will be registered as tap listeners
1812 by stats_tree_stat.c and need to registered before that */
1815 register_all_plugin_tap_listeners();
1818 register_all_tap_listeners();
1820 splash_update(splash_win, "Loading module preferences ...");
1822 /* Now register the preferences for any non-dissector modules.
1823 We must do that before we read the preferences as well. */
1824 prefs_register_modules();
1826 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1827 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1830 g_thread_init(NULL);
1832 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1833 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1835 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1836 /* this is to keep tap extensions updating once every 3 seconds */
1837 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1838 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1841 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1844 splash_update(splash_win, "Loading configuration files ...");
1846 /* Read the preference files. */
1847 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1848 &pf_open_errno, &pf_read_errno, &pf_path);
1849 if (gpf_path != NULL) {
1850 if (gpf_open_errno != 0) {
1851 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1852 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1853 strerror(gpf_open_errno));
1855 if (gpf_read_errno != 0) {
1856 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1857 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1858 strerror(gpf_read_errno));
1861 if (pf_path != NULL) {
1862 if (pf_open_errno != 0) {
1863 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1864 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1865 strerror(pf_open_errno));
1867 if (pf_read_errno != 0) {
1868 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1869 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1870 strerror(pf_read_errno));
1877 /* if the user wants a console to be always there, well, we should open one for him */
1878 if (prefs->gui_console_open == console_open_always) {
1884 /* If this is a capture child process, it should pay no attention
1885 to the "prefs.capture_prom_mode" setting in the preferences file;
1886 it should do what the parent process tells it to do, and if
1887 the parent process wants it not to run in promiscuous mode, it'll
1888 tell it so with a "-p" flag.
1890 Otherwise, set promiscuous mode from the preferences setting. */
1891 /* the same applies to other preferences settings as well. */
1892 if (capture_child) {
1893 auto_scroll_live = FALSE;
1895 capture_opts->promisc_mode = prefs->capture_prom_mode;
1896 capture_opts->show_info = prefs->capture_show_info;
1897 capture_opts->real_time_mode = prefs->capture_real_time;
1898 auto_scroll_live = prefs->capture_auto_scroll;
1901 #endif /* HAVE_LIBPCAP */
1903 /* Set the name resolution code's flags from the preferences. */
1904 g_resolv_flags = prefs->name_resolve;
1906 /* Read the capture filter file. */
1907 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1908 if (cf_path != NULL) {
1909 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1910 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1911 strerror(cf_open_errno));
1915 /* Read the display filter file. */
1916 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1917 if (df_path != NULL) {
1918 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1919 "Could not open your display filter file\n\"%s\": %s.", df_path,
1920 strerror(df_open_errno));
1924 /* Read the disabled protocols file. */
1925 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1926 &dp_path, &dp_open_errno, &dp_read_errno);
1927 if (gdp_path != NULL) {
1928 if (gdp_open_errno != 0) {
1929 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1930 "Could not open global disabled protocols file\n\"%s\": %s.",
1931 gdp_path, strerror(gdp_open_errno));
1933 if (gdp_read_errno != 0) {
1934 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1935 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1936 gdp_path, strerror(gdp_read_errno));
1940 if (dp_path != NULL) {
1941 if (dp_open_errno != 0) {
1942 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1943 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1944 strerror(dp_open_errno));
1946 if (dp_read_errno != 0) {
1947 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1948 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
1949 strerror(dp_read_errno));
1954 /* Read the (static part) of the recent file. Only the static part of it will be read, */
1955 /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
1956 /* We have to do this already here, so command line parameters can overwrite these values. */
1957 recent_read_static(&rf_path, &rf_open_errno);
1959 init_cap_file(&cfile);
1961 /* Now get our args */
1962 while ((opt = getopt(argc, argv, optstring)) != -1) {
1964 /*** capture option specific ***/
1965 case 'a': /* autostop criteria */
1966 case 'b': /* Ringbuffer option */
1967 case 'c': /* Capture xxx packets */
1968 case 'f': /* capture filter */
1969 case 'k': /* Start capture immediately */
1970 case 'H': /* Hide capture info dialog box */
1971 case 'i': /* Use interface xxx */
1972 case 'p': /* Don't capture in promiscuous mode */
1973 case 'Q': /* Quit after capture (just capture to file) */
1974 case 's': /* Set the snapshot (capture) length */
1975 case 'S': /* "Sync" mode: used for following file ala tail -f */
1976 case 'w': /* Write to capture file xxx */
1977 case 'y': /* Set the pcap data link type */
1979 case 'B': /* Buffer size */
1980 /* Hidden option supporting Sync mode */
1981 case 'Z': /* Write to pipe FD XXX */
1984 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
1986 capture_option_specified = TRUE;
1991 /* This is a hidden option supporting Sync mode, so we don't set
1992 * the error flags for the user in the non-libpcap case.
1994 case 'W': /* Write to capture file FD xxx */
1995 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
1999 /*** all non capture option specific ***/
2000 case 'g': /* Go to packet */
2001 go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2003 case 'l': /* Automatic scrolling in live capture mode */
2005 auto_scroll_live = TRUE;
2007 capture_option_specified = TRUE;
2011 case 'L': /* Print list of link-layer types and exit */
2013 list_link_layer_types = TRUE;
2015 capture_option_specified = TRUE;
2019 case 'm': /* Fixed-width font for the display */
2020 if (prefs->PREFS_GUI_FONT_NAME != NULL)
2021 g_free(prefs->PREFS_GUI_FONT_NAME);
2022 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2024 case 'n': /* No name resolution */
2025 g_resolv_flags = RESOLV_NONE;
2027 case 'N': /* Select what types of addresses/port #s to resolve */
2028 if (g_resolv_flags == RESOLV_ALL)
2029 g_resolv_flags = RESOLV_NONE;
2030 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2031 if (badopt != '\0') {
2032 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
2037 case 'o': /* Override preference from command line */
2038 switch (prefs_set_pref(optarg)) {
2041 case PREFS_SET_SYNTAX_ERR:
2042 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
2045 case PREFS_SET_NO_SUCH_PREF:
2046 /* not a preference, might be a recent setting */
2047 switch (recent_set_arg(optarg)) {
2050 case PREFS_SET_SYNTAX_ERR:
2051 /* shouldn't happen, checked already above */
2052 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
2055 case PREFS_SET_NO_SUCH_PREF:
2056 case PREFS_SET_OBSOLETE:
2057 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference/recent value\n",
2062 g_assert_not_reached();
2065 case PREFS_SET_OBSOLETE:
2066 fprintf(stderr, "ethereal: -o flag \"%s\" specifies obsolete preference\n",
2071 g_assert_not_reached();
2074 case 'r': /* Read capture file xxx */
2075 /* We may set "last_open_dir" to "cf_name", and if we change
2076 "last_open_dir" later, we free the old value, so we have to
2077 set "cf_name" to something that's been allocated. */
2078 cf_name = g_strdup(optarg);
2080 case 'R': /* Read file filter */
2083 case 't': /* Time stamp type */
2084 if (strcmp(optarg, "r") == 0)
2085 set_timestamp_setting(TS_RELATIVE);
2086 else if (strcmp(optarg, "a") == 0)
2087 set_timestamp_setting(TS_ABSOLUTE);
2088 else if (strcmp(optarg, "ad") == 0)
2089 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
2090 else if (strcmp(optarg, "d") == 0)
2091 set_timestamp_setting(TS_DELTA);
2093 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
2095 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
2096 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
2101 /* We won't call the init function for the tap this soon
2102 as it would disallow MATE's fields (which are registered
2103 by the preferences set callback) from being used as
2104 part of a tap filter. Instead, we just add the argument
2105 to a list of tap arguments. */
2106 if (!process_tap_cmd_arg(optarg)) {
2107 fprintf(stderr,"ethereal: invalid -z argument.\n");
2108 fprintf(stderr," -z argument must be one of :\n");
2109 list_tap_cmd_args();
2114 case '?': /* Bad flag - print usage message */
2122 if (cf_name != NULL) {
2124 * Input file name specified with "-r" *and* specified as a regular
2125 * command-line argument.
2130 * Input file name not specified with "-r", and a command-line argument
2131 * was specified; treat it as the input file name.
2133 * Yes, this is different from tethereal, where non-flag command-line
2134 * arguments are a filter, but this works better on GUI desktops
2135 * where a command can be specified to be run to open a particular
2136 * file - yes, you could have "-r" as the last part of the command,
2137 * but that's a bit ugly.
2139 cf_name = g_strdup(argv[0]);
2149 * Extra command line arguments were specified; complain.
2151 fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2156 #ifndef HAVE_LIBPCAP
2157 if (capture_option_specified) {
2158 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2166 if (start_capture && list_link_layer_types) {
2167 /* Specifying *both* is bogus. */
2168 fprintf(stderr, "ethereal: You can't specify both -L and a live capture.\n");
2172 if (list_link_layer_types) {
2173 /* We're supposed to list the link-layer types for an interface;
2174 did the user also specify a capture file to be read? */
2176 /* Yes - that's bogus. */
2177 fprintf(stderr, "ethereal: You can't specify -L and a capture file to be read.\n");
2180 /* No - did they specify a ring buffer option? */
2181 if (capture_opts->multi_files_on) {
2182 fprintf(stderr, "ethereal: Ring buffer requested, but a capture isn't being done.\n");
2186 /* We're supposed to do a live capture; did the user also specify
2187 a capture file to be read? */
2188 if (start_capture && cf_name) {
2189 /* Yes - that's bogus. */
2190 fprintf(stderr, "ethereal: You can't specify both a live capture and a capture file to be read.\n");
2194 /* No - was the ring buffer option specified and, if so, does it make
2196 if (capture_opts->multi_files_on) {
2197 /* Ring buffer works only under certain conditions:
2198 a) ring buffer does not work with temporary files;
2199 b) real_time_mode and multi_files_on are mutually exclusive -
2200 real_time_mode takes precedence;
2201 c) it makes no sense to enable the ring buffer if the maximum
2202 file size is set to "infinite". */
2203 if (capture_opts->save_file == NULL) {
2204 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2205 capture_opts->multi_files_on = FALSE;
2207 /* if (capture_opts->real_time_mode) {
2208 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2209 capture_opts->multi_files_on = FALSE;
2211 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2212 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.\n");
2213 /* XXX - this must be redesigned as the conditions changed */
2214 /* capture_opts->multi_files_on = FALSE;*/
2219 if (start_capture || list_link_layer_types) {
2220 /* Did the user specify an interface to use? */
2221 if (capture_opts->iface == NULL) {
2222 /* No - is a default specified in the preferences file? */
2223 if (prefs->capture_device != NULL) {
2225 capture_opts->iface = g_strdup(prefs->capture_device);
2227 /* No - pick the first one from the list of interfaces. */
2228 if_list = get_interface_list(&err, err_str);
2229 if (if_list == NULL) {
2232 case CANT_GET_INTERFACE_LIST:
2233 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2234 fprintf(stderr, "%s\n", cant_get_if_list_errstr);
2235 g_free(cant_get_if_list_errstr);
2238 case NO_INTERFACES_FOUND:
2239 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2244 if_info = if_list->data; /* first interface */
2245 capture_opts->iface = g_strdup(if_info->name);
2246 free_interface_list(if_list);
2251 if (list_link_layer_types) {
2252 /* Get the list of link-layer types for the capture device. */
2253 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2254 if (lt_list == NULL) {
2255 if (err_str[0] != '\0') {
2256 fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2257 "Please check to make sure you have sufficient permissions, and that\n"
2258 "you have the proper interface or pipe specified.\n", err_str);
2260 fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2263 fprintf(stderr, "Data link types (use option -y to set):\n");
2264 for (lt_entry = lt_list; lt_entry != NULL;
2265 lt_entry = g_list_next(lt_entry)) {
2266 data_link_info = lt_entry->data;
2267 fprintf(stderr, " %s", data_link_info->name);
2268 if (data_link_info->description != NULL)
2269 fprintf(stderr, " (%s)", data_link_info->description);
2271 fprintf(stderr, " (not supported)");
2274 free_pcap_linktype_list(lt_list);
2278 if (capture_opts->has_snaplen) {
2279 if (capture_opts->snaplen < 1)
2280 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2281 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2282 capture_opts->snaplen = MIN_PACKET_SIZE;
2285 /* Check the value range of the ringbuffer_num_files parameter */
2286 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2287 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2288 #if RINGBUFFER_MIN_NUM_FILES > 0
2289 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2290 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2292 #endif /* HAVE_LIBPCAP */
2294 /* Notify all registered modules that have had any of their preferences
2295 changed either from one of the preferences file or from the command
2296 line that their preferences have changed. */
2299 /* disabled protocols as per configuration file */
2300 if (gdp_path == NULL && dp_path == NULL) {
2301 set_disabled_protos_list();
2304 /* Build the column format array */
2305 col_setup(&cfile.cinfo, prefs->num_cols);
2306 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2307 cfile.cinfo.col_fmt[i] = get_column_format(i);
2308 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2309 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2311 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2312 cfile.cinfo.col_data[i] = NULL;
2313 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2314 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2316 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2317 cfile.cinfo.col_fence[i] = 0;
2318 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2319 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2322 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2325 for (j = 0; j < NUM_COL_FMTS; j++) {
2326 if (!cfile.cinfo.fmt_matx[i][j])
2329 if (cfile.cinfo.col_first[j] == -1)
2330 cfile.cinfo.col_first[j] = i;
2331 cfile.cinfo.col_last[j] = i;
2335 /* read in rc file from global and personal configuration paths. */
2336 rc_file = get_datafile_path(RC_FILE);
2337 gtk_rc_parse(rc_file);
2338 rc_file = get_persconffile_path(RC_FILE, FALSE);
2339 gtk_rc_parse(rc_file);
2342 font_init(capture_child);
2347 /* close the splash screen, as we are going to open the main window now */
2348 splash_destroy(splash_win);
2352 /* Is this a "child" ethereal, which is only supposed to pop up a
2353 capture box to let us stop the capture, and run a capture
2354 to a file that our parent will read? */
2355 if (capture_child) {
2356 /* This is the child process of a capture session,
2357 so just do the low-level work of a capture - don't create
2358 a temporary file and fork off *another* child process (so don't
2359 call "capture_start()"). */
2361 /* Pop up any queued-up alert boxes. */
2362 display_queued_messages();
2364 /* Now start the capture.
2365 After the capture is done; there's nothing more for us to do. */
2367 /* XXX - hand these stats to the parent process */
2368 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2372 /* capture failed */
2378 /***********************************************************************/
2379 /* Everything is prepared now, preferences and command line was read in,
2380 we are NOT a child window for a synced capture. */
2382 /* Pop up the main window. */
2383 create_main_window(pl_size, tv_size, bv_size, prefs);
2385 /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2386 recent_read_dynamic(&rf_path, &rf_open_errno);
2387 color_filters_enable(recent.packet_list_colorize);
2389 /* rearrange all the widgets as we now have all recent settings ready for this */
2390 main_widgets_rearrange();
2392 /* Fill in column titles. This must be done after the top level window
2395 XXX - is that still true, with fixed-width columns? */
2396 packet_list_set_column_titles();
2398 menu_recent_read_finished();
2400 switch (user_font_apply()) {
2403 case FA_FONT_NOT_RESIZEABLE:
2404 /* "user_font_apply()" popped up an alert box. */
2405 /* turn off zooming - font can't be resized */
2406 case FA_FONT_NOT_AVAILABLE:
2407 /* XXX - did we successfully load the un-zoomed version earlier?
2408 If so, this *probably* means the font is available, but not at
2409 this particular zoom level, but perhaps some other failure
2410 occurred; I'm not sure you can determine which is the case,
2412 /* turn off zooming - zoom level is unavailable */
2414 /* in any other case than FA_SUCCESS, turn off zooming */
2415 recent.gui_zoom_level = 0;
2416 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2419 dnd_init(top_level);
2422 color_filters_init();
2425 /* the window can be sized only, if it's not already shown, so do it now! */
2426 main_load_window_geometry(top_level);
2428 /* If we were given the name of a capture file, read it in now;
2429 we defer it until now, so that, if we can't open it, and pop
2430 up an alert box, the alert box is more likely to come up on
2431 top of the main window - but before the preference-file-error
2432 alert box, so, if we get one of those, it's more likely to come
2435 show_main_window(TRUE);
2436 if (rfilter != NULL) {
2437 if (!dfilter_compile(rfilter, &rfcode)) {
2438 bad_dfilter_alert_box(rfilter);
2439 rfilter_parse_failed = TRUE;
2442 if (!rfilter_parse_failed) {
2443 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2444 /* "cf_open()" succeeded, so it closed the previous
2445 capture file, and thus destroyed any previous read filter
2446 attached to "cf". */
2448 cfile.rfcode = rfcode;
2449 /* Open tap windows; we do so after creating the main window,
2450 to avoid GTK warnings, and after successfully opening the
2451 capture file, so we know we have something to tap, and
2452 after registering all dissectors, so that MATE will have
2453 registered its field array and we can have a filter with
2454 one of MATE's late-registered fields as part of the tap's
2456 start_requested_taps();
2458 /* Read the capture file. */
2459 switch (cf_read(&cfile)) {
2463 /* Just because we got an error, that doesn't mean we were unable
2464 to read any of the file; we handle what we could get from the
2466 /* if the user told us to jump to a specific packet, do it now */
2467 if(go_to_packet != 0) {
2468 cf_goto_frame(&cfile, go_to_packet);
2472 case CF_READ_ABORTED:
2477 /* Save the name of the containing directory specified in the
2478 path name, if any; we can write over cf_name, which is a
2479 good thing, given that "get_dirname()" does write over its
2481 s = get_dirname(cf_name);
2482 /* we might already set this from the recent file, don't overwrite this */
2483 if(get_last_open_dir() == NULL)
2484 set_last_open_dir(s);
2489 dfilter_free(rfcode);
2490 cfile.rfcode = NULL;
2491 set_menus_for_capture_in_progress(FALSE);
2496 if (start_capture) {
2497 if (capture_opts->save_file != NULL) {
2498 /* Save the directory name for future file dialogs. */
2499 /* (get_dirname overwrites filename) */
2500 s = get_dirname(g_strdup(capture_opts->save_file));
2501 set_last_open_dir(s);
2504 /* "-k" was specified; start a capture. */
2505 show_main_window(TRUE);
2506 if (capture_start(capture_opts)) {
2507 /* The capture started. Open tap windows; we do so after creating
2508 the main window, to avoid GTK warnings, and after successfully
2509 opening the capture file, so we know we have something to tap,
2510 and after registering all dissectors, so that MATE will have
2511 registered its field array and we can have a filter with
2512 one of MATE's late-registered fields as part of the tap's
2514 start_requested_taps();
2518 show_main_window(FALSE);
2519 set_menus_for_capture_in_progress(FALSE);
2522 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2523 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2524 if (capture_opts->cfilter) {
2525 g_free(capture_opts->cfilter);
2527 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2529 #else /* HAVE_LIBPCAP */
2530 show_main_window(FALSE);
2531 set_menus_for_capture_in_progress(FALSE);
2532 #endif /* HAVE_LIBPCAP */
2541 /* hide the (unresponsive) main window, while asking the user to close the console window */
2542 gtk_widget_hide(top_level);
2544 /* Shutdown windows sockets */
2547 /* For some unknown reason, the "atexit()" call in "create_console()"
2548 doesn't arrange that "destroy_console()" be called when we exit,
2549 so we call it here if a console was created. */
2555 /* This isn't reached, but we need it to keep GCC from complaining
2556 that "main()" returns without returning a value - it knows that
2557 "exit()" never returns, but it doesn't know that "gtk_exit()"
2558 doesn't, as GTK+ doesn't declare it with the attribute
2560 return 0; /* not reached */
2565 /* We build this as a GUI subsystem application on Win32, so
2566 "WinMain()", not "main()", gets called.
2568 Hack shamelessly stolen from the Win32 port of the GIMP. */
2570 #define _stdcall __attribute__((stdcall))
2574 WinMain (struct HINSTANCE__ *hInstance,
2575 struct HINSTANCE__ *hPrevInstance,
2579 has_console = FALSE;
2580 return main (__argc, __argv);
2584 * If this application has no console window to which its standard output
2585 * would go, create one.
2588 create_console(void)
2591 /* We have no console to which to print the version string, so
2592 create one and make it the standard input, output, and error. */
2593 if (!AllocConsole())
2594 return; /* couldn't create console */
2595 freopen("CONIN$", "r", stdin);
2596 freopen("CONOUT$", "w", stdout);
2597 freopen("CONOUT$", "w", stderr);
2599 /* Well, we have a console now. */
2602 /* Now register "destroy_console()" as a routine to be called just
2603 before the application exits, so that we can destroy the console
2604 after the user has typed a key (so that the console doesn't just
2605 disappear out from under them, giving the user no chance to see
2606 the message(s) we put in there). */
2607 atexit(destroy_console);
2612 destroy_console(void)
2615 printf("\n\nPress any key to exit\n");
2623 /* This routine should not be necessary, at least as I read the GLib
2624 source code, as it looks as if GLib is, on Win32, *supposed* to
2625 create a console window into which to display its output.
2627 That doesn't happen, however. I suspect there's something completely
2628 broken about that code in GLib-for-Win32, and that it may be related
2629 to the breakage that forces us to just call "printf()" on the message
2630 rather than passing the message on to "g_log_default_handler()"
2631 (which is the routine that does the aforementioned non-functional
2632 console window creation). */
2634 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2635 const char *message, gpointer user_data _U_)
2642 /* change this, if you want to see more verbose log output */
2643 /* XXX - make this a pref value */
2644 if( (log_level & G_LOG_LEVEL_MASK) > G_LOG_LEVEL_WARNING) {
2648 /* create a "timestamp" */
2650 today = localtime(&curr);
2653 if (prefs.gui_console_open != console_open_never) {
2657 /* For some unknown reason, the above doesn't appear to actually cause
2658 anything to be sent to the standard output, so we'll just splat the
2659 message out directly, just to make sure it gets out. */
2661 switch(log_level & G_LOG_LEVEL_MASK) {
2662 case G_LOG_LEVEL_ERROR:
2665 case G_LOG_LEVEL_CRITICAL:
2668 case G_LOG_LEVEL_WARNING:
2671 case G_LOG_LEVEL_MESSAGE:
2674 case G_LOG_LEVEL_INFO:
2677 case G_LOG_LEVEL_DEBUG:
2681 fprintf(stderr, "unknown log_level %u\n", log_level);
2683 g_assert_not_reached();
2686 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2687 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2688 today->tm_hour, today->tm_min, today->tm_sec,
2689 log_domain != NULL ? log_domain : "",
2693 g_log_default_handler(log_domain, log_level, message, user_data);
2699 GtkWidget *info_bar_new(void)
2701 /* tip: tooltips don't work on statusbars! */
2702 info_bar = gtk_statusbar_new();
2703 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2704 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2705 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2706 #if GTK_MAJOR_VERSION >= 2
2707 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2709 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2714 GtkWidget *packets_bar_new(void)
2716 /* tip: tooltips don't work on statusbars! */
2717 packets_bar = gtk_statusbar_new();
2718 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2719 packets_bar_update();
2726 * Helper for main_widgets_rearrange()
2728 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2729 gtk_container_remove(GTK_CONTAINER(data), widget);
2732 GtkWidget *main_widget_layout(gint layout_content)
2734 switch(layout_content) {
2735 case(layout_pane_content_none):
2738 case(layout_pane_content_plist):
2741 case(layout_pane_content_pdetails):
2744 case(layout_pane_content_pbytes):
2748 g_assert_not_reached();
2755 * Rearrange the main window widgets
2757 void main_widgets_rearrange(void) {
2758 GtkWidget *first_pane_widget1, *first_pane_widget2;
2759 GtkWidget *second_pane_widget1, *second_pane_widget2;
2760 gboolean split_top_left;
2762 /* be a bit faster */
2763 gtk_widget_hide(main_vbox);
2765 /* be sure, we don't loose a widget while rearranging */
2766 gtk_widget_ref(menubar);
2767 gtk_widget_ref(main_tb);
2768 gtk_widget_ref(filter_tb);
2769 gtk_widget_ref(pkt_scrollw);
2770 gtk_widget_ref(tv_scrollw);
2771 gtk_widget_ref(byte_nb_ptr);
2772 gtk_widget_ref(stat_hbox);
2773 gtk_widget_ref(info_bar);
2774 gtk_widget_ref(packets_bar);
2775 gtk_widget_ref(status_pane);
2776 gtk_widget_ref(main_pane_v1);
2777 gtk_widget_ref(main_pane_v2);
2778 gtk_widget_ref(main_pane_h1);
2779 gtk_widget_ref(main_pane_h2);
2780 gtk_widget_ref(welcome_pane);
2782 /* empty all containers participating */
2783 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2784 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2785 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2786 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2787 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2788 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2789 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2791 /* add the menubar always at the top */
2792 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2795 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2797 /* filter toolbar in toolbar area */
2798 if (!prefs.filter_toolbar_show_in_statusbar) {
2799 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2802 /* fill the main layout panes */
2803 switch(prefs.gui_layout_type) {
2804 case(layout_type_5):
2805 main_first_pane = main_pane_v1;
2806 main_second_pane = main_pane_v2;
2807 split_top_left = FALSE;
2809 case(layout_type_2):
2810 main_first_pane = main_pane_v1;
2811 main_second_pane = main_pane_h1;
2812 split_top_left = FALSE;
2814 case(layout_type_1):
2815 main_first_pane = main_pane_v1;
2816 main_second_pane = main_pane_h1;
2817 split_top_left = TRUE;
2819 case(layout_type_4):
2820 main_first_pane = main_pane_h1;
2821 main_second_pane = main_pane_v1;
2822 split_top_left = FALSE;
2824 case(layout_type_3):
2825 main_first_pane = main_pane_h1;
2826 main_second_pane = main_pane_v1;
2827 split_top_left = TRUE;
2829 case(layout_type_6):
2830 main_first_pane = main_pane_h1;
2831 main_second_pane = main_pane_h2;
2832 split_top_left = FALSE;
2835 main_first_pane = NULL;
2836 main_second_pane = NULL;
2837 split_top_left = FALSE;
2838 g_assert_not_reached();
2840 if (split_top_left) {
2841 first_pane_widget1 = main_second_pane;
2842 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2843 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2844 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2846 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2847 first_pane_widget2 = main_second_pane;
2848 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2849 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2851 if (first_pane_widget1 != NULL)
2852 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2853 if (first_pane_widget2 != NULL)
2854 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2855 if (second_pane_widget1 != NULL)
2856 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2857 if (second_pane_widget2 != NULL)
2858 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2860 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2863 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2865 /* statusbar hbox */
2866 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2868 /* filter toolbar in statusbar hbox */
2869 if (prefs.filter_toolbar_show_in_statusbar) {
2870 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2874 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2875 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2876 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2878 /* hide widgets on users recent settings */
2879 main_widgets_show_or_hide();
2881 gtk_widget_show(main_vbox);
2885 is_widget_visible(GtkWidget *widget, gpointer data)
2887 gboolean *is_visible = data;
2890 if (GTK_WIDGET_VISIBLE(widget))
2897 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2898 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2900 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2902 GtkWidget *w, *item_hb;
2903 #if GTK_MAJOR_VERSION >= 2
2904 gchar *formatted_message;
2908 item_hb = gtk_hbox_new(FALSE, 1);
2910 w = BUTTON_NEW_FROM_STOCK(stock_item);
2911 WIDGET_SET_SIZE(w, 60, 60);
2912 #if GTK_MAJOR_VERSION >= 2
2913 gtk_button_set_label(GTK_BUTTON(w), label);
2915 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
2916 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
2918 w = gtk_label_new(message);
2919 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2920 #if GTK_MAJOR_VERSION >= 2
2921 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
2922 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
2923 g_free(formatted_message);
2926 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
2932 /* XXX - the layout has to be improved */
2936 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
2937 GtkWidget *w, *icon;
2941 welcome_scrollw = scrolled_window_new(NULL, NULL);
2943 welcome_hb = gtk_hbox_new(FALSE, 1);
2944 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
2946 welcome_vb = gtk_vbox_new(FALSE, 1);
2948 item_hb = gtk_hbox_new(FALSE, 1);
2950 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
2951 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
2953 #if GTK_MAJOR_VERSION < 2
2954 message = "Welcome to Ethereal!";
2956 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
2958 w = gtk_label_new(message);
2959 #if GTK_MAJOR_VERSION >= 2
2960 gtk_label_set_markup(GTK_LABEL(w), message);
2962 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2963 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
2965 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2967 w = gtk_label_new("What would you like to do?");
2968 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
2969 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
2972 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
2974 "Capture live data from your network",
2975 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
2976 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2979 item_hb = welcome_item(GTK_STOCK_OPEN,
2981 "Open a previously captured file",
2982 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
2983 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2985 #if (GLIB_MAJOR_VERSION >= 2)
2986 item_hb = welcome_item(GTK_STOCK_HOME,
2988 "Visit the Ethereal homepage",
2989 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
2990 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2994 w = gtk_label_new("");
2995 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
2997 w = gtk_label_new("");
2998 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3000 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3002 w = gtk_label_new("");
3003 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3005 gtk_widget_show_all(welcome_hb);
3007 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3009 gtk_widget_show_all(welcome_scrollw);
3011 return welcome_scrollw;
3018 /* this is just a dummy to fill up window space, simply showing nothing */
3019 return scrolled_window_new(NULL, NULL);
3025 * XXX - this doesn't appear to work with the paned widgets in
3026 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3027 * and the other pane doesn't grow to take up the rest of the pane.
3028 * It does appear to work with GTK+ 2.x.
3031 main_widgets_show_or_hide(void)
3033 gboolean main_second_pane_show;
3035 if (recent.main_toolbar_show) {
3036 gtk_widget_show(main_tb);
3038 gtk_widget_hide(main_tb);
3042 * Show the status hbox if either:
3044 * 1) we're showing the filter toolbar and we want it in the status
3049 * 2) we're showing the status bar.
3051 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3052 recent.statusbar_show) {
3053 gtk_widget_show(stat_hbox);
3055 gtk_widget_hide(stat_hbox);
3058 if (recent.statusbar_show) {
3059 gtk_widget_show(status_pane);
3061 gtk_widget_hide(status_pane);
3064 if (recent.filter_toolbar_show) {
3065 gtk_widget_show(filter_tb);
3067 gtk_widget_hide(filter_tb);
3070 if (recent.packet_list_show && have_capture_file) {
3071 gtk_widget_show(pkt_scrollw);
3073 gtk_widget_hide(pkt_scrollw);
3076 if (recent.tree_view_show && have_capture_file) {
3077 gtk_widget_show(tv_scrollw);
3079 gtk_widget_hide(tv_scrollw);
3082 if (recent.byte_view_show && have_capture_file) {
3083 gtk_widget_show(byte_nb_ptr);
3085 gtk_widget_hide(byte_nb_ptr);
3088 if (have_capture_file) {
3089 gtk_widget_show(main_first_pane);
3091 gtk_widget_hide(main_first_pane);
3095 * Is anything in "main_second_pane" visible?
3096 * If so, show it, otherwise hide it.
3098 main_second_pane_show = FALSE;
3099 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3100 &main_second_pane_show);
3101 if (main_second_pane_show) {
3102 gtk_widget_show(main_second_pane);
3104 gtk_widget_hide(main_second_pane);
3107 if (!have_capture_file) {
3109 gtk_widget_show(welcome_pane);
3112 gtk_widget_hide(welcome_pane);
3117 #if GTK_MAJOR_VERSION >= 2
3118 /* called, when the window state changes (minimized, maximized, ...) */
3120 window_state_event_cb (GtkWidget *widget _U_,
3124 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3126 if( (event->type) == (GDK_WINDOW_STATE)) {
3127 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3128 /* we might have dialogs popped up while we where iconified,
3130 display_queued_messages();
3139 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3142 *filter_bt, *filter_cm, *filter_te,
3143 *filter_add_expr_bt,
3146 GList *dfilter_list = NULL;
3147 GtkTooltips *tooltips;
3148 GtkAccelGroup *accel;
3150 /* Display filter construct dialog has an Apply button, and "OK" not
3151 only sets our text widget, it activates it (i.e., it causes us to
3152 filter the capture). */
3153 static construct_args_t args = {
3154 "Ethereal: Display Filter",
3159 /* use user-defined title if preference is set */
3160 title = create_user_window_title("The Ethereal Network Analyzer");
3163 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3166 tooltips = gtk_tooltips_new();
3169 #if GTK_MAJOR_VERSION < 2
3170 /* has to be done, after top_level window is created */
3171 app_font_gtk1_init(top_level);
3175 gtk_widget_set_name(top_level, "main window");
3176 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3178 #if GTK_MAJOR_VERSION >= 2
3179 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3180 G_CALLBACK (window_state_event_cb), NULL);
3183 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3185 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3186 main_vbox = gtk_vbox_new(FALSE, 1);
3187 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3188 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3189 gtk_widget_show(main_vbox);
3192 menubar = main_menu_new(&accel);
3193 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3194 gtk_widget_show(menubar);
3197 main_tb = toolbar_new();
3198 gtk_widget_show (main_tb);
3201 pkt_scrollw = packet_list_new(prefs);
3202 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3203 gtk_widget_show(pkt_scrollw);
3206 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3207 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3208 gtk_widget_show(tv_scrollw);
3210 #if GTK_MAJOR_VERSION < 2
3211 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3212 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3215 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3216 "changed", tree_view_selection_changed_cb, NULL);
3218 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3219 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3220 gtk_widget_show(tree_view);
3223 byte_nb_ptr = byte_view_new();
3224 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3225 gtk_widget_show(byte_nb_ptr);
3227 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3228 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3231 /* Panes for the packet list, tree, and byte view */
3232 main_pane_v1 = gtk_vpaned_new();
3233 gtk_widget_show(main_pane_v1);
3234 main_pane_v2 = gtk_vpaned_new();
3235 gtk_widget_show(main_pane_v2);
3236 main_pane_h1 = gtk_hpaned_new();
3237 gtk_widget_show(main_pane_h1);
3238 main_pane_h2 = gtk_hpaned_new();
3239 gtk_widget_show(main_pane_h2);
3241 /* filter toolbar */
3242 #if GTK_MAJOR_VERSION < 2
3243 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3246 filter_tb = gtk_toolbar_new();
3247 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3248 GTK_ORIENTATION_HORIZONTAL);
3249 #endif /* GTK_MAJOR_VERSION */
3250 gtk_widget_show(filter_tb);
3252 /* Create the "Filter:" button */
3253 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3254 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3255 gtk_widget_show(filter_bt);
3256 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3258 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3259 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3261 /* Create the filter combobox */
3262 filter_cm = gtk_combo_new();
3263 dfilter_list = NULL;
3264 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3265 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3266 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3267 filter_te = GTK_COMBO(filter_cm)->entry;
3268 main_display_filter_widget=filter_te;
3269 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3270 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3271 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3272 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3273 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3274 WIDGET_SET_SIZE(filter_cm, 400, -1);
3275 gtk_widget_show(filter_cm);
3276 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3278 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3279 gtk_tooltips_set_tip(tooltips, filter_te,
3280 "Enter a display filter, or choose one of your recently used filters. "
3281 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3284 /* Create the "Add Expression..." button, to pop up a dialog
3285 for constructing filter comparison expressions. */
3286 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3287 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3288 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3289 gtk_widget_show(filter_add_expr_bt);
3290 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3291 "Add an expression to this filter string", "Private");
3293 /* Create the "Clear" button */
3294 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3295 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3296 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3297 gtk_widget_show(filter_reset);
3298 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3299 "Clear this filter string and update the display", "Private");
3301 /* Create the "Apply" button */
3302 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3303 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3304 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3305 gtk_widget_show(filter_apply);
3306 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3307 "Apply this filter string to the display", "Private");
3309 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3310 * of any widget that ends up calling a callback which needs
3311 * that text entry pointer */
3312 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3313 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3315 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3317 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3319 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3321 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3323 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3325 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3327 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3329 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3331 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3333 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3335 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3337 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3339 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3341 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3342 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3343 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3345 /* info (main) statusbar */
3346 info_bar = info_bar_new();
3347 gtk_widget_show(info_bar);
3349 /* packets statusbar */
3350 packets_bar = packets_bar_new();
3351 gtk_widget_show(packets_bar);
3353 /* Filter/status hbox */
3354 stat_hbox = gtk_hbox_new(FALSE, 1);
3355 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3356 gtk_widget_show(stat_hbox);
3358 /* Pane for the statusbar */
3359 status_pane = gtk_hpaned_new();
3360 gtk_widget_show(status_pane);
3362 /* Pane for the welcome screen */
3363 welcome_pane = welcome_new();
3364 gtk_widget_show(welcome_pane);
3368 show_main_window(gboolean doing_work)
3370 main_set_for_capture_file(doing_work);
3372 /*** we have finished all init things, show the main window ***/
3373 gtk_widget_show(top_level);
3375 /* the window can be maximized only, if it's visible, so do it after show! */
3376 main_load_window_geometry(top_level);
3378 /* process all pending GUI events before continue */
3379 while (gtk_events_pending()) gtk_main_iteration();
3381 /* Pop up any queued-up alert boxes. */
3382 display_queued_messages();