5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@ethereal.com>
7 * Copyright 1998 Gerald Combs
9 * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10 * needed by dissect routines
11 * Jeff Foster, 2001/03/12, added support tabbed hex display windowss
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #include <io.h> /* open/close on win32 */
46 #ifdef NEED_STRERROR_H
54 #ifdef _WIN32 /* Needed for console I/O */
59 #include <epan/epan.h>
60 #include <epan/filesystem.h>
61 #include <epan/epan_dissect.h>
62 #include <epan/timestamp.h>
63 #include <epan/packet.h>
64 #include <epan/plugins.h>
65 #include <epan/dfilter/dfilter.h>
66 #include <epan/strutil.h>
67 #include <epan/addr_resolv.h>
68 #include <epan/emem.h>
70 /* general (not GTK specific) */
74 #include "disabled_protos.h"
75 #include <epan/prefs.h>
76 #include "filter_dlg.h"
77 #include "layout_prefs.h"
79 #include "color_filters.h"
81 #include "simple_dialog.h"
83 #include <epan/prefs-int.h>
84 #include "ringbuffer.h"
85 #include "../ui_util.h"
87 #include <epan/stat_cmd_args.h>
89 #include "clopts_common.h"
90 #include "version_info.h"
95 #include "pcap-util.h"
100 #include "capture-wpcap.h"
101 #include "capture_wpcap_packet.h"
104 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
105 #include "ethclist.h"
109 #include "statusbar.h"
110 #include "alert_box.h"
111 #include "dlg_utils.h"
112 #include "gtkglobals.h"
114 #include "gui_utils.h"
115 #include "compat_macros.h"
119 #include "../main_window.h"
121 #include "file_dlg.h"
122 #include <epan/column.h>
123 #include "proto_draw.h"
125 #include "packet_win.h"
127 #include "find_dlg.h"
128 #include "packet_list.h"
130 #include "follow_dlg.h"
131 #include "font_utils.h"
132 #include "about_dlg.h"
133 #include "help_dlg.h"
134 #include "decode_as_dlg.h"
135 #include "webbrowser.h"
136 #include "capture_dlg.h"
138 #include "../image/eicon3d64.xpm"
140 #include "capture_ui_utils.h"
142 #include "../epan/emem.h"
147 * Files under personal and global preferences directories in which
148 * GTK settings for Ethereal are stored.
150 #define RC_FILE "gtkrc"
153 #define DEF_READY_MESSAGE " Ready to load or capture"
155 #define DEF_READY_MESSAGE " Ready to load file"
159 GtkWidget *main_display_filter_widget=NULL;
160 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
161 static GtkWidget *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
162 static GtkWidget *main_first_pane, *main_second_pane;
163 static GtkWidget *status_pane;
164 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
165 static GtkWidget *info_bar;
166 static GtkWidget *packets_bar = NULL;
167 static GtkWidget *welcome_pane;
168 static guint main_ctx, file_ctx, help_ctx;
169 static guint packets_ctx;
170 static gchar *packets_str = NULL;
171 GString *comp_info_str, *runtime_info_str;
172 gchar *ethereal_path = NULL;
173 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
175 gboolean capture_child; /* True if this is the child for "-S" */
177 static gboolean has_console; /* TRUE if app has console */
178 static void destroy_console(void);
180 static void console_log_handler(const char *log_domain,
181 GLogLevelFlags log_level, const char *message, gpointer user_data);
184 static gboolean list_link_layer_types;
185 capture_options global_capture_opts;
186 capture_options *capture_opts = &global_capture_opts;
190 static void create_main_window(gint, gint, gint, e_prefs*);
191 static void show_main_window(gboolean);
192 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
193 static void main_save_window_geometry(GtkWidget *widget);
195 #define E_DFILTER_CM_KEY "display_filter_combo"
196 #define E_DFILTER_FL_KEY "display_filter_list"
200 /* Match selected byte pattern */
202 match_selected_cb_do(gpointer data, int action, gchar *text)
204 GtkWidget *filter_te;
205 char *cur_filter, *new_filter;
210 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
213 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
215 switch (action&MATCH_SELECTED_MASK) {
217 case MATCH_SELECTED_REPLACE:
218 new_filter = g_strdup(text);
221 case MATCH_SELECTED_AND:
222 if ((!cur_filter) || (0 == strlen(cur_filter)))
223 new_filter = g_strdup(text);
225 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
228 case MATCH_SELECTED_OR:
229 if ((!cur_filter) || (0 == strlen(cur_filter)))
230 new_filter = g_strdup(text);
232 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
235 case MATCH_SELECTED_NOT:
236 new_filter = g_strconcat("!(", text, ")", NULL);
239 case MATCH_SELECTED_AND_NOT:
240 if ((!cur_filter) || (0 == strlen(cur_filter)))
241 new_filter = g_strconcat("!(", text, ")", NULL);
243 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
246 case MATCH_SELECTED_OR_NOT:
247 if ((!cur_filter) || (0 == strlen(cur_filter)))
248 new_filter = g_strconcat("!(", text, ")", NULL);
250 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
254 g_assert_not_reached();
259 /* Free up the copy we got of the old filter text. */
262 /* create a new one and set the display filter entry accordingly */
263 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
265 /* Run the display filter so it goes in effect. */
266 if (action&MATCH_SELECTED_APPLY_NOW)
267 main_filter_packets(&cfile, new_filter, FALSE);
269 /* Free up the new filter text. */
274 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
276 if (cfile.finfo_selected)
277 match_selected_cb_do((data ? data : w),
279 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
283 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
285 gchar *selected_proto_url;
286 gchar *proto_abbrev = data;
291 if (cfile.finfo_selected) {
292 /* open wiki page using the protocol abbreviation */
293 selected_proto_url = g_strdup_printf("http://wiki.ethereal.com/Protocols/%s", proto_abbrev);
294 browser_open_url(selected_proto_url);
295 g_free(selected_proto_url);
298 case(ESD_BTN_CANCEL):
301 g_assert_not_reached();
307 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
310 const gchar *proto_abbrev;
314 if (cfile.finfo_selected) {
315 /* convert selected field to protocol abbreviation */
316 /* XXX - could this conversion be simplified? */
317 field_id = cfile.finfo_selected->hfinfo->id;
318 /* if the selected field isn't a protocol, get it's parent */
319 if(!proto_registrar_is_protocol(field_id)) {
320 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
323 proto_abbrev = proto_registrar_get_abbrev(field_id);
325 /* ask the user if the wiki page really should be opened */
326 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
327 PRIMARY_TEXT_START "Open Ethereal Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
329 "This will open the \"%s\" related Ethereal Wiki page in your Web browser.\n"
331 "The Ethereal Wiki is a collaborative approach to provide information\n"
332 "about Ethereal in several ways (not limited to protocol specifics).\n"
334 "This Wiki is new, so the page of the selected protocol\n"
335 "may not exist and/or may not contain valuable information.\n"
337 "As everyone can edit the Wiki and add new content (or extend existing),\n"
338 "you are encouraged to add information if you can.\n"
340 "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
342 "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
343 "which will save you a lot of editing and will give a consistent look over the pages.",
344 proto_abbrev, proto_abbrev);
345 simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, (gpointer) proto_abbrev);
351 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
354 const gchar *proto_abbrev;
355 gchar *selected_proto_url;
358 if (cfile.finfo_selected) {
359 /* convert selected field to protocol abbreviation */
360 /* XXX - could this conversion be simplified? */
361 field_id = cfile.finfo_selected->hfinfo->id;
362 /* if the selected field isn't a protocol, get it's parent */
363 if(!proto_registrar_is_protocol(field_id)) {
364 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
367 proto_abbrev = proto_registrar_get_abbrev(field_id);
369 /* open reference page using the protocol abbreviation */
370 selected_proto_url = g_strdup_printf("http://www.ethereal.com/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
371 browser_open_url(selected_proto_url);
372 g_free(selected_proto_url);
378 get_text_from_packet_list(gpointer data)
380 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
381 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
382 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
390 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
391 cfile.pd, fdata->cap_len, &err, &err_info)) {
392 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
393 cf_read_error_message(err, err_info), cfile.filename);
397 edt = epan_dissect_new(FALSE, FALSE);
398 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
400 epan_dissect_fill_in_columns(edt);
402 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
403 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
404 len = strlen(cfile.cinfo.col_expr[column]) +
405 strlen(cfile.cinfo.col_expr_val[column]) + 5;
406 buf = ep_alloc0(len);
407 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
408 cfile.cinfo.col_expr_val[column]);
411 epan_dissect_free(edt);
418 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
420 match_selected_cb_do(data,
422 get_text_from_packet_list(data));
427 /* XXX: use a preference for this setting! */
428 static guint dfilter_combo_max_recent = 10;
430 /* add a display filter to the combo box */
431 /* Note: a new filter string will replace an old identical one */
433 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
435 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
438 /* GtkCombos don't let us get at their list contents easily, so we maintain
439 our own filter list, and feed it to gtk_combo_set_popdown_strings when
440 a new filter is added. */
441 li = g_list_first(dfilter_list);
443 /* If the filter is already in the list, remove the old one and
444 * append the new one at the latest position (at g_list_append() below) */
445 if (li->data && strcmp(s, li->data) == 0) {
446 dfilter_list = g_list_remove(dfilter_list, li->data);
452 dfilter_list = g_list_append(dfilter_list, s);
453 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
454 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), dfilter_list);
455 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(dfilter_list)->data);
461 /* write all non empty display filters (until maximum count)
462 * of the combo box GList to the user's recent file */
464 dfilter_recent_combo_write_all(FILE *rf) {
465 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
466 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
471 /* write all non empty display filter strings to the recent file (until max count) */
472 li = g_list_first(dfilter_list);
473 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
474 if (strlen(li->data)) {
475 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
481 /* empty the combobox entry field */
483 dfilter_combo_add_empty(void) {
484 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
486 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
490 /* add a display filter coming from the user's recent file to the dfilter combo box */
492 dfilter_combo_add_recent(gchar *s) {
493 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
497 if (!dfilter_combo_add(filter_cm, dup)) {
506 /* call cf_filter_packets() and add this filter string to the recent filter list */
508 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
510 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
511 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
513 gboolean add_filter = TRUE;
514 gboolean free_filter = TRUE;
516 cf_status_t cf_status;
518 /* we'll crash later on if dftext is NULL */
519 g_assert(dftext != NULL);
521 s = g_strdup(dftext);
523 /* GtkCombos don't let us get at their list contents easily, so we maintain
524 our own filter list, and feed it to gtk_combo_set_popdown_strings when
525 a new filter is added. */
526 cf_status = cf_filter_packets(cf, s, force);
527 if (cf_status == CF_OK) {
528 li = g_list_first(dfilter_list);
530 if (li->data && strcmp(s, li->data) == 0)
536 /* trim list size first */
537 while (g_list_length(dfilter_list) >= dfilter_combo_max_recent) {
538 dfilter_list = g_list_remove(dfilter_list, g_list_first(dfilter_list)->data);
542 dfilter_list = g_list_append(dfilter_list, s);
543 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
544 gtk_combo_set_popdown_strings(filter_cm, dfilter_list);
545 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(dfilter_list)->data);
551 return (cf_status == CF_OK);
555 /* Run the current display filter on the current packet set, and
558 filter_activate_cb(GtkWidget *w _U_, gpointer data)
562 s = gtk_entry_get_text(GTK_ENTRY(data));
564 main_filter_packets(&cfile, s, FALSE);
567 /* redisplay with no display filter */
569 filter_reset_cb(GtkWidget *w, gpointer data _U_)
571 GtkWidget *filter_te = NULL;
573 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
574 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
576 main_filter_packets(&cfile, "", FALSE);
579 /* mark as reference time frame */
581 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
585 frame->flags.ref_time=1;
587 frame->flags.ref_time=0;
589 cf_reftime_packets(&cfile);
593 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
598 if (cfile.current_frame) {
599 /* XXX hum, should better have a "cfile->current_row" here ... */
600 set_frame_reftime(!cfile.current_frame->flags.ref_time,
602 packet_list_find_row_from_data(cfile.current_frame));
605 case REFTIME_FIND_NEXT:
606 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
608 case REFTIME_FIND_PREV:
609 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
614 #if GTK_MAJOR_VERSION < 2
616 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
617 gpointer user_data _U_)
620 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
624 gchar *help_str = NULL;
625 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
627 gboolean has_blurb = FALSE;
628 guint length = 0, byte_len;
629 GtkWidget *byte_view;
630 const guint8 *byte_data;
631 #if GTK_MAJOR_VERSION >= 2
636 #if GTK_MAJOR_VERSION >= 2
637 /* if nothing is selected */
638 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
641 * Which byte view is displaying the current protocol tree
644 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
645 if (byte_view == NULL)
648 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
649 if (byte_data == NULL)
652 cf_unselect_field(&cfile);
653 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
654 cfile.current_frame, NULL, byte_len);
657 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
660 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
664 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
666 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
667 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
668 g_assert(byte_data != NULL);
670 cfile.finfo_selected = finfo;
671 set_menus_for_selected_tree_row(&cfile);
674 if (finfo->hfinfo->blurb != NULL &&
675 finfo->hfinfo->blurb[0] != '\0') {
677 length = strlen(finfo->hfinfo->blurb);
679 length = strlen(finfo->hfinfo->name);
681 if (finfo->length == 0) {
683 } else if (finfo->length == 1) {
684 strcpy (len_str, ", 1 byte");
686 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
688 statusbar_pop_field_msg(); /* get rid of current help msg */
690 help_str = g_strdup_printf("%s (%s)%s",
691 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
692 finfo->hfinfo->abbrev, len_str);
693 statusbar_push_field_msg(help_str);
697 * Don't show anything if the field name is zero-length;
698 * the pseudo-field for "proto_tree_add_text()" is such
699 * a field, and we don't want "Text (text)" showing up
700 * on the status line if you've selected such a field.
702 * XXX - there are zero-length fields for which we *do*
703 * want to show the field name.
705 * XXX - perhaps the name and abbrev field should be null
706 * pointers rather than null strings for that pseudo-field,
707 * but we'd have to add checks for null pointers in some
708 * places if we did that.
710 * Or perhaps protocol tree items added with
711 * "proto_tree_add_text()" should have -1 as the field index,
712 * with no pseudo-field being used, but that might also
713 * require special checks for -1 to be added.
715 statusbar_push_field_msg("");
719 #if GTK_MAJOR_VERSION < 2
720 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
723 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
728 #if GTK_MAJOR_VERSION < 2
730 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
731 gpointer user_data _U_)
733 GtkWidget *byte_view;
738 * Which byte view is displaying the current protocol tree
741 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
742 if (byte_view == NULL)
745 data = get_byte_view_data_and_length(byte_view, &len);
749 cf_unselect_field(&cfile);
750 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
755 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
757 collapse_all_tree(cfile.edt->tree, tree_view);
760 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
762 expand_all_tree(cfile.edt->tree, tree_view);
765 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
766 #if GTK_MAJOR_VERSION < 2
772 #if GTK_MAJOR_VERSION < 2
773 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
775 /* the mouse position is at an entry, expand that one */
776 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
779 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
781 /* the mouse position is at an entry, expand that one */
782 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
783 gtk_tree_path_free(path);
788 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
789 if (cfile.edt->tree) {
790 guint32 tmp = g_resolv_flags;
791 g_resolv_flags = RESOLV_ALL;
792 proto_tree_draw(cfile.edt->tree, tree_view);
793 g_resolv_flags = tmp;
798 * Push a message referring to file access onto the statusbar.
801 statusbar_push_file_msg(gchar *msg)
803 /*g_warning("statusbar_push: %s", msg);*/
804 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
808 * Pop a message referring to file access off the statusbar.
811 statusbar_pop_file_msg(void)
813 /*g_warning("statusbar_pop");*/
814 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
818 * XXX - do we need multiple statusbar contexts?
822 * Push a message referring to the currently-selected field onto the statusbar.
825 statusbar_push_field_msg(gchar *msg)
827 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
831 * Pop a message referring to the currently-selected field off the statusbar.
834 statusbar_pop_field_msg(void)
836 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
840 * update the packets statusbar to the current values
842 void packets_bar_update(void)
846 /* remove old status */
849 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
852 /* do we have any packets? */
854 if(cfile.drops_known) {
855 packets_str = g_strdup_printf(" P: %u D: %u M: %u Drops: %u",
856 cfile.count, cfile.displayed_count, cfile.marked_count, cfile.drops);
858 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
859 cfile.count, cfile.displayed_count, cfile.marked_count);
862 packets_str = g_strdup(" No Packets");
864 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
869 main_set_for_capture_file(gboolean have_capture_file_in)
871 have_capture_file = have_capture_file_in;
873 main_widgets_show_or_hide();
879 /* get the current geometry, before writing it to disk */
880 main_save_window_geometry(top_level);
882 /* write user's recent file to disk
883 * It is no problem to write this file, even if we do not quit */
886 /* XXX - should we check whether the capture file is an
887 unsaved temporary file for a live capture and, if so,
888 pop up a "do you want to exit without saving the capture
889 file?" dialog, and then just return, leaving said dialog
890 box to forcibly quit if the user clicks "OK"?
892 If so, note that this should be done in a subroutine that
893 returns TRUE if we do so, and FALSE otherwise, and if it
894 returns TRUE we should return TRUE without nuking anything.
896 Note that, if we do that, we might also want to check if
897 an "Update list of packets in real time" capture is in
898 progress and, if so, ask whether they want to terminate
899 the capture and discard it, and return TRUE, before nuking
900 any child capture, if they say they don't want to do so. */
903 /* Nuke any child capture in progress. */
904 capture_kill_child(capture_opts);
907 /* Are we in the middle of reading a capture? */
908 if (cfile.state == FILE_READ_IN_PROGRESS) {
909 /* Yes, so we can't just close the file and quit, as
910 that may yank the rug out from under the read in
911 progress; instead, just set the state to
912 "FILE_READ_ABORTED" and return - the code doing the read
913 will check for that and, if it sees that, will clean
915 cfile.state = FILE_READ_ABORTED;
917 /* Say that the window should *not* be deleted;
918 that'll be done by the code that cleans up. */
921 /* Close any capture file we have open; on some OSes, you
922 can't unlink a temporary capture file if you have it
924 "cf_close()" will unlink it after closing it if
925 it's a temporary file.
927 We do this here, rather than after the main loop returns,
928 as, after the main loop returns, the main window may have
929 been destroyed (if this is called due to a "destroy"
930 even on the main window rather than due to the user
931 selecting a menu item), and there may be a crash
932 or other problem when "cf_close()" tries to
933 clean up stuff in the main window.
935 XXX - is there a better place to put this?
936 Or should we have a routine that *just* closes the
937 capture file, and doesn't do anything with the UI,
938 which we'd call here, and another routine that
939 calls that routine and also cleans up the UI, which
940 we'd call elsewhere? */
943 /* Exit by leaving the main loop, so that any quit functions
944 we registered get called. */
947 /* Say that the window should be deleted. */
953 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
957 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
958 #if GTK_MAJOR_VERSION >= 2
959 gtk_window_present(GTK_WINDOW(top_level));
961 /* user didn't saved his current file, ask him */
962 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
963 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
964 "If you quit the program without saving, your capture data will be discarded.");
965 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
968 /* unchanged file, just exit */
969 /* "main_do_quit()" indicates whether the main window should be deleted. */
970 return main_do_quit();
977 main_load_window_geometry(GtkWidget *widget)
979 window_geometry_t geom;
981 geom.set_pos = prefs.gui_geometry_save_position;
982 geom.x = recent.gui_geometry_main_x;
983 geom.y = recent.gui_geometry_main_y;
984 geom.set_size = prefs.gui_geometry_save_size;
985 if (recent.gui_geometry_main_width > 0 &&
986 recent.gui_geometry_main_height > 0) {
987 geom.width = recent.gui_geometry_main_width;
988 geom.height = recent.gui_geometry_main_height;
989 geom.set_maximized = prefs.gui_geometry_save_maximized;
991 /* We assume this means the width and height weren't set in
992 the "recent" file (or that there is no "recent" file),
993 and weren't set to a default value, so we don't set the
994 size. (The "recent" file code rejects non-positive width
995 and height values.) */
996 geom.set_size = FALSE;
998 geom.maximized = recent.gui_geometry_main_maximized;
1000 window_set_geometry(widget, &geom);
1002 if (recent.has_gui_geometry_main_upper_pane && recent.gui_geometry_main_upper_pane)
1003 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
1004 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_main_lower_pane)
1005 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
1006 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_status_pane)
1007 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
1012 main_save_window_geometry(GtkWidget *widget)
1014 window_geometry_t geom;
1016 window_get_geometry(widget, &geom);
1018 if (prefs.gui_geometry_save_position) {
1019 recent.gui_geometry_main_x = geom.x;
1020 recent.gui_geometry_main_y = geom.y;
1023 if (prefs.gui_geometry_save_size) {
1024 recent.gui_geometry_main_width = geom.width,
1025 recent.gui_geometry_main_height = geom.height;
1028 #if GTK_MAJOR_VERSION >= 2
1029 if(prefs.gui_geometry_save_maximized) {
1030 recent.gui_geometry_main_maximized = geom.maximized;
1033 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
1034 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
1035 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
1039 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1043 /* save file first */
1044 file_save_as_cmd(after_save_exit, NULL);
1046 case(ESD_BTN_DONT_SAVE):
1049 case(ESD_BTN_CANCEL):
1052 g_assert_not_reached();
1057 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1061 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1062 /* user didn't saved his current file, ask him */
1063 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1064 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1065 "If you quit the program without saving, your capture data will be discarded.");
1066 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1068 /* unchanged file, just exit */
1074 print_usage(gboolean print_ver) {
1084 fprintf(output, "This is "PACKAGE " " VERSION "%s"
1085 "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
1087 svnversion, comp_info_str->str, runtime_info_str->str);
1092 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);
1093 fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
1094 fprintf(output, "\t[ -B capture buffer size (Win32 only) ]\n");
1095 fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
1096 fprintf(output, "\t[ -g <packet number> ]\n");
1097 fprintf(output, "\t[ -i <capture interface> ] [ -m <font> ] [ -N <name resolving flags> ]\n");
1098 fprintf(output, "\t[ -o <preference/recent setting> ] ...\n");
1099 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
1100 fprintf(output, "\t[ -t <time stamp format> ]\n");
1101 fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
1102 fprintf(output, "\t[ <infile> ]\n");
1104 fprintf(output, "\n%s [ -vh ] [ -n ] [ -g <packet number> ] [ -m <font> ]\n", PACKAGE);
1105 fprintf(output, "\t[ -N <resolving flags> ] [ -o <preference/recent setting> ...\n");
1106 fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ]\n");
1107 fprintf(output, "\t[ -t <time stamp format> ]\n");
1108 fprintf(output, "\t[ -z <statistics ] [ <infile> ]\n");
1123 printf(PACKAGE " " VERSION "%s\n\n%s\n\n%s\n",
1124 svnversion, comp_info_str->str, runtime_info_str->str);
1131 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1133 Once every 3 seconds we get a callback here which we use to update
1134 the tap extensions. Since Gtk1 is single threaded we dont have to
1135 worry about any locking or critical regions.
1138 update_cb(gpointer data _U_)
1140 draw_tap_listeners(FALSE);
1145 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1146 use threads all updte_thread_mutex can be dropped and protect/unprotect
1147 would just be empty functions.
1149 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1150 gtk1-ethereal and it will just work.
1152 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1154 update_thread(gpointer data _U_)
1158 g_get_current_time(&tv1);
1159 g_static_mutex_lock(&update_thread_mutex);
1160 gdk_threads_enter();
1161 draw_tap_listeners(FALSE);
1162 gdk_threads_leave();
1163 g_static_mutex_unlock(&update_thread_mutex);
1165 g_get_current_time(&tv2);
1166 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1167 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1168 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1169 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1176 protect_thread_critical_region(void)
1178 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1179 g_static_mutex_lock(&update_thread_mutex);
1183 unprotect_thread_critical_region(void)
1185 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1186 g_static_mutex_unlock(&update_thread_mutex);
1190 /* Set the file name in the status line, in the name for the main window,
1191 and in the name for the main window's icon. */
1193 set_display_filename(capture_file *cf)
1195 const gchar *name_ptr;
1200 name_ptr = cf_get_display_name(cf);
1202 if (!cf->is_tempfile && cf->filename) {
1203 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1204 add_menu_recent_capture_file(cf->filename);
1207 /* convert file size */
1208 if (cf->f_datalen/1024/1024 > 10) {
1209 size_str = g_strdup_printf("%ld MB", cf->f_datalen/1024/1024);
1210 } else if (cf->f_datalen/1024 > 10) {
1211 size_str = g_strdup_printf("%ld KB", cf->f_datalen/1024);
1213 size_str = g_strdup_printf("%ld Bytes", cf->f_datalen);
1217 status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu",
1218 (cf->filename) ? cf->filename : "", size_str,
1219 (long)cf->elapsed_time.secs/3600,
1220 (long)cf->elapsed_time.secs%3600/60,
1221 (long)cf->elapsed_time.secs%60);
1223 statusbar_push_file_msg(status_msg);
1227 win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1228 set_main_window_name(win_name);
1232 GtkWidget *close_dlg = NULL;
1235 main_cf_cb_file_closing(capture_file *cf)
1238 /* if we have more than 10000 packets, show a splash screen while closing */
1239 /* XXX - don't know a better way to decide wether to show or not,
1240 * as most of the time is spend in a single eth_clist_clear function,
1241 * so we can't use a progress bar here! */
1242 if(cf->count > 10000) {
1243 close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sClosing file!%s\n\nPlease wait ...",
1244 simple_dialog_primary_start(), simple_dialog_primary_end());
1245 #if GTK_MAJOR_VERSION >= 2
1246 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1248 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
1252 /* Destroy all windows, which refer to the
1253 capture file we're closing. */
1254 destroy_cfile_wins();
1256 /* Clear any file-related status bar messages.
1257 XXX - should be "clear *ALL* file-related status bar messages;
1258 will there ever be more than one on the stack? */
1259 statusbar_pop_file_msg();
1261 /* go back to "No packets" */
1262 packets_bar_update();
1264 /* Restore the standard title bar message. */
1265 set_main_window_name("The Ethereal Network Analyzer");
1267 /* Disable all menu items that make sense only if you have a capture. */
1268 set_menus_for_capture_file(FALSE);
1269 set_menus_for_unsaved_capture_file(FALSE);
1270 set_menus_for_captured_packets(FALSE);
1271 set_menus_for_selected_packet(cf);
1272 set_menus_for_capture_in_progress(FALSE);
1273 set_menus_for_selected_tree_row(cf);
1275 /* Set up main window for no capture file. */
1276 main_set_for_capture_file(FALSE);
1278 main_window_update();
1282 main_cf_cb_file_closed(capture_file *cf _U_)
1284 if(close_dlg != NULL) {
1285 splash_destroy(close_dlg);
1291 main_cf_cb_file_read_start(capture_file *cf)
1293 const gchar *name_ptr;
1296 name_ptr = get_basename(cf->filename);
1298 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1299 statusbar_push_file_msg(load_msg);
1304 main_cf_cb_file_read_finished(capture_file *cf)
1306 statusbar_pop_file_msg();
1307 set_display_filename(cf);
1309 /* Enable menu items that make sense if you have a capture file you've
1310 finished reading. */
1311 set_menus_for_capture_file(TRUE);
1312 set_menus_for_unsaved_capture_file(!cf->user_saved);
1314 /* Enable menu items that make sense if you have some captured packets. */
1315 set_menus_for_captured_packets(TRUE);
1317 /* Set up main window for a capture file. */
1318 main_set_for_capture_file(TRUE);
1323 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1328 if(capture_opts->iface) {
1329 title = g_strdup_printf("%s: Capturing - Ethereal",
1330 get_interface_descriptive_name(capture_opts->iface));
1332 title = g_strdup_printf("Capturing - Ethereal");
1334 set_main_window_name(title);
1337 /* Disable menu items that make no sense if you're currently running
1339 set_menus_for_capture_in_progress(TRUE);
1341 /* update statusbar */
1342 statusbar_push_file_msg("Waiting for capture input data ...");
1344 /* Don't set up main window for a capture file. */
1345 main_set_for_capture_file(FALSE);
1349 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1355 /* We've done this in "prepared" above, but it will be cleared while
1356 switching to the next multiple file. */
1357 if(capture_opts->iface) {
1358 title = g_strdup_printf("%s: Capturing - Ethereal",
1359 get_interface_descriptive_name(capture_opts->iface));
1361 title = g_strdup_printf("Capturing - Ethereal");
1363 set_main_window_name(title);
1366 set_menus_for_capture_in_progress(TRUE);
1368 /* Enable menu items that make sense if you have some captured
1369 packets (yes, I know, we don't have any *yet*). */
1370 set_menus_for_captured_packets(TRUE);
1372 statusbar_pop_file_msg();
1374 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1375 get_interface_descriptive_name(capture_opts->iface),
1376 (capture_opts->save_file) ? capture_opts->save_file : "");
1378 statusbar_push_file_msg(capture_msg);
1380 g_free(capture_msg);
1382 /* Set up main window for a capture file. */
1383 main_set_for_capture_file(TRUE);
1387 main_cf_cb_live_capture_update_continue(capture_file *cf)
1392 statusbar_pop_file_msg();
1394 if (cf->f_datalen/1024/1024 > 10) {
1395 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB",
1396 get_interface_descriptive_name(capture_opts->iface),
1397 capture_opts->save_file,
1398 cf->f_datalen/1024/1024);
1399 } else if (cf->f_datalen/1024 > 10) {
1400 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB",
1401 get_interface_descriptive_name(capture_opts->iface),
1402 capture_opts->save_file,
1403 cf->f_datalen/1024);
1405 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes",
1406 get_interface_descriptive_name(capture_opts->iface),
1407 capture_opts->save_file,
1411 statusbar_push_file_msg(capture_msg);
1414 GtkWidget * stop_dlg = NULL;
1417 main_cf_cb_live_capture_update_finished(capture_file *cf)
1419 if(stop_dlg != NULL) {
1420 simple_dialog_close(stop_dlg);
1424 /* Pop the "<live capture in progress>" message off the status bar. */
1425 statusbar_pop_file_msg();
1427 set_display_filename(cf);
1429 /* Enable menu items that make sense if you're not currently running
1431 set_menus_for_capture_in_progress(FALSE);
1433 /* Enable menu items that make sense if you have a capture file
1434 you've finished reading. */
1435 set_menus_for_capture_file(TRUE);
1436 set_menus_for_unsaved_capture_file(!cf->user_saved);
1438 /* Set up main window for a capture file. */
1439 main_set_for_capture_file(TRUE);
1443 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1448 /* Enable menu items that make sense if you have some captured
1449 packets (yes, I know, we don't have any *yet*). */
1450 /*set_menus_for_captured_packets(TRUE);*/
1452 statusbar_pop_file_msg();
1454 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1455 get_interface_descriptive_name(capture_opts->iface),
1456 (capture_opts->save_file) ? capture_opts->save_file : "");
1458 statusbar_push_file_msg(capture_msg);
1459 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " <capturing>");
1461 g_free(capture_msg);
1463 /* Don't set up main window for a capture file. */
1464 main_set_for_capture_file(FALSE);
1468 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1470 if(stop_dlg != NULL) {
1471 simple_dialog_close(stop_dlg);
1475 /* Pop the "<live capture in progress>" message off the status bar. */
1476 statusbar_pop_file_msg();
1478 /* Pop the "<capturing>" message off the status bar */
1479 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1481 /*set_display_filename(cf);*/
1483 /* Enable menu items that make sense if you're not currently running
1485 set_menus_for_capture_in_progress(FALSE);
1487 /* We don't have loaded the capture file, this will be done later.
1488 * For now we still have simply a blank screen. */
1492 main_cf_cb_live_capture_stopping(capture_file *cf _U_)
1494 stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...",
1495 simple_dialog_primary_start(), simple_dialog_primary_end());
1496 #if GTK_MAJOR_VERSION >= 2
1497 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1499 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1506 main_cf_cb_packet_selected(gpointer data)
1508 capture_file *cf = data;
1510 /* Display the GUI protocol tree and hex dump.
1511 XXX - why do we dump core if we call "proto_tree_draw()"
1512 before calling "add_byte_views()"? */
1513 add_main_byte_views(cf->edt);
1514 main_proto_tree_draw(cf->edt->tree);
1516 /* A packet is selected. */
1517 set_menus_for_selected_packet(cf);
1521 main_cf_cb_packet_unselected(capture_file *cf)
1523 /* Clear out the display of that packet. */
1524 clear_tree_and_hex_views();
1526 /* No packet is selected. */
1527 set_menus_for_selected_packet(cf);
1531 main_cf_cb_field_unselected(capture_file *cf)
1533 statusbar_pop_field_msg();
1534 set_menus_for_selected_tree_row(cf);
1538 main_cf_cb_file_safe_started(gchar * filename)
1540 const gchar *name_ptr;
1543 name_ptr = get_basename(filename);
1545 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1547 statusbar_push_file_msg(save_msg);
1552 main_cf_cb_file_safe_finished(gpointer data _U_)
1554 /* Pop the "Saving:" message off the status bar. */
1555 statusbar_pop_file_msg();
1559 main_cf_cb_file_safe_failed(gpointer data _U_)
1561 /* Pop the "Saving:" message off the status bar. */
1562 statusbar_pop_file_msg();
1566 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1568 set_menus_for_unsaved_capture_file(FALSE);
1571 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1574 case(cf_cb_file_closing):
1575 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
1576 main_cf_cb_file_closing(data);
1578 case(cf_cb_file_closed):
1579 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
1580 main_cf_cb_file_closed(data);
1582 case(cf_cb_file_read_start):
1583 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read start");
1584 main_cf_cb_file_read_start(data);
1586 case(cf_cb_file_read_finished):
1587 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
1588 main_cf_cb_file_read_finished(data);
1591 case(cf_cb_live_capture_prepared):
1592 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
1593 main_cf_cb_live_capture_prepared(data);
1595 case(cf_cb_live_capture_update_started):
1596 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
1597 main_cf_cb_live_capture_update_started(data);
1599 case(cf_cb_live_capture_update_continue):
1600 /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
1601 main_cf_cb_live_capture_update_continue(data);
1603 case(cf_cb_live_capture_fixed_started):
1604 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
1605 main_cf_cb_live_capture_fixed_started(data);
1607 case(cf_cb_live_capture_update_finished):
1608 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
1609 main_cf_cb_live_capture_update_finished(data);
1611 case(cf_cb_live_capture_fixed_finished):
1612 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
1613 main_cf_cb_live_capture_fixed_finished(data);
1615 case(cf_cb_live_capture_stopping):
1616 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
1617 main_cf_cb_live_capture_stopping(data);
1620 case(cf_cb_packet_selected):
1621 main_cf_cb_packet_selected(data);
1623 case(cf_cb_packet_unselected):
1624 main_cf_cb_packet_unselected(data);
1626 case(cf_cb_field_unselected):
1627 main_cf_cb_field_unselected(data);
1629 case(cf_cb_file_safe_started):
1630 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe started");
1631 main_cf_cb_file_safe_started(data);
1633 case(cf_cb_file_safe_finished):
1634 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe finished");
1635 main_cf_cb_file_safe_finished(data);
1637 case(cf_cb_file_safe_reload_finished):
1638 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: reload finished");
1639 main_cf_cb_file_safe_reload_finished(data);
1641 case(cf_cb_file_safe_failed):
1642 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe failed");
1643 main_cf_cb_file_safe_failed(data);
1646 g_warning("main_cf_callback: event %u unknown", event);
1647 g_assert_not_reached();
1651 /* And now our feature presentation... [ fade to music ] */
1653 main(int argc, char *argv[])
1656 const char *command_name;
1661 extern char *optarg;
1662 gboolean arg_error = FALSE;
1670 char *gpf_path, *pf_path;
1671 char *cf_path, *df_path;
1672 char *gdp_path, *dp_path;
1673 int gpf_open_errno, gpf_read_errno;
1674 int pf_open_errno, pf_read_errno;
1675 int cf_open_errno, df_open_errno;
1676 int gdp_open_errno, gdp_read_errno;
1677 int dp_open_errno, dp_read_errno;
1680 gboolean start_capture = FALSE;
1683 GList *lt_list, *lt_entry;
1684 data_link_info_t *data_link_info;
1685 gchar err_str[PCAP_ERRBUF_SIZE];
1686 gchar *cant_get_if_list_errstr;
1687 gboolean stats_known;
1688 struct pcap_stat stats;
1690 gboolean capture_option_specified = FALSE;
1692 gint pl_size = 280, tv_size = 95, bv_size = 75;
1693 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1694 dfilter_t *rfcode = NULL;
1695 gboolean rfilter_parse_failed = FALSE;
1698 GtkWidget *splash_win = NULL;
1699 GLogLevelFlags log_flags;
1700 guint go_to_packet = 0;
1703 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1707 #define OPTSTRING_CHILD "W:Z:"
1708 #define OPTSTRING_WIN32 "B:"
1710 #define OPTSTRING_CHILD "W:"
1711 #define OPTSTRING_WIN32 ""
1714 #define OPTSTRING_CHILD ""
1715 #define OPTSTRING_WIN32 ""
1716 #endif /* HAVE_LIBPCAP */
1718 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1719 OPTSTRING_INIT OPTSTRING_WIN32;
1721 /* initialize memory allocation subsystem */
1725 /*** create the compile and runtime version strings ***/
1727 /* Load wpcap if possible. Do this before collecting the run-time version information */
1730 /* ... and also load the packet.dll from wpcap */
1731 wpcap_packet_load();
1733 /* Start windows sockets */
1734 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1737 /* Assemble the compile-time version information string */
1738 comp_info_str = g_string_new("Compiled ");
1739 g_string_append(comp_info_str, "with ");
1740 g_string_sprintfa(comp_info_str,
1741 #ifdef GTK_MAJOR_VERSION
1742 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1745 "GTK+ (version unknown)");
1748 g_string_append(comp_info_str, ", ");
1749 get_compiled_version_info(comp_info_str);
1751 /* Assemble the run-time version information string */
1752 runtime_info_str = g_string_new("Running ");
1753 get_runtime_version_info(runtime_info_str);
1756 /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1757 /* (e.g. don't start GTK+, if we only have to show the command line help) */
1758 optind_initial = optind;
1759 while ((opt = getopt(argc, argv, optstring)) != -1) {
1761 case 'h': /* Print help and exit */
1765 case 'v': /* Show version and exit */
1769 case 'G': /* dump various field or other infos, see handle_dashG_option() */
1770 /* If invoked with the "-G" flag, we dump out information based on
1771 the argument to the "-G" flag; if no argument is specified,
1772 for backwards compatibility we dump out a glossary of display
1775 We must do this before calling "gtk_init()", because "gtk_init()"
1776 tries to open an X display, and we don't want to have to do any X
1777 stuff just to do a build.
1779 Given that we call "gtk_init()" before doing the regular argument
1780 list processing, so that it can handle X and GTK+ arguments and
1781 remove them from the list at which we look, this means we must do
1782 this before doing the regular argument list processing, as well.
1786 you must give the "-G" flag as the first flag on the command line;
1788 you must give it as "-G", nothing more, nothing less;
1790 the first argument after the "-G" flag, if present, will be used
1791 to specify the information to dump;
1793 arguments after that will not be used. */
1794 handle_dashG_option(argc, argv, "ethereal");
1795 /* will never return! */
1801 /* set getopt index back to initial value, so it will start with the first command line parameter again */
1802 /* (XXX - this seems to be portable, but time will tell) */
1803 optind = optind_initial;
1806 /* Set the current locale according to the program environment.
1807 * We haven't localized anything, but some GTK widgets are localized
1808 * (the file selection dialogue, for example).
1809 * This also sets the C-language locale to the native environment. */
1812 /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1813 gtk_init (&argc, &argv);
1815 cf_callback_add(main_cf_callback, NULL);
1817 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1818 /* initialize our GTK eth_clist_type */
1819 init_eth_clist_type();
1822 ethereal_path = argv[0];
1824 /* Arrange that if we have no console window, and a GLib message logging
1825 routine is called to log a message, we pop up a console window.
1827 We do that by inserting our own handler for all messages logged
1828 to the default domain; that handler pops up a console if necessary,
1829 and then calls the default handler. */
1831 /* We might want to have component specific log levels later ... */
1833 /* the default_log_handler will use stdout, which makes trouble with the */
1834 /* capture child, as it uses stdout for it's sync_pipe */
1835 /* so do the filtering in the console_log_handler and not here */
1838 G_LOG_LEVEL_CRITICAL|
1839 G_LOG_LEVEL_WARNING|
1840 G_LOG_LEVEL_MESSAGE|
1843 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1845 g_log_set_handler(NULL,
1847 console_log_handler, NULL /* user_data */);
1848 g_log_set_handler(LOG_DOMAIN_MAIN,
1850 console_log_handler, NULL /* user_data */);
1853 g_log_set_handler(LOG_DOMAIN_CAPTURE,
1855 console_log_handler, NULL /* user_data */);
1856 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1858 console_log_handler, NULL /* user_data */);
1860 /* Set the initial values in the capture_opts. This might be overwritten
1861 by preference settings and then again by the command line parameters. */
1862 capture_opts_init(capture_opts, &cfile);
1864 capture_opts->snaplen = MIN_PACKET_SIZE;
1865 capture_opts->has_ring_num_files = TRUE;
1867 command_name = get_basename(ethereal_path);
1868 /* Set "capture_child" to indicate whether this is going to be a child
1869 process for a "-S" capture. */
1870 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1871 if (capture_child) {
1872 strcat(optstring, OPTSTRING_CHILD);
1876 /* We want a splash screen only if we're not a child process.
1877 We won't come till here, if we had a "console only" command line parameter. */
1881 splash_win = splash_new("Loading Ethereal ...");
1883 splash_update(splash_win, "Registering dissectors ...");
1885 /* Register all dissectors; we must do this before checking for the
1886 "-G" flag, as the "-G" flag dumps information registered by the
1887 dissectors, and we must do it before we read the preferences, in
1888 case any dissectors register preferences. */
1889 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1890 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1892 splash_update(splash_win, "Registering tap listeners ...");
1894 /* Register all tap listeners; we do this before we parse the arguments,
1895 as the "-z" argument can specify a registered tap. */
1897 /* we register the plugin taps before the other taps because
1898 stats_tree taps plugins will be registered as tap listeners
1899 by stats_tree_stat.c and need to registered before that */
1902 register_all_plugin_tap_listeners();
1905 register_all_tap_listeners();
1907 splash_update(splash_win, "Loading module preferences ...");
1909 /* Now register the preferences for any non-dissector modules.
1910 We must do that before we read the preferences as well. */
1911 prefs_register_modules();
1913 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1914 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1917 g_thread_init(NULL);
1919 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1920 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1922 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1923 /* this is to keep tap extensions updating once every 3 seconds */
1924 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1925 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1928 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1931 splash_update(splash_win, "Loading configuration files ...");
1933 /* Read the preference files. */
1934 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1935 &pf_open_errno, &pf_read_errno, &pf_path);
1936 if (gpf_path != NULL) {
1937 if (gpf_open_errno != 0) {
1938 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1939 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1940 strerror(gpf_open_errno));
1942 if (gpf_read_errno != 0) {
1943 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1944 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1945 strerror(gpf_read_errno));
1948 if (pf_path != NULL) {
1949 if (pf_open_errno != 0) {
1950 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1951 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1952 strerror(pf_open_errno));
1954 if (pf_read_errno != 0) {
1955 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1956 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1957 strerror(pf_read_errno));
1964 /* if the user wants a console to be always there, well, we should open one for him */
1965 if (prefs->gui_console_open == console_open_always) {
1971 /* If this is a capture child process, it should pay no attention
1972 to the "prefs.capture_prom_mode" setting in the preferences file;
1973 it should do what the parent process tells it to do, and if
1974 the parent process wants it not to run in promiscuous mode, it'll
1975 tell it so with a "-p" flag.
1977 Otherwise, set promiscuous mode from the preferences setting. */
1978 /* the same applies to other preferences settings as well. */
1979 if (capture_child) {
1980 auto_scroll_live = FALSE;
1982 capture_opts->promisc_mode = prefs->capture_prom_mode;
1983 capture_opts->show_info = prefs->capture_show_info;
1984 capture_opts->real_time_mode = prefs->capture_real_time;
1985 auto_scroll_live = prefs->capture_auto_scroll;
1988 #endif /* HAVE_LIBPCAP */
1990 /* Set the name resolution code's flags from the preferences. */
1991 g_resolv_flags = prefs->name_resolve;
1993 /* Read the capture filter file. */
1994 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1995 if (cf_path != NULL) {
1996 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1997 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1998 strerror(cf_open_errno));
2002 /* Read the display filter file. */
2003 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
2004 if (df_path != NULL) {
2005 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2006 "Could not open your display filter file\n\"%s\": %s.", df_path,
2007 strerror(df_open_errno));
2011 /* Read the disabled protocols file. */
2012 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
2013 &dp_path, &dp_open_errno, &dp_read_errno);
2014 if (gdp_path != NULL) {
2015 if (gdp_open_errno != 0) {
2016 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2017 "Could not open global disabled protocols file\n\"%s\": %s.",
2018 gdp_path, strerror(gdp_open_errno));
2020 if (gdp_read_errno != 0) {
2021 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2022 "I/O error reading global disabled protocols file\n\"%s\": %s.",
2023 gdp_path, strerror(gdp_read_errno));
2027 if (dp_path != NULL) {
2028 if (dp_open_errno != 0) {
2029 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2030 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
2031 strerror(dp_open_errno));
2033 if (dp_read_errno != 0) {
2034 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2035 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2036 strerror(dp_read_errno));
2041 /* Read the (static part) of the recent file. Only the static part of it will be read, */
2042 /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2043 /* We have to do this already here, so command line parameters can overwrite these values. */
2044 recent_read_static(&rf_path, &rf_open_errno);
2046 init_cap_file(&cfile);
2048 /* Now get our args */
2049 while ((opt = getopt(argc, argv, optstring)) != -1) {
2051 /*** capture option specific ***/
2052 case 'a': /* autostop criteria */
2053 case 'b': /* Ringbuffer option */
2054 case 'c': /* Capture xxx packets */
2055 case 'f': /* capture filter */
2056 case 'k': /* Start capture immediately */
2057 case 'H': /* Hide capture info dialog box */
2058 case 'i': /* Use interface xxx */
2059 case 'p': /* Don't capture in promiscuous mode */
2060 case 'Q': /* Quit after capture (just capture to file) */
2061 case 's': /* Set the snapshot (capture) length */
2062 case 'S': /* "Sync" mode: used for following file ala tail -f */
2063 case 'w': /* Write to capture file xxx */
2064 case 'y': /* Set the pcap data link type */
2066 case 'B': /* Buffer size */
2067 /* Hidden option supporting Sync mode */
2068 case 'Z': /* Write to pipe FD XXX */
2071 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2073 capture_option_specified = TRUE;
2078 /* This is a hidden option supporting Sync mode, so we don't set
2079 * the error flags for the user in the non-libpcap case.
2081 case 'W': /* Write to capture file FD xxx */
2082 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2086 /*** all non capture option specific ***/
2087 case 'g': /* Go to packet */
2088 go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2090 case 'l': /* Automatic scrolling in live capture mode */
2092 auto_scroll_live = TRUE;
2094 capture_option_specified = TRUE;
2098 case 'L': /* Print list of link-layer types and exit */
2100 list_link_layer_types = TRUE;
2102 capture_option_specified = TRUE;
2106 case 'm': /* Fixed-width font for the display */
2107 if (prefs->PREFS_GUI_FONT_NAME != NULL)
2108 g_free(prefs->PREFS_GUI_FONT_NAME);
2109 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2111 case 'n': /* No name resolution */
2112 g_resolv_flags = RESOLV_NONE;
2114 case 'N': /* Select what types of addresses/port #s to resolve */
2115 if (g_resolv_flags == RESOLV_ALL)
2116 g_resolv_flags = RESOLV_NONE;
2117 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2118 if (badopt != '\0') {
2119 g_warning("ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2124 case 'o': /* Override preference from command line */
2125 switch (prefs_set_pref(optarg)) {
2128 case PREFS_SET_SYNTAX_ERR:
2129 g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2132 case PREFS_SET_NO_SUCH_PREF:
2133 /* not a preference, might be a recent setting */
2134 switch (recent_set_arg(optarg)) {
2137 case PREFS_SET_SYNTAX_ERR:
2138 /* shouldn't happen, checked already above */
2139 g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2142 case PREFS_SET_NO_SUCH_PREF:
2143 case PREFS_SET_OBSOLETE:
2144 g_warning("ethereal: -o flag \"%s\" specifies unknown preference/recent value",
2149 g_assert_not_reached();
2152 case PREFS_SET_OBSOLETE:
2153 g_warning("ethereal: -o flag \"%s\" specifies obsolete preference",
2158 g_assert_not_reached();
2161 case 'r': /* Read capture file xxx */
2162 /* We may set "last_open_dir" to "cf_name", and if we change
2163 "last_open_dir" later, we free the old value, so we have to
2164 set "cf_name" to something that's been allocated. */
2165 cf_name = g_strdup(optarg);
2167 case 'R': /* Read file filter */
2170 case 't': /* Time stamp type */
2171 if (strcmp(optarg, "r") == 0)
2172 timestamp_set_type(TS_RELATIVE);
2173 else if (strcmp(optarg, "a") == 0)
2174 timestamp_set_type(TS_ABSOLUTE);
2175 else if (strcmp(optarg, "ad") == 0)
2176 timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2177 else if (strcmp(optarg, "d") == 0)
2178 timestamp_set_type(TS_DELTA);
2180 g_warning("ethereal: Invalid time stamp type \"%s\"",
2182 g_warning("It must be \"r\" for relative, \"a\" for absolute,");
2183 g_warning("\"ad\" for absolute with date, or \"d\" for delta.");
2188 /* We won't call the init function for the stat this soon
2189 as it would disallow MATE's fields (which are registered
2190 by the preferences set callback) from being used as
2191 part of a tap filter. Instead, we just add the argument
2192 to a list of stat arguments. */
2193 if (!process_stat_cmd_arg(optarg)) {
2194 g_warning("ethereal: invalid -z argument.");
2195 g_warning(" -z argument must be one of :");
2196 list_stat_cmd_args();
2201 case '?': /* Bad flag - print usage message */
2202 g_warning("Bad flag");
2210 if (cf_name != NULL) {
2212 * Input file name specified with "-r" *and* specified as a regular
2213 * command-line argument.
2215 g_warning("File name specified both with -r and regular argument");
2219 * Input file name not specified with "-r", and a command-line argument
2220 * was specified; treat it as the input file name.
2222 * Yes, this is different from tethereal, where non-flag command-line
2223 * arguments are a filter, but this works better on GUI desktops
2224 * where a command can be specified to be run to open a particular
2225 * file - yes, you could have "-r" as the last part of the command,
2226 * but that's a bit ugly.
2228 cf_name = g_strdup(argv[0]);
2238 * Extra command line arguments were specified; complain.
2240 g_warning("Invalid argument: %s", argv[0]);
2245 #ifndef HAVE_LIBPCAP
2246 if (capture_option_specified) {
2247 g_warning("This version of Ethereal was not built with support for capturing packets.");
2255 if (start_capture && list_link_layer_types) {
2256 /* Specifying *both* is bogus. */
2257 g_warning("ethereal: You can't specify both -L and a live capture.");
2261 if (list_link_layer_types) {
2262 /* We're supposed to list the link-layer types for an interface;
2263 did the user also specify a capture file to be read? */
2265 /* Yes - that's bogus. */
2266 g_warning("ethereal: You can't specify -L and a capture file to be read.");
2269 /* No - did they specify a ring buffer option? */
2270 if (capture_opts->multi_files_on) {
2271 g_warning("ethereal: Ring buffer requested, but a capture isn't being done.");
2275 /* We're supposed to do a live capture; did the user also specify
2276 a capture file to be read? */
2277 if (start_capture && cf_name) {
2278 /* Yes - that's bogus. */
2279 g_warning("ethereal: You can't specify both a live capture and a capture file to be read.");
2283 /* No - was the ring buffer option specified and, if so, does it make
2285 if (capture_opts->multi_files_on) {
2286 /* Ring buffer works only under certain conditions:
2287 a) ring buffer does not work with temporary files;
2288 b) real_time_mode and multi_files_on are mutually exclusive -
2289 real_time_mode takes precedence;
2290 c) it makes no sense to enable the ring buffer if the maximum
2291 file size is set to "infinite". */
2292 if (capture_opts->save_file == NULL) {
2293 g_warning("ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.");
2294 capture_opts->multi_files_on = FALSE;
2296 /* if (capture_opts->real_time_mode) {
2297 g_warning("ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2298 capture_opts->multi_files_on = FALSE;
2300 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2301 g_warning("ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.");
2302 /* XXX - this must be redesigned as the conditions changed */
2303 /* capture_opts->multi_files_on = FALSE;*/
2308 if (start_capture || list_link_layer_types) {
2309 /* Did the user specify an interface to use? */
2310 if (capture_opts->iface == NULL) {
2311 /* No - is a default specified in the preferences file? */
2312 if (prefs->capture_device != NULL) {
2314 capture_opts->iface = g_strdup(get_if_name(prefs->capture_device));
2316 /* No - pick the first one from the list of interfaces. */
2317 if_list = get_interface_list(&err, err_str);
2318 if (if_list == NULL) {
2321 case CANT_GET_INTERFACE_LIST:
2322 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2323 g_warning("%s", cant_get_if_list_errstr);
2324 g_free(cant_get_if_list_errstr);
2327 case NO_INTERFACES_FOUND:
2328 g_warning("ethereal: There are no interfaces on which a capture can be done");
2333 if_info = if_list->data; /* first interface */
2334 capture_opts->iface = g_strdup(if_info->name);
2335 free_interface_list(if_list);
2340 if (list_link_layer_types) {
2341 /* Get the list of link-layer types for the capture device. */
2342 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2343 if (lt_list == NULL) {
2344 if (err_str[0] != '\0') {
2345 g_warning("ethereal: The list of data link types for the capture device could not be obtained (%s)."
2346 "Please check to make sure you have sufficient permissions, and that\n"
2347 "you have the proper interface or pipe specified.\n", err_str);
2349 g_warning("ethereal: The capture device has no data link types.");
2352 g_warning("Data link types (use option -y to set):");
2353 for (lt_entry = lt_list; lt_entry != NULL;
2354 lt_entry = g_list_next(lt_entry)) {
2355 data_link_info = lt_entry->data;
2356 g_warning(" %s", data_link_info->name);
2357 if (data_link_info->description != NULL)
2358 g_warning(" (%s)", data_link_info->description);
2360 g_warning(" (not supported)");
2363 free_pcap_linktype_list(lt_list);
2367 if (capture_opts->has_snaplen) {
2368 if (capture_opts->snaplen < 1)
2369 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2370 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2371 capture_opts->snaplen = MIN_PACKET_SIZE;
2374 /* Check the value range of the ringbuffer_num_files parameter */
2375 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2376 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2377 #if RINGBUFFER_MIN_NUM_FILES > 0
2378 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2379 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2381 #endif /* HAVE_LIBPCAP */
2383 /* Notify all registered modules that have had any of their preferences
2384 changed either from one of the preferences file or from the command
2385 line that their preferences have changed. */
2388 /* disabled protocols as per configuration file */
2389 if (gdp_path == NULL && dp_path == NULL) {
2390 set_disabled_protos_list();
2393 /* Build the column format array */
2394 col_setup(&cfile.cinfo, prefs->num_cols);
2395 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2396 cfile.cinfo.col_fmt[i] = get_column_format(i);
2397 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2398 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2400 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2401 cfile.cinfo.col_data[i] = NULL;
2402 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2403 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2405 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2406 cfile.cinfo.col_fence[i] = 0;
2407 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2408 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2411 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2414 for (j = 0; j < NUM_COL_FMTS; j++) {
2415 if (!cfile.cinfo.fmt_matx[i][j])
2418 if (cfile.cinfo.col_first[j] == -1)
2419 cfile.cinfo.col_first[j] = i;
2420 cfile.cinfo.col_last[j] = i;
2424 /* read in rc file from global and personal configuration paths. */
2425 rc_file = get_datafile_path(RC_FILE);
2426 gtk_rc_parse(rc_file);
2427 rc_file = get_persconffile_path(RC_FILE, FALSE);
2428 gtk_rc_parse(rc_file);
2431 font_init(capture_child);
2436 /* close the splash screen, as we are going to open the main window now */
2437 splash_destroy(splash_win);
2441 /* Is this a "child" ethereal, which is only supposed to pop up a
2442 capture box to let us stop the capture, and run a capture
2443 to a file that our parent will read? */
2444 if (capture_child) {
2445 /* This is the child process of a capture session,
2446 so just do the low-level work of a capture - don't create
2447 a temporary file and fork off *another* child process (so don't
2448 call "capture_start()"). */
2450 /* Pop up any queued-up alert boxes. */
2451 display_queued_messages();
2453 /* Now start the capture.
2454 After the capture is done; there's nothing more for us to do. */
2456 /* XXX - hand these stats to the parent process */
2457 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2461 /* capture failed */
2467 /***********************************************************************/
2468 /* Everything is prepared now, preferences and command line was read in,
2469 we are NOT a child window for a synced capture. */
2471 /* Pop up the main window. */
2472 create_main_window(pl_size, tv_size, bv_size, prefs);
2474 /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2475 recent_read_dynamic(&rf_path, &rf_open_errno);
2476 color_filters_enable(recent.packet_list_colorize);
2478 /* rearrange all the widgets as we now have all recent settings ready for this */
2479 main_widgets_rearrange();
2481 /* Fill in column titles. This must be done after the top level window
2484 XXX - is that still true, with fixed-width columns? */
2485 packet_list_set_column_titles();
2487 menu_recent_read_finished();
2489 switch (user_font_apply()) {
2492 case FA_FONT_NOT_RESIZEABLE:
2493 /* "user_font_apply()" popped up an alert box. */
2494 /* turn off zooming - font can't be resized */
2495 case FA_FONT_NOT_AVAILABLE:
2496 /* XXX - did we successfully load the un-zoomed version earlier?
2497 If so, this *probably* means the font is available, but not at
2498 this particular zoom level, but perhaps some other failure
2499 occurred; I'm not sure you can determine which is the case,
2501 /* turn off zooming - zoom level is unavailable */
2503 /* in any other case than FA_SUCCESS, turn off zooming */
2504 recent.gui_zoom_level = 0;
2505 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2508 dnd_init(top_level);
2511 color_filters_init();
2514 /* the window can be sized only, if it's not already shown, so do it now! */
2515 main_load_window_geometry(top_level);
2517 /* If we were given the name of a capture file, read it in now;
2518 we defer it until now, so that, if we can't open it, and pop
2519 up an alert box, the alert box is more likely to come up on
2520 top of the main window - but before the preference-file-error
2521 alert box, so, if we get one of those, it's more likely to come
2524 show_main_window(TRUE);
2525 if (rfilter != NULL) {
2526 if (!dfilter_compile(rfilter, &rfcode)) {
2527 bad_dfilter_alert_box(rfilter);
2528 rfilter_parse_failed = TRUE;
2531 if (!rfilter_parse_failed) {
2532 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2533 /* "cf_open()" succeeded, so it closed the previous
2534 capture file, and thus destroyed any previous read filter
2535 attached to "cf". */
2537 cfile.rfcode = rfcode;
2538 /* Open stat windows; we do so after creating the main window,
2539 to avoid GTK warnings, and after successfully opening the
2540 capture file, so we know we have something to compute stats
2541 on, and after registering all dissectors, so that MATE will
2542 have registered its field array and we can have a tap filter
2543 with one of MATE's late-registered fields as part of the
2545 start_requested_stats();
2547 /* Read the capture file. */
2548 switch (cf_read(&cfile)) {
2552 /* Just because we got an error, that doesn't mean we were unable
2553 to read any of the file; we handle what we could get from the
2555 /* if the user told us to jump to a specific packet, do it now */
2556 if(go_to_packet != 0) {
2557 cf_goto_frame(&cfile, go_to_packet);
2561 case CF_READ_ABORTED:
2566 /* Save the name of the containing directory specified in the
2567 path name, if any; we can write over cf_name, which is a
2568 good thing, given that "get_dirname()" does write over its
2570 s = get_dirname(cf_name);
2571 /* we might already set this from the recent file, don't overwrite this */
2572 if(get_last_open_dir() == NULL)
2573 set_last_open_dir(s);
2578 dfilter_free(rfcode);
2579 cfile.rfcode = NULL;
2580 show_main_window(FALSE);
2581 set_menus_for_capture_in_progress(FALSE);
2586 if (start_capture) {
2587 if (capture_opts->save_file != NULL) {
2588 /* Save the directory name for future file dialogs. */
2589 /* (get_dirname overwrites filename) */
2590 s = get_dirname(g_strdup(capture_opts->save_file));
2591 set_last_open_dir(s);
2594 /* "-k" was specified; start a capture. */
2595 show_main_window(TRUE);
2596 if (capture_start(capture_opts)) {
2597 /* The capture started. Open stat windows; we do so after creating
2598 the main window, to avoid GTK warnings, and after successfully
2599 opening the capture file, so we know we have something to compute
2600 stats on, and after registering all dissectors, so that MATE will
2601 have registered its field array and we can have a tap filter with
2602 one of MATE's late-registered fields as part of the filter. */
2603 start_requested_stats();
2607 show_main_window(FALSE);
2608 set_menus_for_capture_in_progress(FALSE);
2611 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2612 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2613 if (capture_opts->cfilter) {
2614 g_free(capture_opts->cfilter);
2616 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2618 #else /* HAVE_LIBPCAP */
2619 show_main_window(FALSE);
2620 set_menus_for_capture_in_progress(FALSE);
2621 #endif /* HAVE_LIBPCAP */
2624 /* we'll enter the GTK loop now and hand the control over to GTK ... */
2626 /* ... back from GTK, we're going down now! */
2632 /* hide the (unresponsive) main window, while asking the user to close the console window */
2633 gtk_widget_hide(top_level);
2635 /* Shutdown windows sockets */
2638 /* For some unknown reason, the "atexit()" call in "create_console()"
2639 doesn't arrange that "destroy_console()" be called when we exit,
2640 so we call it here if a console was created. */
2646 /* This isn't reached, but we need it to keep GCC from complaining
2647 that "main()" returns without returning a value - it knows that
2648 "exit()" never returns, but it doesn't know that "gtk_exit()"
2649 doesn't, as GTK+ doesn't declare it with the attribute
2651 return 0; /* not reached */
2656 /* We build this as a GUI subsystem application on Win32, so
2657 "WinMain()", not "main()", gets called.
2659 Hack shamelessly stolen from the Win32 port of the GIMP. */
2661 #define _stdcall __attribute__((stdcall))
2665 WinMain (struct HINSTANCE__ *hInstance,
2666 struct HINSTANCE__ *hPrevInstance,
2670 has_console = FALSE;
2671 return main (__argc, __argv);
2675 * If this application has no console window to which its standard output
2676 * would go, create one.
2679 create_console(void)
2682 /* We have no console to which to print the version string, so
2683 create one and make it the standard input, output, and error. */
2684 if (!AllocConsole())
2685 return; /* couldn't create console */
2686 freopen("CONIN$", "r", stdin);
2687 freopen("CONOUT$", "w", stdout);
2688 freopen("CONOUT$", "w", stderr);
2690 /* Well, we have a console now. */
2693 /* Now register "destroy_console()" as a routine to be called just
2694 before the application exits, so that we can destroy the console
2695 after the user has typed a key (so that the console doesn't just
2696 disappear out from under them, giving the user no chance to see
2697 the message(s) we put in there). */
2698 atexit(destroy_console);
2701 SetConsoleTitle("Ethereal Capture Child Debug Console");
2703 SetConsoleTitle("Ethereal Debug Console");
2709 destroy_console(void)
2711 if (has_console && !capture_child) {
2712 printf("\n\nPress any key to exit\n");
2720 /* This routine should not be necessary, at least as I read the GLib
2721 source code, as it looks as if GLib is, on Win32, *supposed* to
2722 create a console window into which to display its output.
2724 That doesn't happen, however. I suspect there's something completely
2725 broken about that code in GLib-for-Win32, and that it may be related
2726 to the breakage that forces us to just call "printf()" on the message
2727 rather than passing the message on to "g_log_default_handler()"
2728 (which is the routine that does the aforementioned non-functional
2729 console window creation). */
2731 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2732 const char *message, gpointer user_data _U_)
2739 /* change this, if you want to see more verbose log output */
2740 /* XXX - make this a pref value */
2741 if( (log_level & G_LOG_LEVEL_MASK) > G_LOG_LEVEL_WARNING) {
2745 /* create a "timestamp" */
2747 today = localtime(&curr);
2750 if (prefs.gui_console_open != console_open_never) {
2754 /* For some unknown reason, the above doesn't appear to actually cause
2755 anything to be sent to the standard output, so we'll just splat the
2756 message out directly, just to make sure it gets out. */
2758 switch(log_level & G_LOG_LEVEL_MASK) {
2759 case G_LOG_LEVEL_ERROR:
2762 case G_LOG_LEVEL_CRITICAL:
2765 case G_LOG_LEVEL_WARNING:
2768 case G_LOG_LEVEL_MESSAGE:
2771 case G_LOG_LEVEL_INFO:
2774 case G_LOG_LEVEL_DEBUG:
2778 fprintf(stderr, "unknown log_level %u\n", log_level);
2780 g_assert_not_reached();
2783 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2784 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2785 today->tm_hour, today->tm_min, today->tm_sec,
2786 log_domain != NULL ? log_domain : "",
2790 g_log_default_handler(log_domain, log_level, message, user_data);
2796 static GtkWidget *info_bar_new(void)
2798 /* tip: tooltips don't work on statusbars! */
2799 info_bar = gtk_statusbar_new();
2800 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2801 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2802 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2803 #if GTK_MAJOR_VERSION >= 2
2804 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2806 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2811 static GtkWidget *packets_bar_new(void)
2813 /* tip: tooltips don't work on statusbars! */
2814 packets_bar = gtk_statusbar_new();
2815 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2816 packets_bar_update();
2823 * Helper for main_widgets_rearrange()
2825 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2826 gtk_container_remove(GTK_CONTAINER(data), widget);
2829 static GtkWidget *main_widget_layout(gint layout_content)
2831 switch(layout_content) {
2832 case(layout_pane_content_none):
2835 case(layout_pane_content_plist):
2838 case(layout_pane_content_pdetails):
2841 case(layout_pane_content_pbytes):
2845 g_assert_not_reached();
2852 * Rearrange the main window widgets
2854 void main_widgets_rearrange(void) {
2855 GtkWidget *first_pane_widget1, *first_pane_widget2;
2856 GtkWidget *second_pane_widget1, *second_pane_widget2;
2857 gboolean split_top_left;
2859 /* be a bit faster */
2860 gtk_widget_hide(main_vbox);
2862 /* be sure, we don't loose a widget while rearranging */
2863 gtk_widget_ref(menubar);
2864 gtk_widget_ref(main_tb);
2865 gtk_widget_ref(filter_tb);
2866 gtk_widget_ref(pkt_scrollw);
2867 gtk_widget_ref(tv_scrollw);
2868 gtk_widget_ref(byte_nb_ptr);
2869 gtk_widget_ref(stat_hbox);
2870 gtk_widget_ref(info_bar);
2871 gtk_widget_ref(packets_bar);
2872 gtk_widget_ref(status_pane);
2873 gtk_widget_ref(main_pane_v1);
2874 gtk_widget_ref(main_pane_v2);
2875 gtk_widget_ref(main_pane_h1);
2876 gtk_widget_ref(main_pane_h2);
2877 gtk_widget_ref(welcome_pane);
2879 /* empty all containers participating */
2880 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2881 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2882 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2883 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2884 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2885 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2886 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2888 /* add the menubar always at the top */
2889 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2892 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2894 /* filter toolbar in toolbar area */
2895 if (!prefs.filter_toolbar_show_in_statusbar) {
2896 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2899 /* fill the main layout panes */
2900 switch(prefs.gui_layout_type) {
2901 case(layout_type_5):
2902 main_first_pane = main_pane_v1;
2903 main_second_pane = main_pane_v2;
2904 split_top_left = FALSE;
2906 case(layout_type_2):
2907 main_first_pane = main_pane_v1;
2908 main_second_pane = main_pane_h1;
2909 split_top_left = FALSE;
2911 case(layout_type_1):
2912 main_first_pane = main_pane_v1;
2913 main_second_pane = main_pane_h1;
2914 split_top_left = TRUE;
2916 case(layout_type_4):
2917 main_first_pane = main_pane_h1;
2918 main_second_pane = main_pane_v1;
2919 split_top_left = FALSE;
2921 case(layout_type_3):
2922 main_first_pane = main_pane_h1;
2923 main_second_pane = main_pane_v1;
2924 split_top_left = TRUE;
2926 case(layout_type_6):
2927 main_first_pane = main_pane_h1;
2928 main_second_pane = main_pane_h2;
2929 split_top_left = FALSE;
2932 main_first_pane = NULL;
2933 main_second_pane = NULL;
2934 split_top_left = FALSE;
2935 g_assert_not_reached();
2937 if (split_top_left) {
2938 first_pane_widget1 = main_second_pane;
2939 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2940 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2941 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2943 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2944 first_pane_widget2 = main_second_pane;
2945 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2946 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2948 if (first_pane_widget1 != NULL)
2949 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2950 if (first_pane_widget2 != NULL)
2951 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2952 if (second_pane_widget1 != NULL)
2953 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2954 if (second_pane_widget2 != NULL)
2955 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2957 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2960 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2962 /* statusbar hbox */
2963 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2965 /* filter toolbar in statusbar hbox */
2966 if (prefs.filter_toolbar_show_in_statusbar) {
2967 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2971 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2972 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2973 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2975 /* hide widgets on users recent settings */
2976 main_widgets_show_or_hide();
2978 gtk_widget_show(main_vbox);
2982 is_widget_visible(GtkWidget *widget, gpointer data)
2984 gboolean *is_visible = data;
2987 if (GTK_WIDGET_VISIBLE(widget))
2994 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2995 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2997 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2999 GtkWidget *w, *item_hb;
3000 #if GTK_MAJOR_VERSION >= 2
3001 gchar *formatted_message;
3005 item_hb = gtk_hbox_new(FALSE, 1);
3007 w = BUTTON_NEW_FROM_STOCK(stock_item);
3008 WIDGET_SET_SIZE(w, 60, 60);
3009 #if GTK_MAJOR_VERSION >= 2
3010 gtk_button_set_label(GTK_BUTTON(w), label);
3012 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
3013 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
3015 w = gtk_label_new(message);
3016 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3017 #if GTK_MAJOR_VERSION >= 2
3018 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
3019 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
3020 g_free(formatted_message);
3023 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
3029 /* XXX - the layout has to be improved */
3033 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
3034 GtkWidget *w, *icon;
3038 welcome_scrollw = scrolled_window_new(NULL, NULL);
3040 welcome_hb = gtk_hbox_new(FALSE, 1);
3041 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
3043 welcome_vb = gtk_vbox_new(FALSE, 1);
3045 item_hb = gtk_hbox_new(FALSE, 1);
3047 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
3048 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
3050 #if GTK_MAJOR_VERSION < 2
3051 message = "Welcome to Ethereal!";
3053 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
3055 w = gtk_label_new(message);
3056 #if GTK_MAJOR_VERSION >= 2
3057 gtk_label_set_markup(GTK_LABEL(w), message);
3059 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3060 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3062 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3064 w = gtk_label_new("What would you like to do?");
3065 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
3066 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3069 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
3071 "Capture live data from your network",
3072 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
3073 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3076 item_hb = welcome_item(GTK_STOCK_OPEN,
3078 "Open a previously captured file",
3079 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
3080 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3082 #if (GLIB_MAJOR_VERSION >= 2)
3083 item_hb = welcome_item(GTK_STOCK_HOME,
3085 "Visit the Ethereal homepage",
3086 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
3087 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3091 w = gtk_label_new("");
3092 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
3094 w = gtk_label_new("");
3095 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3097 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3099 w = gtk_label_new("");
3100 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3102 gtk_widget_show_all(welcome_hb);
3104 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3106 gtk_widget_show_all(welcome_scrollw);
3108 return welcome_scrollw;
3115 /* this is just a dummy to fill up window space, simply showing nothing */
3116 return scrolled_window_new(NULL, NULL);
3122 * XXX - this doesn't appear to work with the paned widgets in
3123 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3124 * and the other pane doesn't grow to take up the rest of the pane.
3125 * It does appear to work with GTK+ 2.x.
3128 main_widgets_show_or_hide(void)
3130 gboolean main_second_pane_show;
3132 if (recent.main_toolbar_show) {
3133 gtk_widget_show(main_tb);
3135 gtk_widget_hide(main_tb);
3139 * Show the status hbox if either:
3141 * 1) we're showing the filter toolbar and we want it in the status
3146 * 2) we're showing the status bar.
3148 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3149 recent.statusbar_show) {
3150 gtk_widget_show(stat_hbox);
3152 gtk_widget_hide(stat_hbox);
3155 if (recent.statusbar_show) {
3156 gtk_widget_show(status_pane);
3158 gtk_widget_hide(status_pane);
3161 if (recent.filter_toolbar_show) {
3162 gtk_widget_show(filter_tb);
3164 gtk_widget_hide(filter_tb);
3167 if (recent.packet_list_show && have_capture_file) {
3168 gtk_widget_show(pkt_scrollw);
3170 gtk_widget_hide(pkt_scrollw);
3173 if (recent.tree_view_show && have_capture_file) {
3174 gtk_widget_show(tv_scrollw);
3176 gtk_widget_hide(tv_scrollw);
3179 if (recent.byte_view_show && have_capture_file) {
3180 gtk_widget_show(byte_nb_ptr);
3182 gtk_widget_hide(byte_nb_ptr);
3185 if (have_capture_file) {
3186 gtk_widget_show(main_first_pane);
3188 gtk_widget_hide(main_first_pane);
3192 * Is anything in "main_second_pane" visible?
3193 * If so, show it, otherwise hide it.
3195 main_second_pane_show = FALSE;
3196 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3197 &main_second_pane_show);
3198 if (main_second_pane_show) {
3199 gtk_widget_show(main_second_pane);
3201 gtk_widget_hide(main_second_pane);
3204 if (!have_capture_file) {
3206 gtk_widget_show(welcome_pane);
3209 gtk_widget_hide(welcome_pane);
3214 #if GTK_MAJOR_VERSION >= 2
3215 /* called, when the window state changes (minimized, maximized, ...) */
3217 window_state_event_cb (GtkWidget *widget _U_,
3221 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3223 if( (event->type) == (GDK_WINDOW_STATE)) {
3224 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3225 /* we might have dialogs popped up while we where iconified,
3227 display_queued_messages();
3236 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3239 *filter_bt, *filter_cm, *filter_te,
3240 *filter_add_expr_bt,
3243 GList *dfilter_list = NULL;
3244 GtkTooltips *tooltips;
3245 GtkAccelGroup *accel;
3247 /* Display filter construct dialog has an Apply button, and "OK" not
3248 only sets our text widget, it activates it (i.e., it causes us to
3249 filter the capture). */
3250 static construct_args_t args = {
3251 "Ethereal: Display Filter",
3256 /* use user-defined title if preference is set */
3257 title = create_user_window_title("The Ethereal Network Analyzer");
3260 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3263 tooltips = gtk_tooltips_new();
3266 #if GTK_MAJOR_VERSION < 2
3267 /* has to be done, after top_level window is created */
3268 app_font_gtk1_init(top_level);
3272 gtk_widget_set_name(top_level, "main window");
3273 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3275 #if GTK_MAJOR_VERSION >= 2
3276 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3277 G_CALLBACK (window_state_event_cb), NULL);
3280 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3282 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3283 main_vbox = gtk_vbox_new(FALSE, 1);
3284 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3285 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3286 gtk_widget_show(main_vbox);
3289 menubar = main_menu_new(&accel);
3290 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3291 gtk_widget_show(menubar);
3294 main_tb = toolbar_new();
3295 gtk_widget_show (main_tb);
3298 pkt_scrollw = packet_list_new(prefs);
3299 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3300 gtk_widget_show(pkt_scrollw);
3303 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3304 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3305 gtk_widget_show(tv_scrollw);
3307 #if GTK_MAJOR_VERSION < 2
3308 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3309 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3312 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3313 "changed", tree_view_selection_changed_cb, NULL);
3315 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3316 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3317 gtk_widget_show(tree_view);
3320 byte_nb_ptr = byte_view_new();
3321 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3322 gtk_widget_show(byte_nb_ptr);
3324 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3325 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3328 /* Panes for the packet list, tree, and byte view */
3329 main_pane_v1 = gtk_vpaned_new();
3330 gtk_widget_show(main_pane_v1);
3331 main_pane_v2 = gtk_vpaned_new();
3332 gtk_widget_show(main_pane_v2);
3333 main_pane_h1 = gtk_hpaned_new();
3334 gtk_widget_show(main_pane_h1);
3335 main_pane_h2 = gtk_hpaned_new();
3336 gtk_widget_show(main_pane_h2);
3338 /* filter toolbar */
3339 #if GTK_MAJOR_VERSION < 2
3340 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3343 filter_tb = gtk_toolbar_new();
3344 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3345 GTK_ORIENTATION_HORIZONTAL);
3346 #endif /* GTK_MAJOR_VERSION */
3347 gtk_widget_show(filter_tb);
3349 /* Create the "Filter:" button */
3350 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3351 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3352 gtk_widget_show(filter_bt);
3353 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3355 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3356 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3358 /* Create the filter combobox */
3359 filter_cm = gtk_combo_new();
3360 dfilter_list = NULL;
3361 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3362 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3363 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3364 filter_te = GTK_COMBO(filter_cm)->entry;
3365 main_display_filter_widget=filter_te;
3366 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3367 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3368 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3369 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3370 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3371 WIDGET_SET_SIZE(filter_cm, 400, -1);
3372 gtk_widget_show(filter_cm);
3373 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3375 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3376 gtk_tooltips_set_tip(tooltips, filter_te,
3377 "Enter a display filter, or choose one of your recently used filters. "
3378 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3381 /* Create the "Add Expression..." button, to pop up a dialog
3382 for constructing filter comparison expressions. */
3383 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3384 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3385 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3386 gtk_widget_show(filter_add_expr_bt);
3387 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3388 "Add an expression to this filter string", "Private");
3390 /* Create the "Clear" button */
3391 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3392 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3393 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3394 gtk_widget_show(filter_reset);
3395 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3396 "Clear this filter string and update the display", "Private");
3398 /* Create the "Apply" button */
3399 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3400 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3401 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3402 gtk_widget_show(filter_apply);
3403 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3404 "Apply this filter string to the display", "Private");
3406 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3407 * of any widget that ends up calling a callback which needs
3408 * that text entry pointer */
3409 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3410 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3412 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3414 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3416 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3418 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3420 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3422 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3424 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3426 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3428 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3430 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3432 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3434 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3436 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3438 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3439 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3440 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3442 /* info (main) statusbar */
3443 info_bar = info_bar_new();
3444 gtk_widget_show(info_bar);
3446 /* packets statusbar */
3447 packets_bar = packets_bar_new();
3448 gtk_widget_show(packets_bar);
3450 /* Filter/status hbox */
3451 stat_hbox = gtk_hbox_new(FALSE, 1);
3452 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3453 gtk_widget_show(stat_hbox);
3455 /* Pane for the statusbar */
3456 status_pane = gtk_hpaned_new();
3457 gtk_widget_show(status_pane);
3459 /* Pane for the welcome screen */
3460 welcome_pane = welcome_new();
3461 gtk_widget_show(welcome_pane);
3465 show_main_window(gboolean doing_work)
3467 main_set_for_capture_file(doing_work);
3469 /*** we have finished all init things, show the main window ***/
3470 gtk_widget_show(top_level);
3472 /* the window can be maximized only, if it's visible, so do it after show! */
3473 main_load_window_geometry(top_level);
3475 /* process all pending GUI events before continue */
3476 while (gtk_events_pending()) gtk_main_iteration();
3478 /* Pop up any queued-up alert boxes. */
3479 display_queued_messages();