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 /* Restore the standard title bar message. */
1262 set_main_window_name("The Ethereal Network Analyzer");
1264 /* Disable all menu items that make sense only if you have a capture. */
1265 set_menus_for_capture_file(FALSE);
1266 set_menus_for_unsaved_capture_file(FALSE);
1267 set_menus_for_captured_packets(FALSE);
1268 set_menus_for_selected_packet(cf);
1269 set_menus_for_capture_in_progress(FALSE);
1270 set_menus_for_selected_tree_row(cf);
1272 /* Set up main window for no capture file. */
1273 main_set_for_capture_file(FALSE);
1275 main_window_update();
1279 main_cf_cb_file_closed(capture_file *cf _U_)
1281 if(close_dlg != NULL) {
1282 splash_destroy(close_dlg);
1286 /* go back to "No packets" */
1287 packets_bar_update();
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_)
1495 /* XXX - the time to stop the capture has been reduced (this was only a
1496 * problem on Win32 because of the capture piping), so showing a splash
1497 * isn't really necessary any longer. Unfortunately, the GTKClist packet
1498 * list seems to have problems updating after the dialog is closed, so
1499 * this was disabled here. */
1500 stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...",
1501 simple_dialog_primary_start(), simple_dialog_primary_end());
1502 #if GTK_MAJOR_VERSION >= 2
1503 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1505 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1513 main_cf_cb_packet_selected(gpointer data)
1515 capture_file *cf = data;
1517 /* Display the GUI protocol tree and hex dump.
1518 XXX - why do we dump core if we call "proto_tree_draw()"
1519 before calling "add_byte_views()"? */
1520 add_main_byte_views(cf->edt);
1521 main_proto_tree_draw(cf->edt->tree);
1523 /* A packet is selected. */
1524 set_menus_for_selected_packet(cf);
1528 main_cf_cb_packet_unselected(capture_file *cf)
1530 /* Clear out the display of that packet. */
1531 clear_tree_and_hex_views();
1533 /* No packet is selected. */
1534 set_menus_for_selected_packet(cf);
1538 main_cf_cb_field_unselected(capture_file *cf)
1540 statusbar_pop_field_msg();
1541 set_menus_for_selected_tree_row(cf);
1545 main_cf_cb_file_safe_started(gchar * filename)
1547 const gchar *name_ptr;
1550 name_ptr = get_basename(filename);
1552 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1554 statusbar_push_file_msg(save_msg);
1559 main_cf_cb_file_safe_finished(gpointer data _U_)
1561 /* Pop the "Saving:" message off the status bar. */
1562 statusbar_pop_file_msg();
1566 main_cf_cb_file_safe_failed(gpointer data _U_)
1568 /* Pop the "Saving:" message off the status bar. */
1569 statusbar_pop_file_msg();
1573 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1575 set_menus_for_unsaved_capture_file(FALSE);
1578 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1581 case(cf_cb_file_closing):
1582 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
1583 main_cf_cb_file_closing(data);
1585 case(cf_cb_file_closed):
1586 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
1587 main_cf_cb_file_closed(data);
1589 case(cf_cb_file_read_start):
1590 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read start");
1591 main_cf_cb_file_read_start(data);
1593 case(cf_cb_file_read_finished):
1594 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
1595 main_cf_cb_file_read_finished(data);
1598 case(cf_cb_live_capture_prepared):
1599 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
1600 main_cf_cb_live_capture_prepared(data);
1602 case(cf_cb_live_capture_update_started):
1603 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
1604 main_cf_cb_live_capture_update_started(data);
1606 case(cf_cb_live_capture_update_continue):
1607 /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
1608 main_cf_cb_live_capture_update_continue(data);
1610 case(cf_cb_live_capture_fixed_started):
1611 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
1612 main_cf_cb_live_capture_fixed_started(data);
1614 case(cf_cb_live_capture_update_finished):
1615 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
1616 main_cf_cb_live_capture_update_finished(data);
1618 case(cf_cb_live_capture_fixed_finished):
1619 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
1620 main_cf_cb_live_capture_fixed_finished(data);
1622 case(cf_cb_live_capture_stopping):
1623 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
1624 main_cf_cb_live_capture_stopping(data);
1627 case(cf_cb_packet_selected):
1628 main_cf_cb_packet_selected(data);
1630 case(cf_cb_packet_unselected):
1631 main_cf_cb_packet_unselected(data);
1633 case(cf_cb_field_unselected):
1634 main_cf_cb_field_unselected(data);
1636 case(cf_cb_file_safe_started):
1637 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe started");
1638 main_cf_cb_file_safe_started(data);
1640 case(cf_cb_file_safe_finished):
1641 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe finished");
1642 main_cf_cb_file_safe_finished(data);
1644 case(cf_cb_file_safe_reload_finished):
1645 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: reload finished");
1646 main_cf_cb_file_safe_reload_finished(data);
1648 case(cf_cb_file_safe_failed):
1649 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe failed");
1650 main_cf_cb_file_safe_failed(data);
1653 g_warning("main_cf_callback: event %u unknown", event);
1654 g_assert_not_reached();
1658 /* And now our feature presentation... [ fade to music ] */
1660 main(int argc, char *argv[])
1663 const char *command_name;
1668 extern char *optarg;
1669 gboolean arg_error = FALSE;
1677 char *gpf_path, *pf_path;
1678 char *cf_path, *df_path;
1679 char *gdp_path, *dp_path;
1680 int gpf_open_errno, gpf_read_errno;
1681 int pf_open_errno, pf_read_errno;
1682 int cf_open_errno, df_open_errno;
1683 int gdp_open_errno, gdp_read_errno;
1684 int dp_open_errno, dp_read_errno;
1687 gboolean start_capture = FALSE;
1690 GList *lt_list, *lt_entry;
1691 data_link_info_t *data_link_info;
1692 gchar err_str[PCAP_ERRBUF_SIZE];
1693 gchar *cant_get_if_list_errstr;
1694 gboolean stats_known;
1695 struct pcap_stat stats;
1697 gboolean capture_option_specified = FALSE;
1699 gint pl_size = 280, tv_size = 95, bv_size = 75;
1700 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1701 dfilter_t *rfcode = NULL;
1702 gboolean rfilter_parse_failed = FALSE;
1705 GtkWidget *splash_win = NULL;
1706 GLogLevelFlags log_flags;
1707 guint go_to_packet = 0;
1710 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1714 #define OPTSTRING_CHILD "W:Z:"
1715 #define OPTSTRING_WIN32 "B:"
1717 #define OPTSTRING_CHILD "W:"
1718 #define OPTSTRING_WIN32 ""
1721 #define OPTSTRING_CHILD ""
1722 #define OPTSTRING_WIN32 ""
1723 #endif /* HAVE_LIBPCAP */
1725 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1726 OPTSTRING_INIT OPTSTRING_WIN32;
1728 /* initialize memory allocation subsystem */
1732 /*** create the compile and runtime version strings ***/
1734 /* Load wpcap if possible. Do this before collecting the run-time version information */
1737 /* ... and also load the packet.dll from wpcap */
1738 wpcap_packet_load();
1740 /* Start windows sockets */
1741 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1744 /* Assemble the compile-time version information string */
1745 comp_info_str = g_string_new("Compiled ");
1746 g_string_append(comp_info_str, "with ");
1747 g_string_sprintfa(comp_info_str,
1748 #ifdef GTK_MAJOR_VERSION
1749 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1752 "GTK+ (version unknown)");
1755 g_string_append(comp_info_str, ", ");
1756 get_compiled_version_info(comp_info_str);
1758 /* Assemble the run-time version information string */
1759 runtime_info_str = g_string_new("Running ");
1760 get_runtime_version_info(runtime_info_str);
1763 /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1764 /* (e.g. don't start GTK+, if we only have to show the command line help) */
1765 optind_initial = optind;
1766 while ((opt = getopt(argc, argv, optstring)) != -1) {
1768 case 'h': /* Print help and exit */
1772 case 'v': /* Show version and exit */
1776 case 'G': /* dump various field or other infos, see handle_dashG_option() */
1777 /* If invoked with the "-G" flag, we dump out information based on
1778 the argument to the "-G" flag; if no argument is specified,
1779 for backwards compatibility we dump out a glossary of display
1782 We must do this before calling "gtk_init()", because "gtk_init()"
1783 tries to open an X display, and we don't want to have to do any X
1784 stuff just to do a build.
1786 Given that we call "gtk_init()" before doing the regular argument
1787 list processing, so that it can handle X and GTK+ arguments and
1788 remove them from the list at which we look, this means we must do
1789 this before doing the regular argument list processing, as well.
1793 you must give the "-G" flag as the first flag on the command line;
1795 you must give it as "-G", nothing more, nothing less;
1797 the first argument after the "-G" flag, if present, will be used
1798 to specify the information to dump;
1800 arguments after that will not be used. */
1801 handle_dashG_option(argc, argv, "ethereal");
1802 /* will never return! */
1808 /* set getopt index back to initial value, so it will start with the first command line parameter again */
1809 /* (XXX - this seems to be portable, but time will tell) */
1810 optind = optind_initial;
1813 /* Set the current locale according to the program environment.
1814 * We haven't localized anything, but some GTK widgets are localized
1815 * (the file selection dialogue, for example).
1816 * This also sets the C-language locale to the native environment. */
1819 /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1820 gtk_init (&argc, &argv);
1822 cf_callback_add(main_cf_callback, NULL);
1824 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1825 /* initialize our GTK eth_clist_type */
1826 init_eth_clist_type();
1829 ethereal_path = argv[0];
1831 /* Arrange that if we have no console window, and a GLib message logging
1832 routine is called to log a message, we pop up a console window.
1834 We do that by inserting our own handler for all messages logged
1835 to the default domain; that handler pops up a console if necessary,
1836 and then calls the default handler. */
1838 /* We might want to have component specific log levels later ... */
1840 /* the default_log_handler will use stdout, which makes trouble with the */
1841 /* capture child, as it uses stdout for it's sync_pipe */
1842 /* so do the filtering in the console_log_handler and not here */
1845 G_LOG_LEVEL_CRITICAL|
1846 G_LOG_LEVEL_WARNING|
1847 G_LOG_LEVEL_MESSAGE|
1850 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1852 g_log_set_handler(NULL,
1854 console_log_handler, NULL /* user_data */);
1855 g_log_set_handler(LOG_DOMAIN_MAIN,
1857 console_log_handler, NULL /* user_data */);
1860 g_log_set_handler(LOG_DOMAIN_CAPTURE,
1862 console_log_handler, NULL /* user_data */);
1863 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1865 console_log_handler, NULL /* user_data */);
1867 /* Set the initial values in the capture_opts. This might be overwritten
1868 by preference settings and then again by the command line parameters. */
1869 capture_opts_init(capture_opts, &cfile);
1871 capture_opts->snaplen = MIN_PACKET_SIZE;
1872 capture_opts->has_ring_num_files = TRUE;
1874 command_name = get_basename(ethereal_path);
1875 /* Set "capture_child" to indicate whether this is going to be a child
1876 process for a "-S" capture. */
1877 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1878 if (capture_child) {
1879 strcat(optstring, OPTSTRING_CHILD);
1883 /* We want a splash screen only if we're not a child process.
1884 We won't come till here, if we had a "console only" command line parameter. */
1888 splash_win = splash_new("Loading Ethereal ...");
1890 splash_update(splash_win, "Registering dissectors ...");
1892 /* Register all dissectors; we must do this before checking for the
1893 "-G" flag, as the "-G" flag dumps information registered by the
1894 dissectors, and we must do it before we read the preferences, in
1895 case any dissectors register preferences. */
1896 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1897 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1899 splash_update(splash_win, "Registering tap listeners ...");
1901 /* Register all tap listeners; we do this before we parse the arguments,
1902 as the "-z" argument can specify a registered tap. */
1904 /* we register the plugin taps before the other taps because
1905 stats_tree taps plugins will be registered as tap listeners
1906 by stats_tree_stat.c and need to registered before that */
1909 register_all_plugin_tap_listeners();
1912 register_all_tap_listeners();
1914 splash_update(splash_win, "Loading module preferences ...");
1916 /* Now register the preferences for any non-dissector modules.
1917 We must do that before we read the preferences as well. */
1918 prefs_register_modules();
1920 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1921 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1924 g_thread_init(NULL);
1926 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1927 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1929 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1930 /* this is to keep tap extensions updating once every 3 seconds */
1931 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1932 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1935 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1938 splash_update(splash_win, "Loading configuration files ...");
1940 /* Read the preference files. */
1941 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1942 &pf_open_errno, &pf_read_errno, &pf_path);
1943 if (gpf_path != NULL) {
1944 if (gpf_open_errno != 0) {
1945 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1946 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1947 strerror(gpf_open_errno));
1949 if (gpf_read_errno != 0) {
1950 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1951 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1952 strerror(gpf_read_errno));
1955 if (pf_path != NULL) {
1956 if (pf_open_errno != 0) {
1957 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1958 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1959 strerror(pf_open_errno));
1961 if (pf_read_errno != 0) {
1962 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1963 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1964 strerror(pf_read_errno));
1971 /* if the user wants a console to be always there, well, we should open one for him */
1972 if (prefs->gui_console_open == console_open_always) {
1978 /* If this is a capture child process, it should pay no attention
1979 to the "prefs.capture_prom_mode" setting in the preferences file;
1980 it should do what the parent process tells it to do, and if
1981 the parent process wants it not to run in promiscuous mode, it'll
1982 tell it so with a "-p" flag.
1984 Otherwise, set promiscuous mode from the preferences setting. */
1985 /* the same applies to other preferences settings as well. */
1986 if (capture_child) {
1987 auto_scroll_live = FALSE;
1989 capture_opts->promisc_mode = prefs->capture_prom_mode;
1990 capture_opts->show_info = prefs->capture_show_info;
1991 capture_opts->real_time_mode = prefs->capture_real_time;
1992 auto_scroll_live = prefs->capture_auto_scroll;
1995 #endif /* HAVE_LIBPCAP */
1997 /* Set the name resolution code's flags from the preferences. */
1998 g_resolv_flags = prefs->name_resolve;
2000 /* Read the capture filter file. */
2001 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
2002 if (cf_path != NULL) {
2003 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2004 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2005 strerror(cf_open_errno));
2009 /* Read the display filter file. */
2010 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
2011 if (df_path != NULL) {
2012 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2013 "Could not open your display filter file\n\"%s\": %s.", df_path,
2014 strerror(df_open_errno));
2018 /* Read the disabled protocols file. */
2019 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
2020 &dp_path, &dp_open_errno, &dp_read_errno);
2021 if (gdp_path != NULL) {
2022 if (gdp_open_errno != 0) {
2023 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2024 "Could not open global disabled protocols file\n\"%s\": %s.",
2025 gdp_path, strerror(gdp_open_errno));
2027 if (gdp_read_errno != 0) {
2028 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2029 "I/O error reading global disabled protocols file\n\"%s\": %s.",
2030 gdp_path, strerror(gdp_read_errno));
2034 if (dp_path != NULL) {
2035 if (dp_open_errno != 0) {
2036 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2037 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
2038 strerror(dp_open_errno));
2040 if (dp_read_errno != 0) {
2041 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2042 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2043 strerror(dp_read_errno));
2048 /* Read the (static part) of the recent file. Only the static part of it will be read, */
2049 /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2050 /* We have to do this already here, so command line parameters can overwrite these values. */
2051 recent_read_static(&rf_path, &rf_open_errno);
2053 init_cap_file(&cfile);
2055 /* Now get our args */
2056 while ((opt = getopt(argc, argv, optstring)) != -1) {
2058 /*** capture option specific ***/
2059 case 'a': /* autostop criteria */
2060 case 'b': /* Ringbuffer option */
2061 case 'c': /* Capture xxx packets */
2062 case 'f': /* capture filter */
2063 case 'k': /* Start capture immediately */
2064 case 'H': /* Hide capture info dialog box */
2065 case 'i': /* Use interface xxx */
2066 case 'p': /* Don't capture in promiscuous mode */
2067 case 'Q': /* Quit after capture (just capture to file) */
2068 case 's': /* Set the snapshot (capture) length */
2069 case 'S': /* "Sync" mode: used for following file ala tail -f */
2070 case 'w': /* Write to capture file xxx */
2071 case 'y': /* Set the pcap data link type */
2073 case 'B': /* Buffer size */
2074 /* Hidden option supporting Sync mode */
2075 case 'Z': /* Write to pipe FD XXX */
2078 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2080 capture_option_specified = TRUE;
2085 /* This is a hidden option supporting Sync mode, so we don't set
2086 * the error flags for the user in the non-libpcap case.
2088 case 'W': /* Write to capture file FD xxx */
2089 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2093 /*** all non capture option specific ***/
2094 case 'g': /* Go to packet */
2095 go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2097 case 'l': /* Automatic scrolling in live capture mode */
2099 auto_scroll_live = TRUE;
2101 capture_option_specified = TRUE;
2105 case 'L': /* Print list of link-layer types and exit */
2107 list_link_layer_types = TRUE;
2109 capture_option_specified = TRUE;
2113 case 'm': /* Fixed-width font for the display */
2114 if (prefs->PREFS_GUI_FONT_NAME != NULL)
2115 g_free(prefs->PREFS_GUI_FONT_NAME);
2116 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2118 case 'n': /* No name resolution */
2119 g_resolv_flags = RESOLV_NONE;
2121 case 'N': /* Select what types of addresses/port #s to resolve */
2122 if (g_resolv_flags == RESOLV_ALL)
2123 g_resolv_flags = RESOLV_NONE;
2124 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2125 if (badopt != '\0') {
2126 g_warning("ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2131 case 'o': /* Override preference from command line */
2132 switch (prefs_set_pref(optarg)) {
2135 case PREFS_SET_SYNTAX_ERR:
2136 g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2139 case PREFS_SET_NO_SUCH_PREF:
2140 /* not a preference, might be a recent setting */
2141 switch (recent_set_arg(optarg)) {
2144 case PREFS_SET_SYNTAX_ERR:
2145 /* shouldn't happen, checked already above */
2146 g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2149 case PREFS_SET_NO_SUCH_PREF:
2150 case PREFS_SET_OBSOLETE:
2151 g_warning("ethereal: -o flag \"%s\" specifies unknown preference/recent value",
2156 g_assert_not_reached();
2159 case PREFS_SET_OBSOLETE:
2160 g_warning("ethereal: -o flag \"%s\" specifies obsolete preference",
2165 g_assert_not_reached();
2168 case 'r': /* Read capture file xxx */
2169 /* We may set "last_open_dir" to "cf_name", and if we change
2170 "last_open_dir" later, we free the old value, so we have to
2171 set "cf_name" to something that's been allocated. */
2172 cf_name = g_strdup(optarg);
2174 case 'R': /* Read file filter */
2177 case 't': /* Time stamp type */
2178 if (strcmp(optarg, "r") == 0)
2179 timestamp_set_type(TS_RELATIVE);
2180 else if (strcmp(optarg, "a") == 0)
2181 timestamp_set_type(TS_ABSOLUTE);
2182 else if (strcmp(optarg, "ad") == 0)
2183 timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2184 else if (strcmp(optarg, "d") == 0)
2185 timestamp_set_type(TS_DELTA);
2187 g_warning("ethereal: Invalid time stamp type \"%s\"",
2189 g_warning("It must be \"r\" for relative, \"a\" for absolute,");
2190 g_warning("\"ad\" for absolute with date, or \"d\" for delta.");
2195 /* We won't call the init function for the stat this soon
2196 as it would disallow MATE's fields (which are registered
2197 by the preferences set callback) from being used as
2198 part of a tap filter. Instead, we just add the argument
2199 to a list of stat arguments. */
2200 if (!process_stat_cmd_arg(optarg)) {
2201 g_warning("ethereal: invalid -z argument.");
2202 g_warning(" -z argument must be one of :");
2203 list_stat_cmd_args();
2208 case '?': /* Bad flag - print usage message */
2209 g_warning("Bad flag");
2217 if (cf_name != NULL) {
2219 * Input file name specified with "-r" *and* specified as a regular
2220 * command-line argument.
2222 g_warning("File name specified both with -r and regular argument");
2226 * Input file name not specified with "-r", and a command-line argument
2227 * was specified; treat it as the input file name.
2229 * Yes, this is different from tethereal, where non-flag command-line
2230 * arguments are a filter, but this works better on GUI desktops
2231 * where a command can be specified to be run to open a particular
2232 * file - yes, you could have "-r" as the last part of the command,
2233 * but that's a bit ugly.
2235 cf_name = g_strdup(argv[0]);
2245 * Extra command line arguments were specified; complain.
2247 g_warning("Invalid argument: %s", argv[0]);
2252 #ifndef HAVE_LIBPCAP
2253 if (capture_option_specified) {
2254 g_warning("This version of Ethereal was not built with support for capturing packets.");
2262 if (start_capture && list_link_layer_types) {
2263 /* Specifying *both* is bogus. */
2264 g_warning("ethereal: You can't specify both -L and a live capture.");
2268 if (list_link_layer_types) {
2269 /* We're supposed to list the link-layer types for an interface;
2270 did the user also specify a capture file to be read? */
2272 /* Yes - that's bogus. */
2273 g_warning("ethereal: You can't specify -L and a capture file to be read.");
2276 /* No - did they specify a ring buffer option? */
2277 if (capture_opts->multi_files_on) {
2278 g_warning("ethereal: Ring buffer requested, but a capture isn't being done.");
2282 /* We're supposed to do a live capture; did the user also specify
2283 a capture file to be read? */
2284 if (start_capture && cf_name) {
2285 /* Yes - that's bogus. */
2286 g_warning("ethereal: You can't specify both a live capture and a capture file to be read.");
2290 /* No - was the ring buffer option specified and, if so, does it make
2292 if (capture_opts->multi_files_on) {
2293 /* Ring buffer works only under certain conditions:
2294 a) ring buffer does not work with temporary files;
2295 b) real_time_mode and multi_files_on are mutually exclusive -
2296 real_time_mode takes precedence;
2297 c) it makes no sense to enable the ring buffer if the maximum
2298 file size is set to "infinite". */
2299 if (capture_opts->save_file == NULL) {
2300 g_warning("ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.");
2301 capture_opts->multi_files_on = FALSE;
2303 /* if (capture_opts->real_time_mode) {
2304 g_warning("ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2305 capture_opts->multi_files_on = FALSE;
2307 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2308 g_warning("ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.");
2309 /* XXX - this must be redesigned as the conditions changed */
2310 /* capture_opts->multi_files_on = FALSE;*/
2315 if (start_capture || list_link_layer_types) {
2316 /* Did the user specify an interface to use? */
2317 if (capture_opts->iface == NULL) {
2318 /* No - is a default specified in the preferences file? */
2319 if (prefs->capture_device != NULL) {
2321 capture_opts->iface = g_strdup(get_if_name(prefs->capture_device));
2323 /* No - pick the first one from the list of interfaces. */
2324 if_list = get_interface_list(&err, err_str);
2325 if (if_list == NULL) {
2328 case CANT_GET_INTERFACE_LIST:
2329 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2330 g_warning("%s", cant_get_if_list_errstr);
2331 g_free(cant_get_if_list_errstr);
2334 case NO_INTERFACES_FOUND:
2335 g_warning("ethereal: There are no interfaces on which a capture can be done");
2340 if_info = if_list->data; /* first interface */
2341 capture_opts->iface = g_strdup(if_info->name);
2342 free_interface_list(if_list);
2347 if (list_link_layer_types) {
2348 /* Get the list of link-layer types for the capture device. */
2349 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2350 if (lt_list == NULL) {
2351 if (err_str[0] != '\0') {
2352 g_warning("ethereal: The list of data link types for the capture device could not be obtained (%s)."
2353 "Please check to make sure you have sufficient permissions, and that\n"
2354 "you have the proper interface or pipe specified.\n", err_str);
2356 g_warning("ethereal: The capture device has no data link types.");
2359 g_warning("Data link types (use option -y to set):");
2360 for (lt_entry = lt_list; lt_entry != NULL;
2361 lt_entry = g_list_next(lt_entry)) {
2362 data_link_info = lt_entry->data;
2363 g_warning(" %s", data_link_info->name);
2364 if (data_link_info->description != NULL)
2365 g_warning(" (%s)", data_link_info->description);
2367 g_warning(" (not supported)");
2370 free_pcap_linktype_list(lt_list);
2374 if (capture_opts->has_snaplen) {
2375 if (capture_opts->snaplen < 1)
2376 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2377 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2378 capture_opts->snaplen = MIN_PACKET_SIZE;
2381 /* Check the value range of the ringbuffer_num_files parameter */
2382 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2383 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2384 #if RINGBUFFER_MIN_NUM_FILES > 0
2385 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2386 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2388 #endif /* HAVE_LIBPCAP */
2390 /* Notify all registered modules that have had any of their preferences
2391 changed either from one of the preferences file or from the command
2392 line that their preferences have changed. */
2395 /* disabled protocols as per configuration file */
2396 if (gdp_path == NULL && dp_path == NULL) {
2397 set_disabled_protos_list();
2400 /* Build the column format array */
2401 col_setup(&cfile.cinfo, prefs->num_cols);
2402 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2403 cfile.cinfo.col_fmt[i] = get_column_format(i);
2404 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2405 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2407 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2408 cfile.cinfo.col_data[i] = NULL;
2409 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2410 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2412 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2413 cfile.cinfo.col_fence[i] = 0;
2414 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2415 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2418 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2421 for (j = 0; j < NUM_COL_FMTS; j++) {
2422 if (!cfile.cinfo.fmt_matx[i][j])
2425 if (cfile.cinfo.col_first[j] == -1)
2426 cfile.cinfo.col_first[j] = i;
2427 cfile.cinfo.col_last[j] = i;
2431 /* read in rc file from global and personal configuration paths. */
2432 rc_file = get_datafile_path(RC_FILE);
2433 gtk_rc_parse(rc_file);
2434 rc_file = get_persconffile_path(RC_FILE, FALSE);
2435 gtk_rc_parse(rc_file);
2438 font_init(capture_child);
2443 /* close the splash screen, as we are going to open the main window now */
2444 splash_destroy(splash_win);
2448 /* Is this a "child" ethereal, which is only supposed to pop up a
2449 capture box to let us stop the capture, and run a capture
2450 to a file that our parent will read? */
2451 if (capture_child) {
2452 /* This is the child process of a capture session,
2453 so just do the low-level work of a capture - don't create
2454 a temporary file and fork off *another* child process (so don't
2455 call "capture_start()"). */
2457 /* Pop up any queued-up alert boxes. */
2458 display_queued_messages();
2460 /* Now start the capture.
2461 After the capture is done; there's nothing more for us to do. */
2463 /* XXX - hand these stats to the parent process */
2464 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2468 /* capture failed */
2474 /***********************************************************************/
2475 /* Everything is prepared now, preferences and command line was read in,
2476 we are NOT a child window for a synced capture. */
2478 /* Pop up the main window. */
2479 create_main_window(pl_size, tv_size, bv_size, prefs);
2481 /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2482 recent_read_dynamic(&rf_path, &rf_open_errno);
2483 color_filters_enable(recent.packet_list_colorize);
2485 /* rearrange all the widgets as we now have all recent settings ready for this */
2486 main_widgets_rearrange();
2488 /* Fill in column titles. This must be done after the top level window
2491 XXX - is that still true, with fixed-width columns? */
2492 packet_list_set_column_titles();
2494 menu_recent_read_finished();
2496 switch (user_font_apply()) {
2499 case FA_FONT_NOT_RESIZEABLE:
2500 /* "user_font_apply()" popped up an alert box. */
2501 /* turn off zooming - font can't be resized */
2502 case FA_FONT_NOT_AVAILABLE:
2503 /* XXX - did we successfully load the un-zoomed version earlier?
2504 If so, this *probably* means the font is available, but not at
2505 this particular zoom level, but perhaps some other failure
2506 occurred; I'm not sure you can determine which is the case,
2508 /* turn off zooming - zoom level is unavailable */
2510 /* in any other case than FA_SUCCESS, turn off zooming */
2511 recent.gui_zoom_level = 0;
2512 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2515 dnd_init(top_level);
2518 color_filters_init();
2521 /* the window can be sized only, if it's not already shown, so do it now! */
2522 main_load_window_geometry(top_level);
2524 /* If we were given the name of a capture file, read it in now;
2525 we defer it until now, so that, if we can't open it, and pop
2526 up an alert box, the alert box is more likely to come up on
2527 top of the main window - but before the preference-file-error
2528 alert box, so, if we get one of those, it's more likely to come
2531 show_main_window(TRUE);
2532 if (rfilter != NULL) {
2533 if (!dfilter_compile(rfilter, &rfcode)) {
2534 bad_dfilter_alert_box(rfilter);
2535 rfilter_parse_failed = TRUE;
2538 if (!rfilter_parse_failed) {
2539 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2540 /* "cf_open()" succeeded, so it closed the previous
2541 capture file, and thus destroyed any previous read filter
2542 attached to "cf". */
2544 cfile.rfcode = rfcode;
2545 /* Open stat windows; we do so after creating the main window,
2546 to avoid GTK warnings, and after successfully opening the
2547 capture file, so we know we have something to compute stats
2548 on, and after registering all dissectors, so that MATE will
2549 have registered its field array and we can have a tap filter
2550 with one of MATE's late-registered fields as part of the
2552 start_requested_stats();
2554 /* Read the capture file. */
2555 switch (cf_read(&cfile)) {
2559 /* Just because we got an error, that doesn't mean we were unable
2560 to read any of the file; we handle what we could get from the
2562 /* if the user told us to jump to a specific packet, do it now */
2563 if(go_to_packet != 0) {
2564 cf_goto_frame(&cfile, go_to_packet);
2568 case CF_READ_ABORTED:
2573 /* Save the name of the containing directory specified in the
2574 path name, if any; we can write over cf_name, which is a
2575 good thing, given that "get_dirname()" does write over its
2577 s = get_dirname(cf_name);
2578 /* we might already set this from the recent file, don't overwrite this */
2579 if(get_last_open_dir() == NULL)
2580 set_last_open_dir(s);
2585 dfilter_free(rfcode);
2586 cfile.rfcode = NULL;
2587 show_main_window(FALSE);
2588 set_menus_for_capture_in_progress(FALSE);
2593 if (start_capture) {
2594 if (capture_opts->save_file != NULL) {
2595 /* Save the directory name for future file dialogs. */
2596 /* (get_dirname overwrites filename) */
2597 s = get_dirname(g_strdup(capture_opts->save_file));
2598 set_last_open_dir(s);
2601 /* "-k" was specified; start a capture. */
2602 show_main_window(TRUE);
2603 if (capture_start(capture_opts)) {
2604 /* The capture started. Open stat windows; we do so after creating
2605 the main window, to avoid GTK warnings, and after successfully
2606 opening the capture file, so we know we have something to compute
2607 stats on, and after registering all dissectors, so that MATE will
2608 have registered its field array and we can have a tap filter with
2609 one of MATE's late-registered fields as part of the filter. */
2610 start_requested_stats();
2614 show_main_window(FALSE);
2615 set_menus_for_capture_in_progress(FALSE);
2618 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2619 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2620 if (capture_opts->cfilter) {
2621 g_free(capture_opts->cfilter);
2623 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2625 #else /* HAVE_LIBPCAP */
2626 show_main_window(FALSE);
2627 set_menus_for_capture_in_progress(FALSE);
2628 #endif /* HAVE_LIBPCAP */
2631 /* we'll enter the GTK loop now and hand the control over to GTK ... */
2633 /* ... back from GTK, we're going down now! */
2639 /* hide the (unresponsive) main window, while asking the user to close the console window */
2640 gtk_widget_hide(top_level);
2642 /* Shutdown windows sockets */
2645 /* For some unknown reason, the "atexit()" call in "create_console()"
2646 doesn't arrange that "destroy_console()" be called when we exit,
2647 so we call it here if a console was created. */
2653 /* This isn't reached, but we need it to keep GCC from complaining
2654 that "main()" returns without returning a value - it knows that
2655 "exit()" never returns, but it doesn't know that "gtk_exit()"
2656 doesn't, as GTK+ doesn't declare it with the attribute
2658 return 0; /* not reached */
2663 /* We build this as a GUI subsystem application on Win32, so
2664 "WinMain()", not "main()", gets called.
2666 Hack shamelessly stolen from the Win32 port of the GIMP. */
2668 #define _stdcall __attribute__((stdcall))
2672 WinMain (struct HINSTANCE__ *hInstance,
2673 struct HINSTANCE__ *hPrevInstance,
2677 has_console = FALSE;
2678 return main (__argc, __argv);
2682 * If this application has no console window to which its standard output
2683 * would go, create one.
2686 create_console(void)
2689 /* We have no console to which to print the version string, so
2690 create one and make it the standard input, output, and error. */
2691 if (!AllocConsole())
2692 return; /* couldn't create console */
2693 freopen("CONIN$", "r", stdin);
2694 freopen("CONOUT$", "w", stdout);
2695 freopen("CONOUT$", "w", stderr);
2697 /* Well, we have a console now. */
2700 /* Now register "destroy_console()" as a routine to be called just
2701 before the application exits, so that we can destroy the console
2702 after the user has typed a key (so that the console doesn't just
2703 disappear out from under them, giving the user no chance to see
2704 the message(s) we put in there). */
2705 atexit(destroy_console);
2708 SetConsoleTitle("Ethereal Capture Child Debug Console");
2710 SetConsoleTitle("Ethereal Debug Console");
2716 destroy_console(void)
2718 if (has_console && !capture_child) {
2719 printf("\n\nPress any key to exit\n");
2727 /* This routine should not be necessary, at least as I read the GLib
2728 source code, as it looks as if GLib is, on Win32, *supposed* to
2729 create a console window into which to display its output.
2731 That doesn't happen, however. I suspect there's something completely
2732 broken about that code in GLib-for-Win32, and that it may be related
2733 to the breakage that forces us to just call "printf()" on the message
2734 rather than passing the message on to "g_log_default_handler()"
2735 (which is the routine that does the aforementioned non-functional
2736 console window creation). */
2738 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2739 const char *message, gpointer user_data _U_)
2746 /* ignore log message, if log_level isn't interesting */
2747 if( !(log_level & G_LOG_LEVEL_MASK & prefs.console_log_level)) {
2751 /* create a "timestamp" */
2753 today = localtime(&curr);
2756 if (prefs.gui_console_open != console_open_never) {
2760 /* For some unknown reason, the above doesn't appear to actually cause
2761 anything to be sent to the standard output, so we'll just splat the
2762 message out directly, just to make sure it gets out. */
2764 switch(log_level & G_LOG_LEVEL_MASK) {
2765 case G_LOG_LEVEL_ERROR:
2768 case G_LOG_LEVEL_CRITICAL:
2771 case G_LOG_LEVEL_WARNING:
2774 case G_LOG_LEVEL_MESSAGE:
2777 case G_LOG_LEVEL_INFO:
2780 case G_LOG_LEVEL_DEBUG:
2784 fprintf(stderr, "unknown log_level %u\n", log_level);
2786 g_assert_not_reached();
2789 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2790 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2791 today->tm_hour, today->tm_min, today->tm_sec,
2792 log_domain != NULL ? log_domain : "",
2796 g_log_default_handler(log_domain, log_level, message, user_data);
2802 static GtkWidget *info_bar_new(void)
2804 /* tip: tooltips don't work on statusbars! */
2805 info_bar = gtk_statusbar_new();
2806 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2807 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2808 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2809 #if GTK_MAJOR_VERSION >= 2
2810 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2812 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2817 static GtkWidget *packets_bar_new(void)
2819 /* tip: tooltips don't work on statusbars! */
2820 packets_bar = gtk_statusbar_new();
2821 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2822 packets_bar_update();
2829 * Helper for main_widgets_rearrange()
2831 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2832 gtk_container_remove(GTK_CONTAINER(data), widget);
2835 static GtkWidget *main_widget_layout(gint layout_content)
2837 switch(layout_content) {
2838 case(layout_pane_content_none):
2841 case(layout_pane_content_plist):
2844 case(layout_pane_content_pdetails):
2847 case(layout_pane_content_pbytes):
2851 g_assert_not_reached();
2858 * Rearrange the main window widgets
2860 void main_widgets_rearrange(void) {
2861 GtkWidget *first_pane_widget1, *first_pane_widget2;
2862 GtkWidget *second_pane_widget1, *second_pane_widget2;
2863 gboolean split_top_left;
2865 /* be a bit faster */
2866 gtk_widget_hide(main_vbox);
2868 /* be sure, we don't loose a widget while rearranging */
2869 gtk_widget_ref(menubar);
2870 gtk_widget_ref(main_tb);
2871 gtk_widget_ref(filter_tb);
2872 gtk_widget_ref(pkt_scrollw);
2873 gtk_widget_ref(tv_scrollw);
2874 gtk_widget_ref(byte_nb_ptr);
2875 gtk_widget_ref(stat_hbox);
2876 gtk_widget_ref(info_bar);
2877 gtk_widget_ref(packets_bar);
2878 gtk_widget_ref(status_pane);
2879 gtk_widget_ref(main_pane_v1);
2880 gtk_widget_ref(main_pane_v2);
2881 gtk_widget_ref(main_pane_h1);
2882 gtk_widget_ref(main_pane_h2);
2883 gtk_widget_ref(welcome_pane);
2885 /* empty all containers participating */
2886 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2887 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2888 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2889 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2890 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2891 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2892 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2894 /* add the menubar always at the top */
2895 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2898 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2900 /* filter toolbar in toolbar area */
2901 if (!prefs.filter_toolbar_show_in_statusbar) {
2902 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2905 /* fill the main layout panes */
2906 switch(prefs.gui_layout_type) {
2907 case(layout_type_5):
2908 main_first_pane = main_pane_v1;
2909 main_second_pane = main_pane_v2;
2910 split_top_left = FALSE;
2912 case(layout_type_2):
2913 main_first_pane = main_pane_v1;
2914 main_second_pane = main_pane_h1;
2915 split_top_left = FALSE;
2917 case(layout_type_1):
2918 main_first_pane = main_pane_v1;
2919 main_second_pane = main_pane_h1;
2920 split_top_left = TRUE;
2922 case(layout_type_4):
2923 main_first_pane = main_pane_h1;
2924 main_second_pane = main_pane_v1;
2925 split_top_left = FALSE;
2927 case(layout_type_3):
2928 main_first_pane = main_pane_h1;
2929 main_second_pane = main_pane_v1;
2930 split_top_left = TRUE;
2932 case(layout_type_6):
2933 main_first_pane = main_pane_h1;
2934 main_second_pane = main_pane_h2;
2935 split_top_left = FALSE;
2938 main_first_pane = NULL;
2939 main_second_pane = NULL;
2940 split_top_left = FALSE;
2941 g_assert_not_reached();
2943 if (split_top_left) {
2944 first_pane_widget1 = main_second_pane;
2945 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2946 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2947 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2949 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2950 first_pane_widget2 = main_second_pane;
2951 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2952 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2954 if (first_pane_widget1 != NULL)
2955 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2956 if (first_pane_widget2 != NULL)
2957 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2958 if (second_pane_widget1 != NULL)
2959 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2960 if (second_pane_widget2 != NULL)
2961 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2963 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2966 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2968 /* statusbar hbox */
2969 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2971 /* filter toolbar in statusbar hbox */
2972 if (prefs.filter_toolbar_show_in_statusbar) {
2973 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2977 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2978 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2979 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2981 /* hide widgets on users recent settings */
2982 main_widgets_show_or_hide();
2984 gtk_widget_show(main_vbox);
2988 is_widget_visible(GtkWidget *widget, gpointer data)
2990 gboolean *is_visible = data;
2993 if (GTK_WIDGET_VISIBLE(widget))
3000 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
3001 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
3003 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
3005 GtkWidget *w, *item_hb;
3006 #if GTK_MAJOR_VERSION >= 2
3007 gchar *formatted_message;
3011 item_hb = gtk_hbox_new(FALSE, 1);
3013 w = BUTTON_NEW_FROM_STOCK(stock_item);
3014 WIDGET_SET_SIZE(w, 60, 60);
3015 #if GTK_MAJOR_VERSION >= 2
3016 gtk_button_set_label(GTK_BUTTON(w), label);
3018 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
3019 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
3021 w = gtk_label_new(message);
3022 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3023 #if GTK_MAJOR_VERSION >= 2
3024 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
3025 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
3026 g_free(formatted_message);
3029 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
3035 /* XXX - the layout has to be improved */
3039 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
3040 GtkWidget *w, *icon;
3044 welcome_scrollw = scrolled_window_new(NULL, NULL);
3046 welcome_hb = gtk_hbox_new(FALSE, 1);
3047 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
3049 welcome_vb = gtk_vbox_new(FALSE, 1);
3051 item_hb = gtk_hbox_new(FALSE, 1);
3053 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
3054 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
3056 #if GTK_MAJOR_VERSION < 2
3057 message = "Welcome to Ethereal!";
3059 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
3061 w = gtk_label_new(message);
3062 #if GTK_MAJOR_VERSION >= 2
3063 gtk_label_set_markup(GTK_LABEL(w), message);
3065 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3066 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3068 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3070 w = gtk_label_new("What would you like to do?");
3071 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
3072 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3075 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
3077 "Capture live data from your network",
3078 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
3079 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3082 item_hb = welcome_item(GTK_STOCK_OPEN,
3084 "Open a previously captured file",
3085 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
3086 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3088 #if (GLIB_MAJOR_VERSION >= 2)
3089 item_hb = welcome_item(GTK_STOCK_HOME,
3091 "Visit the Ethereal homepage",
3092 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
3093 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3097 w = gtk_label_new("");
3098 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
3100 w = gtk_label_new("");
3101 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3103 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3105 w = gtk_label_new("");
3106 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3108 gtk_widget_show_all(welcome_hb);
3110 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3112 gtk_widget_show_all(welcome_scrollw);
3114 return welcome_scrollw;
3121 /* this is just a dummy to fill up window space, simply showing nothing */
3122 return scrolled_window_new(NULL, NULL);
3128 * XXX - this doesn't appear to work with the paned widgets in
3129 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3130 * and the other pane doesn't grow to take up the rest of the pane.
3131 * It does appear to work with GTK+ 2.x.
3134 main_widgets_show_or_hide(void)
3136 gboolean main_second_pane_show;
3138 if (recent.main_toolbar_show) {
3139 gtk_widget_show(main_tb);
3141 gtk_widget_hide(main_tb);
3145 * Show the status hbox if either:
3147 * 1) we're showing the filter toolbar and we want it in the status
3152 * 2) we're showing the status bar.
3154 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3155 recent.statusbar_show) {
3156 gtk_widget_show(stat_hbox);
3158 gtk_widget_hide(stat_hbox);
3161 if (recent.statusbar_show) {
3162 gtk_widget_show(status_pane);
3164 gtk_widget_hide(status_pane);
3167 if (recent.filter_toolbar_show) {
3168 gtk_widget_show(filter_tb);
3170 gtk_widget_hide(filter_tb);
3173 if (recent.packet_list_show && have_capture_file) {
3174 gtk_widget_show(pkt_scrollw);
3176 gtk_widget_hide(pkt_scrollw);
3179 if (recent.tree_view_show && have_capture_file) {
3180 gtk_widget_show(tv_scrollw);
3182 gtk_widget_hide(tv_scrollw);
3185 if (recent.byte_view_show && have_capture_file) {
3186 gtk_widget_show(byte_nb_ptr);
3188 gtk_widget_hide(byte_nb_ptr);
3191 if (have_capture_file) {
3192 gtk_widget_show(main_first_pane);
3194 gtk_widget_hide(main_first_pane);
3198 * Is anything in "main_second_pane" visible?
3199 * If so, show it, otherwise hide it.
3201 main_second_pane_show = FALSE;
3202 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3203 &main_second_pane_show);
3204 if (main_second_pane_show) {
3205 gtk_widget_show(main_second_pane);
3207 gtk_widget_hide(main_second_pane);
3210 if (!have_capture_file) {
3212 gtk_widget_show(welcome_pane);
3215 gtk_widget_hide(welcome_pane);
3220 #if GTK_MAJOR_VERSION >= 2
3221 /* called, when the window state changes (minimized, maximized, ...) */
3223 window_state_event_cb (GtkWidget *widget _U_,
3227 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3229 if( (event->type) == (GDK_WINDOW_STATE)) {
3230 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3231 /* we might have dialogs popped up while we where iconified,
3233 display_queued_messages();
3242 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3245 *filter_bt, *filter_cm, *filter_te,
3246 *filter_add_expr_bt,
3249 GList *dfilter_list = NULL;
3250 GtkTooltips *tooltips;
3251 GtkAccelGroup *accel;
3253 /* Display filter construct dialog has an Apply button, and "OK" not
3254 only sets our text widget, it activates it (i.e., it causes us to
3255 filter the capture). */
3256 static construct_args_t args = {
3257 "Ethereal: Display Filter",
3262 /* use user-defined title if preference is set */
3263 title = create_user_window_title("The Ethereal Network Analyzer");
3266 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3269 tooltips = gtk_tooltips_new();
3272 #if GTK_MAJOR_VERSION < 2
3273 /* has to be done, after top_level window is created */
3274 app_font_gtk1_init(top_level);
3278 gtk_widget_set_name(top_level, "main window");
3279 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3281 #if GTK_MAJOR_VERSION >= 2
3282 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3283 G_CALLBACK (window_state_event_cb), NULL);
3286 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3288 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3289 main_vbox = gtk_vbox_new(FALSE, 1);
3290 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3291 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3292 gtk_widget_show(main_vbox);
3295 menubar = main_menu_new(&accel);
3296 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3297 gtk_widget_show(menubar);
3300 main_tb = toolbar_new();
3301 gtk_widget_show (main_tb);
3304 pkt_scrollw = packet_list_new(prefs);
3305 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3306 gtk_widget_show(pkt_scrollw);
3309 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3310 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3311 gtk_widget_show(tv_scrollw);
3313 #if GTK_MAJOR_VERSION < 2
3314 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3315 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3318 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3319 "changed", tree_view_selection_changed_cb, NULL);
3321 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3322 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3323 gtk_widget_show(tree_view);
3326 byte_nb_ptr = byte_view_new();
3327 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3328 gtk_widget_show(byte_nb_ptr);
3330 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3331 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3334 /* Panes for the packet list, tree, and byte view */
3335 main_pane_v1 = gtk_vpaned_new();
3336 gtk_widget_show(main_pane_v1);
3337 main_pane_v2 = gtk_vpaned_new();
3338 gtk_widget_show(main_pane_v2);
3339 main_pane_h1 = gtk_hpaned_new();
3340 gtk_widget_show(main_pane_h1);
3341 main_pane_h2 = gtk_hpaned_new();
3342 gtk_widget_show(main_pane_h2);
3344 /* filter toolbar */
3345 #if GTK_MAJOR_VERSION < 2
3346 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3349 filter_tb = gtk_toolbar_new();
3350 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3351 GTK_ORIENTATION_HORIZONTAL);
3352 #endif /* GTK_MAJOR_VERSION */
3353 gtk_widget_show(filter_tb);
3355 /* Create the "Filter:" button */
3356 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3357 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3358 gtk_widget_show(filter_bt);
3359 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3361 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3362 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3364 /* Create the filter combobox */
3365 filter_cm = gtk_combo_new();
3366 dfilter_list = NULL;
3367 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3368 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3369 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3370 filter_te = GTK_COMBO(filter_cm)->entry;
3371 main_display_filter_widget=filter_te;
3372 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3373 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3374 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3375 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3376 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3377 WIDGET_SET_SIZE(filter_cm, 400, -1);
3378 gtk_widget_show(filter_cm);
3379 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3381 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3382 gtk_tooltips_set_tip(tooltips, filter_te,
3383 "Enter a display filter, or choose one of your recently used filters. "
3384 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3387 /* Create the "Add Expression..." button, to pop up a dialog
3388 for constructing filter comparison expressions. */
3389 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3390 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3391 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3392 gtk_widget_show(filter_add_expr_bt);
3393 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3394 "Add an expression to this filter string", "Private");
3396 /* Create the "Clear" button */
3397 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3398 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3399 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3400 gtk_widget_show(filter_reset);
3401 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3402 "Clear this filter string and update the display", "Private");
3404 /* Create the "Apply" button */
3405 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3406 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3407 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3408 gtk_widget_show(filter_apply);
3409 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3410 "Apply this filter string to the display", "Private");
3412 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3413 * of any widget that ends up calling a callback which needs
3414 * that text entry pointer */
3415 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3416 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3418 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3420 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3422 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3424 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3426 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3428 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3430 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3432 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3434 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3436 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3438 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3440 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3442 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3444 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3445 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3446 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3448 /* info (main) statusbar */
3449 info_bar = info_bar_new();
3450 gtk_widget_show(info_bar);
3452 /* packets statusbar */
3453 packets_bar = packets_bar_new();
3454 gtk_widget_show(packets_bar);
3456 /* Filter/status hbox */
3457 stat_hbox = gtk_hbox_new(FALSE, 1);
3458 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3459 gtk_widget_show(stat_hbox);
3461 /* Pane for the statusbar */
3462 status_pane = gtk_hpaned_new();
3463 gtk_widget_show(status_pane);
3465 /* Pane for the welcome screen */
3466 welcome_pane = welcome_new();
3467 gtk_widget_show(welcome_pane);
3471 show_main_window(gboolean doing_work)
3473 main_set_for_capture_file(doing_work);
3475 /*** we have finished all init things, show the main window ***/
3476 gtk_widget_show(top_level);
3478 /* the window can be maximized only, if it's visible, so do it after show! */
3479 main_load_window_geometry(top_level);
3481 /* process all pending GUI events before continue */
3482 while (gtk_events_pending()) gtk_main_iteration();
3484 /* Pop up any queued-up alert boxes. */
3485 display_queued_messages();