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.
42 #ifdef NEED_STRERROR_H
50 #ifdef _WIN32 /* Needed for console I/O */
55 #include <epan/epan.h>
56 #include <epan/filesystem.h>
57 #include <epan/epan_dissect.h>
58 #include <epan/timestamp.h>
59 #include <epan/packet.h>
60 #include <epan/plugins.h>
61 #include <epan/dfilter/dfilter.h>
62 #include <epan/strutil.h>
63 #include <epan/addr_resolv.h>
64 #include <epan/emem.h>
66 /* general (not GTK specific) */
70 #include "disabled_protos.h"
71 #include <epan/prefs.h>
72 #include "filter_dlg.h"
73 #include "layout_prefs.h"
75 #include "color_filters.h"
77 #include "simple_dialog.h"
79 #include <epan/prefs-int.h>
80 #include "ringbuffer.h"
81 #include "../ui_util.h"
83 #include <epan/stat_cmd_args.h>
85 #include "clopts_common.h"
86 #include "cmdarg_err.h"
87 #include "version_info.h"
92 #include "capture-pcap-util.h"
94 #include "capture_loop.h"
95 #include "capture_sync.h"
99 #include "capture-wpcap.h"
100 #include "capture_wpcap_packet.h"
103 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
104 #include "ethclist.h"
108 #include "statusbar.h"
109 #include "alert_box.h"
110 #include "dlg_utils.h"
111 #include "gtkglobals.h"
113 #include "gui_utils.h"
114 #include "compat_macros.h"
118 #include "../main_window.h"
120 #include "file_dlg.h"
121 #include <epan/column.h>
122 #include "proto_draw.h"
124 #include "packet_win.h"
126 #include "find_dlg.h"
127 #include "packet_list.h"
129 #include "follow_dlg.h"
130 #include "font_utils.h"
131 #include "about_dlg.h"
132 #include "help_dlg.h"
133 #include "decode_as_dlg.h"
134 #include "webbrowser.h"
135 #include "capture_dlg.h"
136 #include "capture_ui_utils.h"
138 #include "../epan/emem.h"
139 #include "file_util.h"
140 #include "../image/eicon3d16.xpm"
141 #include "../image/eicon3d32.xpm"
142 #include "../image/eicon3d48.xpm"
143 #include "../image/eicon3d64.xpm"
144 #include "../image/eiconcap16.xpm"
145 #include "../image/eiconcap32.xpm"
146 #include "../image/eiconcap48.xpm"
150 * Files under personal and global preferences directories in which
151 * GTK settings for Ethereal are stored.
153 #define RC_FILE "gtkrc"
156 #define DEF_READY_MESSAGE " Ready to load or capture"
158 #define DEF_READY_MESSAGE " Ready to load file"
162 GtkWidget *main_display_filter_widget=NULL;
163 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
164 static GtkWidget *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
165 static GtkWidget *main_first_pane, *main_second_pane;
166 static GtkWidget *status_pane;
167 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
168 static GtkWidget *info_bar;
169 static GtkWidget *packets_bar = NULL;
170 static GtkWidget *welcome_pane;
171 static guint main_ctx, file_ctx, help_ctx;
172 static guint packets_ctx;
173 static gchar *packets_str = NULL;
174 GString *comp_info_str, *runtime_info_str;
175 gchar *ethereal_path = NULL;
176 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
178 gboolean capture_child; /* True if this is the child for "-S" */
180 static gboolean has_console; /* TRUE if app has console */
181 static void destroy_console(void);
183 static void console_log_handler(const char *log_domain,
184 GLogLevelFlags log_level, const char *message, gpointer user_data);
187 static gboolean list_link_layer_types;
188 capture_options global_capture_opts;
189 capture_options *capture_opts = &global_capture_opts;
193 static void create_main_window(gint, gint, gint, e_prefs*);
194 static void show_main_window(gboolean);
195 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
196 static void main_save_window_geometry(GtkWidget *widget);
198 #define E_DFILTER_CM_KEY "display_filter_combo"
199 #define E_DFILTER_FL_KEY "display_filter_list"
203 /* Match selected byte pattern */
205 match_selected_cb_do(gpointer data, int action, gchar *text)
207 GtkWidget *filter_te;
208 char *cur_filter, *new_filter;
213 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
216 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
218 switch (action&MATCH_SELECTED_MASK) {
220 case MATCH_SELECTED_REPLACE:
221 new_filter = g_strdup(text);
224 case MATCH_SELECTED_AND:
225 if ((!cur_filter) || (0 == strlen(cur_filter)))
226 new_filter = g_strdup(text);
228 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
231 case MATCH_SELECTED_OR:
232 if ((!cur_filter) || (0 == strlen(cur_filter)))
233 new_filter = g_strdup(text);
235 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
238 case MATCH_SELECTED_NOT:
239 new_filter = g_strconcat("!(", text, ")", NULL);
242 case MATCH_SELECTED_AND_NOT:
243 if ((!cur_filter) || (0 == strlen(cur_filter)))
244 new_filter = g_strconcat("!(", text, ")", NULL);
246 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
249 case MATCH_SELECTED_OR_NOT:
250 if ((!cur_filter) || (0 == strlen(cur_filter)))
251 new_filter = g_strconcat("!(", text, ")", NULL);
253 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
257 g_assert_not_reached();
262 /* Free up the copy we got of the old filter text. */
265 /* create a new one and set the display filter entry accordingly */
266 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
268 /* Run the display filter so it goes in effect. */
269 if (action&MATCH_SELECTED_APPLY_NOW)
270 main_filter_packets(&cfile, new_filter, FALSE);
272 /* Free up the new filter text. */
277 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
279 if (cfile.finfo_selected)
280 match_selected_cb_do((data ? data : w),
282 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
286 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
288 gchar *selected_proto_url;
289 gchar *proto_abbrev = data;
294 if (cfile.finfo_selected) {
295 /* open wiki page using the protocol abbreviation */
296 selected_proto_url = g_strdup_printf("http://wiki.ethereal.com/Protocols/%s", proto_abbrev);
297 browser_open_url(selected_proto_url);
298 g_free(selected_proto_url);
301 case(ESD_BTN_CANCEL):
304 g_assert_not_reached();
310 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
313 const gchar *proto_abbrev;
317 if (cfile.finfo_selected) {
318 /* convert selected field to protocol abbreviation */
319 /* XXX - could this conversion be simplified? */
320 field_id = cfile.finfo_selected->hfinfo->id;
321 /* if the selected field isn't a protocol, get it's parent */
322 if(!proto_registrar_is_protocol(field_id)) {
323 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
326 proto_abbrev = proto_registrar_get_abbrev(field_id);
328 /* ask the user if the wiki page really should be opened */
329 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
330 PRIMARY_TEXT_START "Open Ethereal Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
332 "This will open the \"%s\" related Ethereal Wiki page in your Web browser.\n"
334 "The Ethereal Wiki is a collaborative approach to provide information\n"
335 "about Ethereal in several ways (not limited to protocol specifics).\n"
337 "This Wiki is new, so the page of the selected protocol\n"
338 "may not exist and/or may not contain valuable information.\n"
340 "As everyone can edit the Wiki and add new content (or extend existing),\n"
341 "you are encouraged to add information if you can.\n"
343 "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
345 "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
346 "which will save you a lot of editing and will give a consistent look over the pages.",
347 proto_abbrev, proto_abbrev);
348 simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, (gpointer) proto_abbrev);
354 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
357 const gchar *proto_abbrev;
358 gchar *selected_proto_url;
361 if (cfile.finfo_selected) {
362 /* convert selected field to protocol abbreviation */
363 /* XXX - could this conversion be simplified? */
364 field_id = cfile.finfo_selected->hfinfo->id;
365 /* if the selected field isn't a protocol, get it's parent */
366 if(!proto_registrar_is_protocol(field_id)) {
367 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
370 proto_abbrev = proto_registrar_get_abbrev(field_id);
372 /* open reference page using the protocol abbreviation */
373 selected_proto_url = g_strdup_printf("http://www.ethereal.com/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
374 browser_open_url(selected_proto_url);
375 g_free(selected_proto_url);
381 get_text_from_packet_list(gpointer data)
383 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
384 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
385 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
393 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
394 cfile.pd, fdata->cap_len, &err, &err_info)) {
395 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
396 cf_read_error_message(err, err_info), cfile.filename);
400 edt = epan_dissect_new(FALSE, FALSE);
401 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
403 epan_dissect_fill_in_columns(edt);
405 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
406 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
407 len = strlen(cfile.cinfo.col_expr[column]) +
408 strlen(cfile.cinfo.col_expr_val[column]) + 5;
409 buf = ep_alloc0(len);
410 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
411 cfile.cinfo.col_expr_val[column]);
414 epan_dissect_free(edt);
421 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
423 match_selected_cb_do(data,
425 get_text_from_packet_list(data));
430 /* XXX: use a preference for this setting! */
431 static guint dfilter_combo_max_recent = 10;
433 /* add a display filter to the combo box */
434 /* Note: a new filter string will replace an old identical one */
436 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
438 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
441 /* GtkCombos don't let us get at their list contents easily, so we maintain
442 our own filter list, and feed it to gtk_combo_set_popdown_strings when
443 a new filter is added. */
444 li = g_list_first(dfilter_list);
446 /* If the filter is already in the list, remove the old one and
447 * append the new one at the latest position (at g_list_append() below) */
448 if (li->data && strcmp(s, li->data) == 0) {
449 dfilter_list = g_list_remove(dfilter_list, li->data);
455 dfilter_list = g_list_append(dfilter_list, s);
456 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
457 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), dfilter_list);
458 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(dfilter_list)->data);
464 /* write all non empty display filters (until maximum count)
465 * of the combo box GList to the user's recent file */
467 dfilter_recent_combo_write_all(FILE *rf) {
468 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
469 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
474 /* write all non empty display filter strings to the recent file (until max count) */
475 li = g_list_first(dfilter_list);
476 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
477 if (strlen(li->data)) {
478 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
484 /* empty the combobox entry field */
486 dfilter_combo_add_empty(void) {
487 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
489 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
493 /* add a display filter coming from the user's recent file to the dfilter combo box */
495 dfilter_combo_add_recent(gchar *s) {
496 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
500 if (!dfilter_combo_add(filter_cm, dup)) {
509 /* call cf_filter_packets() and add this filter string to the recent filter list */
511 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
513 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
514 GList *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
516 gboolean add_filter = TRUE;
517 gboolean free_filter = TRUE;
519 cf_status_t cf_status;
521 /* we'll crash later on if dftext is NULL */
522 g_assert(dftext != NULL);
524 s = g_strdup(dftext);
526 /* GtkCombos don't let us get at their list contents easily, so we maintain
527 our own filter list, and feed it to gtk_combo_set_popdown_strings when
528 a new filter is added. */
529 cf_status = cf_filter_packets(cf, s, force);
530 if (cf_status == CF_OK) {
531 li = g_list_first(dfilter_list);
533 if (li->data && strcmp(s, li->data) == 0)
539 /* trim list size first */
540 while (g_list_length(dfilter_list) >= dfilter_combo_max_recent) {
541 dfilter_list = g_list_remove(dfilter_list, g_list_first(dfilter_list)->data);
545 dfilter_list = g_list_append(dfilter_list, s);
546 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
547 gtk_combo_set_popdown_strings(filter_cm, dfilter_list);
548 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(dfilter_list)->data);
554 return (cf_status == CF_OK);
558 /* Run the current display filter on the current packet set, and
561 filter_activate_cb(GtkWidget *w _U_, gpointer data)
565 s = gtk_entry_get_text(GTK_ENTRY(data));
567 main_filter_packets(&cfile, s, FALSE);
570 /* redisplay with no display filter */
572 filter_reset_cb(GtkWidget *w, gpointer data _U_)
574 GtkWidget *filter_te = NULL;
576 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
577 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
579 main_filter_packets(&cfile, "", FALSE);
582 /* mark as reference time frame */
584 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
588 frame->flags.ref_time=1;
590 frame->flags.ref_time=0;
592 cf_reftime_packets(&cfile);
596 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
601 if (cfile.current_frame) {
602 /* XXX hum, should better have a "cfile->current_row" here ... */
603 set_frame_reftime(!cfile.current_frame->flags.ref_time,
605 packet_list_find_row_from_data(cfile.current_frame));
608 case REFTIME_FIND_NEXT:
609 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
611 case REFTIME_FIND_PREV:
612 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
617 #if GTK_MAJOR_VERSION < 2
619 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
620 gpointer user_data _U_)
623 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
627 gchar *help_str = NULL;
628 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
630 gboolean has_blurb = FALSE;
631 guint length = 0, byte_len;
632 GtkWidget *byte_view;
633 const guint8 *byte_data;
634 #if GTK_MAJOR_VERSION >= 2
639 #if GTK_MAJOR_VERSION >= 2
640 /* if nothing is selected */
641 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
644 * Which byte view is displaying the current protocol tree
647 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
648 if (byte_view == NULL)
651 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
652 if (byte_data == NULL)
655 cf_unselect_field(&cfile);
656 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
657 cfile.current_frame, NULL, byte_len);
660 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
663 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
667 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
669 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
670 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
671 g_assert(byte_data != NULL);
673 cfile.finfo_selected = finfo;
674 set_menus_for_selected_tree_row(&cfile);
677 if (finfo->hfinfo->blurb != NULL &&
678 finfo->hfinfo->blurb[0] != '\0') {
680 length = strlen(finfo->hfinfo->blurb);
682 length = strlen(finfo->hfinfo->name);
684 if (finfo->length == 0) {
686 } else if (finfo->length == 1) {
687 strcpy (len_str, ", 1 byte");
689 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
691 statusbar_pop_field_msg(); /* get rid of current help msg */
693 help_str = g_strdup_printf("%s (%s)%s",
694 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
695 finfo->hfinfo->abbrev, len_str);
696 statusbar_push_field_msg(help_str);
700 * Don't show anything if the field name is zero-length;
701 * the pseudo-field for "proto_tree_add_text()" is such
702 * a field, and we don't want "Text (text)" showing up
703 * on the status line if you've selected such a field.
705 * XXX - there are zero-length fields for which we *do*
706 * want to show the field name.
708 * XXX - perhaps the name and abbrev field should be null
709 * pointers rather than null strings for that pseudo-field,
710 * but we'd have to add checks for null pointers in some
711 * places if we did that.
713 * Or perhaps protocol tree items added with
714 * "proto_tree_add_text()" should have -1 as the field index,
715 * with no pseudo-field being used, but that might also
716 * require special checks for -1 to be added.
718 statusbar_push_field_msg("");
722 #if GTK_MAJOR_VERSION < 2
723 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
726 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
731 #if GTK_MAJOR_VERSION < 2
733 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
734 gpointer user_data _U_)
736 GtkWidget *byte_view;
741 * Which byte view is displaying the current protocol tree
744 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
745 if (byte_view == NULL)
748 data = get_byte_view_data_and_length(byte_view, &len);
752 cf_unselect_field(&cfile);
753 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
758 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
760 collapse_all_tree(cfile.edt->tree, tree_view);
763 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
765 expand_all_tree(cfile.edt->tree, tree_view);
768 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
769 #if GTK_MAJOR_VERSION < 2
775 #if GTK_MAJOR_VERSION < 2
776 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
778 /* the mouse position is at an entry, expand that one */
779 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
782 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
784 /* the mouse position is at an entry, expand that one */
785 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
786 gtk_tree_path_free(path);
791 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
792 if (cfile.edt->tree) {
793 guint32 tmp = g_resolv_flags;
794 g_resolv_flags = RESOLV_ALL;
795 proto_tree_draw(cfile.edt->tree, tree_view);
796 g_resolv_flags = tmp;
801 * Push a message referring to file access onto the statusbar.
804 statusbar_push_file_msg(gchar *msg)
806 /*g_warning("statusbar_push: %s", msg);*/
807 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
811 * Pop a message referring to file access off the statusbar.
814 statusbar_pop_file_msg(void)
816 /*g_warning("statusbar_pop");*/
817 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
821 * XXX - do we need multiple statusbar contexts?
825 * Push a message referring to the currently-selected field onto the statusbar.
828 statusbar_push_field_msg(gchar *msg)
830 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
834 * Pop a message referring to the currently-selected field off the statusbar.
837 statusbar_pop_field_msg(void)
839 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
843 * update the packets statusbar to the current values
845 void packets_bar_update(void)
849 /* remove old status */
852 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
855 /* do we have any packets? */
857 if(cfile.drops_known) {
858 packets_str = g_strdup_printf(" P: %u D: %u M: %u Drops: %u",
859 cfile.count, cfile.displayed_count, cfile.marked_count, cfile.drops);
861 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
862 cfile.count, cfile.displayed_count, cfile.marked_count);
865 packets_str = g_strdup(" No Packets");
867 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
872 main_set_for_capture_file(gboolean have_capture_file_in)
874 have_capture_file = have_capture_file_in;
876 main_widgets_show_or_hide();
882 /* get the current geometry, before writing it to disk */
883 main_save_window_geometry(top_level);
885 /* write user's recent file to disk
886 * It is no problem to write this file, even if we do not quit */
889 /* XXX - should we check whether the capture file is an
890 unsaved temporary file for a live capture and, if so,
891 pop up a "do you want to exit without saving the capture
892 file?" dialog, and then just return, leaving said dialog
893 box to forcibly quit if the user clicks "OK"?
895 If so, note that this should be done in a subroutine that
896 returns TRUE if we do so, and FALSE otherwise, and if it
897 returns TRUE we should return TRUE without nuking anything.
899 Note that, if we do that, we might also want to check if
900 an "Update list of packets in real time" capture is in
901 progress and, if so, ask whether they want to terminate
902 the capture and discard it, and return TRUE, before nuking
903 any child capture, if they say they don't want to do so. */
906 /* Nuke any child capture in progress. */
907 capture_kill_child(capture_opts);
910 /* Are we in the middle of reading a capture? */
911 if (cfile.state == FILE_READ_IN_PROGRESS) {
912 /* Yes, so we can't just close the file and quit, as
913 that may yank the rug out from under the read in
914 progress; instead, just set the state to
915 "FILE_READ_ABORTED" and return - the code doing the read
916 will check for that and, if it sees that, will clean
918 cfile.state = FILE_READ_ABORTED;
920 /* Say that the window should *not* be deleted;
921 that'll be done by the code that cleans up. */
924 /* Close any capture file we have open; on some OSes, you
925 can't unlink a temporary capture file if you have it
927 "cf_close()" will unlink it after closing it if
928 it's a temporary file.
930 We do this here, rather than after the main loop returns,
931 as, after the main loop returns, the main window may have
932 been destroyed (if this is called due to a "destroy"
933 even on the main window rather than due to the user
934 selecting a menu item), and there may be a crash
935 or other problem when "cf_close()" tries to
936 clean up stuff in the main window.
938 XXX - is there a better place to put this?
939 Or should we have a routine that *just* closes the
940 capture file, and doesn't do anything with the UI,
941 which we'd call here, and another routine that
942 calls that routine and also cleans up the UI, which
943 we'd call elsewhere? */
946 /* Exit by leaving the main loop, so that any quit functions
947 we registered get called. */
950 /* Say that the window should be deleted. */
956 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
960 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
961 #if GTK_MAJOR_VERSION >= 2
962 gtk_window_present(GTK_WINDOW(top_level));
964 /* user didn't saved his current file, ask him */
965 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
966 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
967 "If you quit the program without saving, your capture data will be discarded.");
968 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
971 /* unchanged file, just exit */
972 /* "main_do_quit()" indicates whether the main window should be deleted. */
973 return main_do_quit();
980 main_load_window_geometry(GtkWidget *widget)
982 window_geometry_t geom;
984 geom.set_pos = prefs.gui_geometry_save_position;
985 geom.x = recent.gui_geometry_main_x;
986 geom.y = recent.gui_geometry_main_y;
987 geom.set_size = prefs.gui_geometry_save_size;
988 if (recent.gui_geometry_main_width > 0 &&
989 recent.gui_geometry_main_height > 0) {
990 geom.width = recent.gui_geometry_main_width;
991 geom.height = recent.gui_geometry_main_height;
992 geom.set_maximized = prefs.gui_geometry_save_maximized;
994 /* We assume this means the width and height weren't set in
995 the "recent" file (or that there is no "recent" file),
996 and weren't set to a default value, so we don't set the
997 size. (The "recent" file code rejects non-positive width
998 and height values.) */
999 geom.set_size = FALSE;
1001 geom.maximized = recent.gui_geometry_main_maximized;
1003 window_set_geometry(widget, &geom);
1005 if (recent.has_gui_geometry_main_upper_pane && recent.gui_geometry_main_upper_pane)
1006 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
1007 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_main_lower_pane)
1008 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
1009 if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_status_pane)
1010 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
1015 main_save_window_geometry(GtkWidget *widget)
1017 window_geometry_t geom;
1019 window_get_geometry(widget, &geom);
1021 if (prefs.gui_geometry_save_position) {
1022 recent.gui_geometry_main_x = geom.x;
1023 recent.gui_geometry_main_y = geom.y;
1026 if (prefs.gui_geometry_save_size) {
1027 recent.gui_geometry_main_width = geom.width,
1028 recent.gui_geometry_main_height = geom.height;
1031 #if GTK_MAJOR_VERSION >= 2
1032 if(prefs.gui_geometry_save_maximized) {
1033 recent.gui_geometry_main_maximized = geom.maximized;
1036 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
1037 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
1038 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
1042 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1046 /* save file first */
1047 file_save_as_cmd(after_save_exit, NULL);
1049 case(ESD_BTN_DONT_SAVE):
1052 case(ESD_BTN_CANCEL):
1055 g_assert_not_reached();
1060 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1064 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1065 /* user didn't saved his current file, ask him */
1066 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1067 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1068 "If you quit the program without saving, your capture data will be discarded.");
1069 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1071 /* unchanged file, just exit */
1077 print_usage(gboolean print_ver) {
1087 fprintf(output, "Ethereal " VERSION "%s\n"
1088 "Interactively dump and analyze network traffic.\n"
1089 "See http://www.ethereal.com for more information.\n"
1092 svnversion, get_copyright_info());
1096 fprintf(output, "\n");
1097 fprintf(output, "Usage: ethereal [options] ... [ <infile> ]\n");
1098 fprintf(output, "\n");
1101 fprintf(output, "Capture interface:\n");
1102 fprintf(output, " -i <interface> name or idx of interface (def: first none loopback)\n");
1103 fprintf(output, " -f <capture filter> packet filter in libpcap filter syntax\n");
1104 fprintf(output, " -s <snaplen> packet snapshot length (def: 65535)\n");
1105 fprintf(output, " -p don't capture in promiscuous mode\n");
1106 fprintf(output, " -k start capturing immediately (def: do nothing)\n");
1107 fprintf(output, " -Q quit Ethereal after capturing\n");
1108 fprintf(output, " -S update packet display when new packets are captured\n");
1109 fprintf(output, " -l turn on automatic scrolling while -S is in use\n");
1111 fprintf(output, " -B <buffer size> size of kernel buffer (def: 1MB)\n");
1113 fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
1114 fprintf(output, " -D print list of interfaces and exit\n");
1115 fprintf(output, " -L print list of link-layer types of iface and exit\n");
1116 fprintf(output, "\n");
1117 fprintf(output, "Capture stop conditions:\n");
1118 fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n");
1119 fprintf(output, " -a <autostop cond.> ... duration:NUM - stop after NUM seconds\n");
1120 fprintf(output, " filesize:NUM - stop this file after NUM KB\n");
1121 fprintf(output, " files:NUM - stop after NUM files\n");
1122 /*fprintf(output, "\n");*/
1123 fprintf(output, "Capture output:\n");
1124 fprintf(output, " -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
1125 fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
1126 fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
1127 #endif /* HAVE_LIBPCAP */
1129 /*fprintf(output, "\n");*/
1130 fprintf(output, "Input file:\n");
1131 fprintf(output, " -r <infile> set the filename to read from (no pipes or stdin!)\n");
1133 fprintf(output, "\n");
1134 fprintf(output, "Processing:\n");
1135 fprintf(output, " -R <read filter> packet filter in Ethereal display filter syntax\n");
1136 fprintf(output, " -n disable all name resolutions (def: all enabled)\n");
1137 fprintf(output, " -N <name resolve flags> enable specific name resolution(s): \"mntC\"\n");
1139 fprintf(output, "\n");
1140 fprintf(output, "User interface:\n");
1141 fprintf(output, " -g <packet number> go to specified packet number after \"-r\"\n");
1142 fprintf(output, " -m <font> set the font name used for most text\n");
1143 fprintf(output, " -t ad|a|r|d output format of time stamps (def: r: rel. to first)\n");
1144 fprintf(output, " -z <statistics> show various statistics, see man page for details\n");
1146 fprintf(output, "\n");
1147 fprintf(output, "Output:\n");
1148 fprintf(stderr, " -w <outfile|-> set the output filename (or '-' for stdout)\n");
1150 fprintf(output, "\n");
1151 fprintf(stderr, "Miscellaneous:\n");
1152 fprintf(stderr, " -h display this help and exit\n");
1153 fprintf(stderr, " -v display version info and exit\n");
1154 fprintf(output, " -o <name>:<value> ... override preference or recent setting\n");
1168 printf(PACKAGE " " VERSION "%s\n"
1175 svnversion, get_copyright_info(), comp_info_str->str,
1176 runtime_info_str->str);
1184 * Report an error in command-line arguments.
1185 * Creates a console on Windows.
1186 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
1187 * terminal isn't the standard error?
1190 cmdarg_err(const char *fmt, ...)
1198 fprintf(stderr, "ethereal: ");
1199 vfprintf(stderr, fmt, ap);
1200 fprintf(stderr, "\n");
1205 * Report additional information for an error in command-line arguments.
1206 * Creates a console on Windows.
1207 * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
1208 * terminal isn't the standard error?
1211 cmdarg_err_cont(const char *fmt, ...)
1219 vfprintf(stderr, fmt, ap);
1220 fprintf(stderr, "\n");
1224 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1226 Once every 3 seconds we get a callback here which we use to update
1227 the tap extensions. Since Gtk1 is single threaded we dont have to
1228 worry about any locking or critical regions.
1231 update_cb(gpointer data _U_)
1233 draw_tap_listeners(FALSE);
1238 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1239 use threads all updte_thread_mutex can be dropped and protect/unprotect
1240 would just be empty functions.
1242 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1243 gtk1-ethereal and it will just work.
1245 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1247 update_thread(gpointer data _U_)
1251 g_get_current_time(&tv1);
1252 g_static_mutex_lock(&update_thread_mutex);
1253 gdk_threads_enter();
1254 draw_tap_listeners(FALSE);
1255 gdk_threads_leave();
1256 g_static_mutex_unlock(&update_thread_mutex);
1258 g_get_current_time(&tv2);
1259 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1260 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1261 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1262 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1269 protect_thread_critical_region(void)
1271 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1272 g_static_mutex_lock(&update_thread_mutex);
1276 unprotect_thread_critical_region(void)
1278 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1279 g_static_mutex_unlock(&update_thread_mutex);
1283 /* Set the file name in the status line, in the name for the main window,
1284 and in the name for the main window's icon. */
1286 set_display_filename(capture_file *cf)
1288 const gchar *name_ptr;
1293 name_ptr = cf_get_display_name(cf);
1295 if (!cf->is_tempfile && cf->filename) {
1296 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1297 add_menu_recent_capture_file(cf->filename);
1300 /* convert file size */
1301 if (cf->f_datalen/1024/1024 > 10) {
1302 size_str = g_strdup_printf("%ld MB", cf->f_datalen/1024/1024);
1303 } else if (cf->f_datalen/1024 > 10) {
1304 size_str = g_strdup_printf("%ld KB", cf->f_datalen/1024);
1306 size_str = g_strdup_printf("%ld Bytes", cf->f_datalen);
1310 status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu",
1311 (cf->filename) ? cf->filename : "", size_str,
1312 (long)cf->elapsed_time.secs/3600,
1313 (long)cf->elapsed_time.secs%3600/60,
1314 (long)cf->elapsed_time.secs%60);
1316 statusbar_push_file_msg(status_msg);
1320 win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1321 set_main_window_name(win_name);
1325 GtkWidget *close_dlg = NULL;
1328 main_cf_cb_file_closing(capture_file *cf)
1331 /* if we have more than 10000 packets, show a splash screen while closing */
1332 /* XXX - don't know a better way to decide wether to show or not,
1333 * as most of the time is spend in a single eth_clist_clear function,
1334 * so we can't use a progress bar here! */
1335 if(cf->count > 10000) {
1336 close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sClosing file!%s\n\nPlease wait ...",
1337 simple_dialog_primary_start(), simple_dialog_primary_end());
1338 #if GTK_MAJOR_VERSION >= 2
1339 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1341 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
1345 /* Destroy all windows, which refer to the
1346 capture file we're closing. */
1347 destroy_packet_wins();
1348 file_save_as_destroy();
1350 /* Clear any file-related status bar messages.
1351 XXX - should be "clear *ALL* file-related status bar messages;
1352 will there ever be more than one on the stack? */
1353 statusbar_pop_file_msg();
1355 /* Restore the standard title bar message. */
1356 set_main_window_name("The Ethereal Network Analyzer");
1358 /* Disable all menu items that make sense only if you have a capture. */
1359 set_menus_for_capture_file(FALSE);
1360 set_menus_for_unsaved_capture_file(FALSE);
1361 set_menus_for_captured_packets(FALSE);
1362 set_menus_for_selected_packet(cf);
1363 set_menus_for_capture_in_progress(FALSE);
1364 set_menus_for_selected_tree_row(cf);
1366 /* Set up main window for no capture file. */
1367 main_set_for_capture_file(FALSE);
1369 main_window_update();
1373 main_cf_cb_file_closed(capture_file *cf _U_)
1375 if(close_dlg != NULL) {
1376 splash_destroy(close_dlg);
1380 /* go back to "No packets" */
1381 packets_bar_update();
1385 main_cf_cb_file_read_start(capture_file *cf)
1387 const gchar *name_ptr;
1390 name_ptr = get_basename(cf->filename);
1392 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1393 statusbar_push_file_msg(load_msg);
1398 main_cf_cb_file_read_finished(capture_file *cf)
1400 statusbar_pop_file_msg();
1401 set_display_filename(cf);
1403 /* Enable menu items that make sense if you have a capture file you've
1404 finished reading. */
1405 set_menus_for_capture_file(TRUE);
1406 set_menus_for_unsaved_capture_file(!cf->user_saved);
1408 /* Enable menu items that make sense if you have some captured packets. */
1409 set_menus_for_captured_packets(TRUE);
1411 /* Set up main window for a capture file. */
1412 main_set_for_capture_file(TRUE);
1415 #if GTK_MAJOR_VERSION >= 2
1416 GList *icon_list_create(
1417 const char **icon16_xpm,
1418 const char **icon32_xpm,
1419 const char **icon48_xpm,
1420 const char **icon64_xpm)
1422 GList *icon_list = NULL;
1423 GdkPixbuf * pixbuf16;
1424 GdkPixbuf * pixbuf32;
1425 GdkPixbuf * pixbuf48;
1426 GdkPixbuf * pixbuf64;
1429 if(icon16_xpm != NULL) {
1430 pixbuf16 = gdk_pixbuf_new_from_xpm_data(icon16_xpm);
1432 icon_list = g_list_append(icon_list, pixbuf16);
1435 if(icon32_xpm != NULL) {
1436 pixbuf32 = gdk_pixbuf_new_from_xpm_data(icon32_xpm);
1438 icon_list = g_list_append(icon_list, pixbuf32);
1441 if(icon48_xpm != NULL) {
1442 pixbuf48 = gdk_pixbuf_new_from_xpm_data(icon48_xpm);
1444 icon_list = g_list_append(icon_list, pixbuf48);
1447 if(icon64_xpm != NULL) {
1448 pixbuf64 = gdk_pixbuf_new_from_xpm_data(icon64_xpm);
1450 icon_list = g_list_append(icon_list, pixbuf64);
1459 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1462 #if GTK_MAJOR_VERSION >= 2
1463 static GList *icon_list = NULL;
1467 if(capture_opts->iface) {
1468 title = g_strdup_printf("%s: Capturing - Ethereal",
1469 get_interface_descriptive_name(capture_opts->iface));
1471 title = g_strdup_printf("Capturing - Ethereal");
1473 set_main_window_name(title);
1476 #if GTK_MAJOR_VERSION >= 2
1477 if(icon_list == NULL) {
1478 icon_list = icon_list_create(eiconcap16_xpm, eiconcap32_xpm, eiconcap48_xpm, NULL);
1480 gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1483 /* Disable menu items that make no sense if you're currently running
1485 set_menus_for_capture_in_progress(TRUE);
1487 /* update statusbar */
1488 statusbar_push_file_msg("Waiting for capture input data ...");
1490 /* Don't set up main window for a capture file. */
1491 main_set_for_capture_file(FALSE);
1495 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1501 /* We've done this in "prepared" above, but it will be cleared while
1502 switching to the next multiple file. */
1503 if(capture_opts->iface) {
1504 title = g_strdup_printf("%s: Capturing - Ethereal",
1505 get_interface_descriptive_name(capture_opts->iface));
1507 title = g_strdup_printf("Capturing - Ethereal");
1509 set_main_window_name(title);
1512 set_menus_for_capture_in_progress(TRUE);
1514 /* Enable menu items that make sense if you have some captured
1515 packets (yes, I know, we don't have any *yet*). */
1516 set_menus_for_captured_packets(TRUE);
1518 statusbar_pop_file_msg();
1520 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1521 get_interface_descriptive_name(capture_opts->iface),
1522 (capture_opts->save_file) ? capture_opts->save_file : "");
1524 statusbar_push_file_msg(capture_msg);
1526 g_free(capture_msg);
1528 /* Set up main window for a capture file. */
1529 main_set_for_capture_file(TRUE);
1533 main_cf_cb_live_capture_update_continue(capture_file *cf)
1538 statusbar_pop_file_msg();
1540 if (cf->f_datalen/1024/1024 > 10) {
1541 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB",
1542 get_interface_descriptive_name(capture_opts->iface),
1543 capture_opts->save_file,
1544 cf->f_datalen/1024/1024);
1545 } else if (cf->f_datalen/1024 > 10) {
1546 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB",
1547 get_interface_descriptive_name(capture_opts->iface),
1548 capture_opts->save_file,
1549 cf->f_datalen/1024);
1551 capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes",
1552 get_interface_descriptive_name(capture_opts->iface),
1553 capture_opts->save_file,
1557 statusbar_push_file_msg(capture_msg);
1560 GtkWidget * stop_dlg = NULL;
1563 main_cf_cb_live_capture_update_finished(capture_file *cf)
1565 if(stop_dlg != NULL) {
1566 simple_dialog_close(stop_dlg);
1570 /* Pop the "<live capture in progress>" message off the status bar. */
1571 statusbar_pop_file_msg();
1573 set_display_filename(cf);
1575 /* Enable menu items that make sense if you're not currently running
1577 set_menus_for_capture_in_progress(FALSE);
1579 /* Enable menu items that make sense if you have a capture file
1580 you've finished reading. */
1581 set_menus_for_capture_file(TRUE);
1582 set_menus_for_unsaved_capture_file(!cf->user_saved);
1584 /* Set up main window for a capture file. */
1585 main_set_for_capture_file(TRUE);
1587 if(capture_opts->quit_after_cap) {
1588 /* command line asked us to quit after the capture */
1589 /* don't pop up a dialog to ask for unsaved files etc. */
1595 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1600 /* Enable menu items that make sense if you have some captured
1601 packets (yes, I know, we don't have any *yet*). */
1602 /*set_menus_for_captured_packets(TRUE);*/
1604 statusbar_pop_file_msg();
1606 capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1607 get_interface_descriptive_name(capture_opts->iface),
1608 (capture_opts->save_file) ? capture_opts->save_file : "");
1610 statusbar_push_file_msg(capture_msg);
1611 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " P: 0");
1613 g_free(capture_msg);
1615 /* Don't set up main window for a capture file. */
1616 main_set_for_capture_file(FALSE);
1620 main_cf_cb_live_capture_fixed_continue(capture_file *cf)
1625 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1627 capture_msg = g_strdup_printf(" P: %u",
1628 cf_get_packet_count(cf));
1630 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, capture_msg);
1632 g_free(capture_msg);
1636 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1638 if(stop_dlg != NULL) {
1639 simple_dialog_close(stop_dlg);
1643 /* Pop the "<live capture in progress>" message off the status bar. */
1644 statusbar_pop_file_msg();
1646 /* Pop the "<capturing>" message off the status bar */
1647 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1649 /*set_display_filename(cf);*/
1651 /* Enable menu items that make sense if you're not currently running
1653 set_menus_for_capture_in_progress(FALSE);
1655 /* Restore the standard title bar message */
1656 /* (just in case we have trouble opening the capture file). */
1657 set_main_window_name("The Ethereal Network Analyzer");
1659 /* We don't have loaded the capture file, this will be done later.
1660 * For now we still have simply a blank screen. */
1662 if(capture_opts->quit_after_cap) {
1663 /* command line asked us to quit after the capture */
1664 /* don't pop up a dialog to ask for unsaved files etc. */
1670 main_cf_cb_live_capture_stopping(capture_file *cf _U_)
1672 #if GTK_MAJOR_VERSION >= 2
1673 static GList *icon_list = NULL;
1677 /* XXX - the time to stop the capture has been reduced (this was only a
1678 * problem on Win32 because of the capture piping), so showing a splash
1679 * isn't really necessary any longer. Unfortunately, the GTKClist packet
1680 * list seems to have problems updating after the dialog is closed, so
1681 * this was disabled here. */
1682 stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...",
1683 simple_dialog_primary_start(), simple_dialog_primary_end());
1684 #if GTK_MAJOR_VERSION >= 2
1685 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1687 gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1691 #if GTK_MAJOR_VERSION >= 2
1692 if(icon_list == NULL) {
1693 icon_list = icon_list_create(eicon3d16_xpm, eicon3d32_xpm, eicon3d48_xpm, eicon3d64_xpm);
1695 gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1702 main_cf_cb_packet_selected(gpointer data)
1704 capture_file *cf = data;
1706 /* Display the GUI protocol tree and hex dump.
1707 XXX - why do we dump core if we call "proto_tree_draw()"
1708 before calling "add_byte_views()"? */
1709 add_main_byte_views(cf->edt);
1710 main_proto_tree_draw(cf->edt->tree);
1712 /* A packet is selected. */
1713 set_menus_for_selected_packet(cf);
1717 main_cf_cb_packet_unselected(capture_file *cf)
1719 /* Clear out the display of that packet. */
1720 clear_tree_and_hex_views();
1722 /* No packet is selected. */
1723 set_menus_for_selected_packet(cf);
1727 main_cf_cb_field_unselected(capture_file *cf)
1729 statusbar_pop_field_msg();
1730 set_menus_for_selected_tree_row(cf);
1734 main_cf_cb_file_safe_started(gchar * filename)
1736 const gchar *name_ptr;
1739 name_ptr = get_basename(filename);
1741 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1743 statusbar_push_file_msg(save_msg);
1748 main_cf_cb_file_safe_finished(gpointer data _U_)
1750 /* Pop the "Saving:" message off the status bar. */
1751 statusbar_pop_file_msg();
1755 main_cf_cb_file_safe_failed(gpointer data _U_)
1757 /* Pop the "Saving:" message off the status bar. */
1758 statusbar_pop_file_msg();
1762 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1764 set_menus_for_unsaved_capture_file(FALSE);
1767 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1770 case(cf_cb_file_closing):
1771 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
1772 main_cf_cb_file_closing(data);
1774 case(cf_cb_file_closed):
1775 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
1776 main_cf_cb_file_closed(data);
1778 case(cf_cb_file_read_start):
1779 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read start");
1780 main_cf_cb_file_read_start(data);
1782 case(cf_cb_file_read_finished):
1783 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
1784 main_cf_cb_file_read_finished(data);
1787 case(cf_cb_live_capture_prepared):
1788 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
1789 main_cf_cb_live_capture_prepared(data);
1791 case(cf_cb_live_capture_update_started):
1792 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
1793 main_cf_cb_live_capture_update_started(data);
1795 case(cf_cb_live_capture_update_continue):
1796 /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
1797 main_cf_cb_live_capture_update_continue(data);
1799 case(cf_cb_live_capture_update_finished):
1800 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
1801 main_cf_cb_live_capture_update_finished(data);
1803 case(cf_cb_live_capture_fixed_started):
1804 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
1805 main_cf_cb_live_capture_fixed_started(data);
1807 case(cf_cb_live_capture_fixed_continue):
1808 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");
1809 main_cf_cb_live_capture_fixed_continue(data);
1811 case(cf_cb_live_capture_fixed_finished):
1812 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
1813 main_cf_cb_live_capture_fixed_finished(data);
1815 case(cf_cb_live_capture_stopping):
1816 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
1817 main_cf_cb_live_capture_stopping(data);
1820 case(cf_cb_packet_selected):
1821 main_cf_cb_packet_selected(data);
1823 case(cf_cb_packet_unselected):
1824 main_cf_cb_packet_unselected(data);
1826 case(cf_cb_field_unselected):
1827 main_cf_cb_field_unselected(data);
1829 case(cf_cb_file_safe_started):
1830 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe started");
1831 main_cf_cb_file_safe_started(data);
1833 case(cf_cb_file_safe_finished):
1834 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe finished");
1835 main_cf_cb_file_safe_finished(data);
1837 case(cf_cb_file_safe_reload_finished):
1838 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: reload finished");
1839 main_cf_cb_file_safe_reload_finished(data);
1841 case(cf_cb_file_safe_failed):
1842 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe failed");
1843 main_cf_cb_file_safe_failed(data);
1846 g_warning("main_cf_callback: event %u unknown", event);
1847 g_assert_not_reached();
1851 /* And now our feature presentation... [ fade to music ] */
1853 main(int argc, char *argv[])
1856 const char *command_name;
1861 extern char *optarg;
1862 gboolean arg_error = FALSE;
1870 char *gpf_path, *pf_path;
1871 char *cf_path, *df_path;
1872 char *gdp_path, *dp_path;
1873 int gpf_open_errno, gpf_read_errno;
1874 int pf_open_errno, pf_read_errno;
1875 int cf_open_errno, df_open_errno;
1876 int gdp_open_errno, gdp_read_errno;
1877 int dp_open_errno, dp_read_errno;
1880 gboolean start_capture = FALSE;
1881 gboolean stats_known;
1882 struct pcap_stat stats;
1884 gboolean capture_option_specified = FALSE;
1886 gint pl_size = 280, tv_size = 95, bv_size = 75;
1887 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1888 dfilter_t *rfcode = NULL;
1889 gboolean rfilter_parse_failed = FALSE;
1892 GtkWidget *splash_win = NULL;
1893 GLogLevelFlags log_flags;
1894 guint go_to_packet = 0;
1897 #define OPTSTRING_INIT "a:b:c:Df:g:Hhi:klLm:nN:o:pQr:R:Ss:t:vw:y:z:"
1901 #define OPTSTRING_CHILD "Z:"
1902 #define OPTSTRING_WIN32 "B:"
1904 #define OPTSTRING_CHILD ""
1905 #define OPTSTRING_WIN32 ""
1908 #define OPTSTRING_CHILD ""
1909 #define OPTSTRING_WIN32 ""
1910 #endif /* HAVE_LIBPCAP */
1912 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1913 OPTSTRING_INIT OPTSTRING_WIN32;
1915 /* initialize memory allocation subsystem */
1920 /* Load wpcap if possible. Do this before collecting the run-time version information */
1923 /* ... and also load the packet.dll from wpcap */
1924 wpcap_packet_load();
1926 /* Start windows sockets */
1927 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1930 /* Assemble the compile-time version information string */
1931 comp_info_str = g_string_new("Compiled ");
1932 g_string_append(comp_info_str, "with ");
1933 g_string_sprintfa(comp_info_str,
1934 #ifdef GTK_MAJOR_VERSION
1935 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1938 "GTK+ (version unknown)");
1941 g_string_append(comp_info_str, ", ");
1942 get_compiled_version_info(comp_info_str);
1944 /* Assemble the run-time version information string */
1945 runtime_info_str = g_string_new("Running ");
1946 get_runtime_version_info(runtime_info_str);
1949 /* "pre-scan" the command line parameters, if we have "console only"
1950 parameters. We do this so we don't start GTK+ if we're only showing
1951 command-line help or version information.
1953 XXX - this pre-scan is doen before we start GTK+, so we haven't
1954 run gtk_init() on the arguments. That means that GTK+ arguments
1955 have not been removed from the argument list; those arguments
1956 begin with "--", and will be treated as an error by getopt().
1958 We thus ignore errors - *and* set "opterr" to 0 to suppress the
1961 optind_initial = optind;
1962 while ((opt = getopt(argc, argv, optstring)) != -1) {
1964 case 'h': /* Print help and exit */
1968 case 'v': /* Show version and exit */
1972 case '?': /* Ignore errors - the "real" scan will catch them. */
1977 /* Set getopt index back to initial value, so it will start with the
1978 first command line parameter again. Also reset opterr to 1, so that
1979 error messages are printed by getopt().
1981 XXX - this seems to work on most platforms, but time will tell.
1982 The Single UNIX Specification says "The getopt() function need
1983 not be reentrant", so this isn't guaranteed to work. The Mac
1984 OS X 10.4[.x] getopt() man page says
1986 In order to use getopt() to evaluate multiple sets of arguments, or to
1987 evaluate a single set of arguments multiple times, the variable optreset
1988 must be set to 1 before the second and each additional set of calls to
1989 getopt(), and the variable optind must be reinitialized.
1993 The optreset variable was added to make it possible to call the getopt()
1994 function multiple times. This is an extension to the IEEE Std 1003.2
1995 (``POSIX.2'') specification.
1997 which I think comes from one of the other BSDs.
1999 XXX - if we want to control all the command-line option errors, so
2000 that we can display them where we choose (e.g., in a window), we'd
2001 want to leave opterr as 0, and produce our own messages using optopt.
2002 We'd have to check the value of optopt to see if it's a valid option
2003 letter, in which case *presumably* the error is "this option requires
2004 an argument but none was specified", or not a valid option letter,
2005 in which case *presumably* the error is "this option isn't valid".
2006 Some versions of getopt() let you supply a option string beginning
2007 with ':', which means that getopt() will return ':' rather than '?'
2008 for "this option requires an argument but none was specified", but
2010 optind = optind_initial;
2013 /* Set the current locale according to the program environment.
2014 * We haven't localized anything, but some GTK widgets are localized
2015 * (the file selection dialogue, for example).
2016 * This also sets the C-language locale to the native environment. */
2019 /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
2020 gtk_init (&argc, &argv);
2022 cf_callback_add(main_cf_callback, NULL);
2024 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
2025 /* initialize our GTK eth_clist_type */
2026 init_eth_clist_type();
2029 ethereal_path = argv[0];
2031 /* Arrange that if we have no console window, and a GLib message logging
2032 routine is called to log a message, we pop up a console window.
2034 We do that by inserting our own handler for all messages logged
2035 to the default domain; that handler pops up a console if necessary,
2036 and then calls the default handler. */
2038 /* We might want to have component specific log levels later ... */
2040 /* the default_log_handler will use stdout, which makes trouble with the */
2041 /* capture child, as it uses stdout for it's sync_pipe */
2042 /* so do the filtering in the console_log_handler and not here */
2045 G_LOG_LEVEL_CRITICAL|
2046 G_LOG_LEVEL_WARNING|
2047 G_LOG_LEVEL_MESSAGE|
2050 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
2052 g_log_set_handler(NULL,
2054 console_log_handler, NULL /* user_data */);
2055 g_log_set_handler(LOG_DOMAIN_MAIN,
2057 console_log_handler, NULL /* user_data */);
2060 g_log_set_handler(LOG_DOMAIN_CAPTURE,
2062 console_log_handler, NULL /* user_data */);
2063 g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
2065 console_log_handler, NULL /* user_data */);
2067 /* Set the initial values in the capture_opts. This might be overwritten
2068 by preference settings and then again by the command line parameters. */
2069 capture_opts_init(capture_opts, &cfile);
2071 capture_opts->snaplen = MIN_PACKET_SIZE;
2072 capture_opts->has_ring_num_files = TRUE;
2074 command_name = get_basename(ethereal_path);
2075 /* Set "capture_child" to indicate whether this is going to be a child
2076 process for a "-S" capture. */
2077 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
2078 if (capture_child) {
2079 strcat(optstring, OPTSTRING_CHILD);
2083 /* We want a splash screen only if we're not a child process.
2084 We won't come till here, if we had a "console only" command line parameter. */
2088 splash_win = splash_new("Loading Ethereal ...");
2090 splash_update(splash_win, "Init dissectors ...");
2092 /* Register all dissectors; we must do this before checking for the
2093 "-G" flag, as the "-G" flag dumps information registered by the
2094 dissectors, and we must do it before we read the preferences, in
2095 case any dissectors register preferences. */
2096 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
2097 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
2099 splash_update(splash_win, "Init tap listeners ...");
2101 /* Register all tap listeners; we do this before we parse the arguments,
2102 as the "-z" argument can specify a registered tap. */
2104 /* we register the plugin taps before the other taps because
2105 stats_tree taps plugins will be registered as tap listeners
2106 by stats_tree_stat.c and need to registered before that */
2109 register_all_plugin_tap_listeners();
2112 register_all_tap_listeners();
2114 splash_update(splash_win, "Loading module preferences ...");
2116 /* Now register the preferences for any non-dissector modules.
2117 We must do that before we read the preferences as well. */
2118 prefs_register_modules();
2120 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
2121 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
2124 g_thread_init(NULL);
2126 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
2127 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
2129 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
2130 /* this is to keep tap extensions updating once every 3 seconds */
2131 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
2132 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
2135 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
2138 splash_update(splash_win, "Loading configuration files ...");
2140 /* Read the preference files. */
2141 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
2142 &pf_open_errno, &pf_read_errno, &pf_path);
2143 if (gpf_path != NULL) {
2144 if (gpf_open_errno != 0) {
2145 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2146 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
2147 strerror(gpf_open_errno));
2149 if (gpf_read_errno != 0) {
2150 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2151 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
2152 strerror(gpf_read_errno));
2155 if (pf_path != NULL) {
2156 if (pf_open_errno != 0) {
2157 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2158 "Could not open your preferences file\n\"%s\": %s.", pf_path,
2159 strerror(pf_open_errno));
2161 if (pf_read_errno != 0) {
2162 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2163 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
2164 strerror(pf_read_errno));
2171 /* if the user wants a console to be always there, well, we should open one for him */
2172 if (prefs->gui_console_open == console_open_always) {
2178 /* If this is a capture child process, it should pay no attention
2179 to the "prefs.capture_prom_mode" setting in the preferences file;
2180 it should do what the parent process tells it to do, and if
2181 the parent process wants it not to run in promiscuous mode, it'll
2182 tell it so with a "-p" flag.
2184 Otherwise, set promiscuous mode from the preferences setting. */
2185 /* the same applies to other preferences settings as well. */
2186 if (capture_child) {
2187 auto_scroll_live = FALSE;
2189 capture_opts->promisc_mode = prefs->capture_prom_mode;
2190 capture_opts->show_info = prefs->capture_show_info;
2191 capture_opts->real_time_mode = prefs->capture_real_time;
2192 auto_scroll_live = prefs->capture_auto_scroll;
2195 #endif /* HAVE_LIBPCAP */
2197 /* Set the name resolution code's flags from the preferences. */
2198 g_resolv_flags = prefs->name_resolve;
2200 /* Read the capture filter file. */
2201 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
2202 if (cf_path != NULL) {
2203 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2204 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2205 strerror(cf_open_errno));
2209 /* Read the display filter file. */
2210 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
2211 if (df_path != NULL) {
2212 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2213 "Could not open your display filter file\n\"%s\": %s.", df_path,
2214 strerror(df_open_errno));
2218 /* Read the disabled protocols file. */
2219 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
2220 &dp_path, &dp_open_errno, &dp_read_errno);
2221 if (gdp_path != NULL) {
2222 if (gdp_open_errno != 0) {
2223 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2224 "Could not open global disabled protocols file\n\"%s\": %s.",
2225 gdp_path, strerror(gdp_open_errno));
2227 if (gdp_read_errno != 0) {
2228 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2229 "I/O error reading global disabled protocols file\n\"%s\": %s.",
2230 gdp_path, strerror(gdp_read_errno));
2234 if (dp_path != NULL) {
2235 if (dp_open_errno != 0) {
2236 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2237 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
2238 strerror(dp_open_errno));
2240 if (dp_read_errno != 0) {
2241 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2242 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2243 strerror(dp_read_errno));
2248 /* Read the (static part) of the recent file. Only the static part of it will be read, */
2249 /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2250 /* We have to do this already here, so command line parameters can overwrite these values. */
2251 recent_read_static(&rf_path, &rf_open_errno);
2253 init_cap_file(&cfile);
2255 /* Now get our args */
2256 while ((opt = getopt(argc, argv, optstring)) != -1) {
2258 /*** capture option specific ***/
2259 case 'a': /* autostop criteria */
2260 case 'b': /* Ringbuffer option */
2261 case 'c': /* Capture xxx packets */
2262 case 'f': /* capture filter */
2263 case 'k': /* Start capture immediately */
2264 case 'H': /* Hide capture info dialog box */
2265 case 'i': /* Use interface xxx */
2266 case 'p': /* Don't capture in promiscuous mode */
2267 case 'Q': /* Quit after capture (just capture to file) */
2268 case 's': /* Set the snapshot (capture) length */
2269 case 'S': /* "Sync" mode: used for following file ala tail -f */
2270 case 'w': /* Write to capture file xxx */
2271 case 'y': /* Set the pcap data link type */
2273 case 'B': /* Buffer size */
2274 /* Hidden option supporting Sync mode */
2275 case 'Z': /* Write to pipe FD XXX */
2278 capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
2280 capture_option_specified = TRUE;
2285 /*** all non capture option specific ***/
2286 case 'D': /* Print a list of capture devices and exit */
2288 capture_opts_list_interfaces();
2291 capture_option_specified = TRUE;
2295 case 'g': /* Go to packet */
2296 go_to_packet = get_positive_int(optarg, "go to packet");
2298 case 'l': /* Automatic scrolling in live capture mode */
2300 auto_scroll_live = TRUE;
2302 capture_option_specified = TRUE;
2306 case 'L': /* Print list of link-layer types and exit */
2308 list_link_layer_types = TRUE;
2310 capture_option_specified = TRUE;
2314 case 'm': /* Fixed-width font for the display */
2315 if (prefs->PREFS_GUI_FONT_NAME != NULL)
2316 g_free(prefs->PREFS_GUI_FONT_NAME);
2317 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2319 case 'n': /* No name resolution */
2320 g_resolv_flags = RESOLV_NONE;
2322 case 'N': /* Select what types of addresses/port #s to resolve */
2323 if (g_resolv_flags == RESOLV_ALL)
2324 g_resolv_flags = RESOLV_NONE;
2325 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2326 if (badopt != '\0') {
2327 cmdarg_err("-N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2332 case 'o': /* Override preference from command line */
2333 switch (prefs_set_pref(optarg)) {
2336 case PREFS_SET_SYNTAX_ERR:
2337 cmdarg_err("Invalid -o flag \"%s\"", optarg);
2340 case PREFS_SET_NO_SUCH_PREF:
2341 /* not a preference, might be a recent setting */
2342 switch (recent_set_arg(optarg)) {
2345 case PREFS_SET_SYNTAX_ERR:
2346 /* shouldn't happen, checked already above */
2347 cmdarg_err("Invalid -o flag \"%s\"", optarg);
2350 case PREFS_SET_NO_SUCH_PREF:
2351 case PREFS_SET_OBSOLETE:
2352 cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
2357 g_assert_not_reached();
2360 case PREFS_SET_OBSOLETE:
2361 cmdarg_err("-o flag \"%s\" specifies obsolete preference",
2366 g_assert_not_reached();
2369 case 'r': /* Read capture file xxx */
2370 /* We may set "last_open_dir" to "cf_name", and if we change
2371 "last_open_dir" later, we free the old value, so we have to
2372 set "cf_name" to something that's been allocated. */
2373 #if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
2374 /* since GLib 2.6, we need to convert filenames to utf8 for Win32 */
2375 cf_name = g_locale_to_utf8(optarg, -1, NULL, NULL, NULL);
2377 cf_name = g_strdup(optarg);
2380 case 'R': /* Read file filter */
2383 case 't': /* Time stamp type */
2384 if (strcmp(optarg, "r") == 0)
2385 timestamp_set_type(TS_RELATIVE);
2386 else if (strcmp(optarg, "a") == 0)
2387 timestamp_set_type(TS_ABSOLUTE);
2388 else if (strcmp(optarg, "ad") == 0)
2389 timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2390 else if (strcmp(optarg, "d") == 0)
2391 timestamp_set_type(TS_DELTA);
2393 cmdarg_err("Invalid time stamp type \"%s\"", optarg);
2394 cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
2395 cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
2400 /* We won't call the init function for the stat this soon
2401 as it would disallow MATE's fields (which are registered
2402 by the preferences set callback) from being used as
2403 part of a tap filter. Instead, we just add the argument
2404 to a list of stat arguments. */
2405 if (!process_stat_cmd_arg(optarg)) {
2406 cmdarg_err("Invalid -z argument.");
2407 cmdarg_err_cont(" -z argument must be one of :");
2408 list_stat_cmd_args();
2413 case '?': /* Bad flag - print usage message */
2421 if (cf_name != NULL) {
2423 * Input file name specified with "-r" *and* specified as a regular
2424 * command-line argument.
2426 cmdarg_err("File name specified both with -r and regular argument");
2430 * Input file name not specified with "-r", and a command-line argument
2431 * was specified; treat it as the input file name.
2433 * Yes, this is different from tethereal, where non-flag command-line
2434 * arguments are a filter, but this works better on GUI desktops
2435 * where a command can be specified to be run to open a particular
2436 * file - yes, you could have "-r" as the last part of the command,
2437 * but that's a bit ugly.
2439 #if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
2440 /* since GLib 2.6, we need to convert filenames to utf8 for Win32 */
2441 cf_name = g_locale_to_utf8(argv[0], -1, NULL, NULL, NULL);
2443 cf_name = g_strdup(argv[0]);
2454 * Extra command line arguments were specified; complain.
2456 cmdarg_err("Invalid argument: %s", argv[0]);
2461 #ifndef HAVE_LIBPCAP
2462 if (capture_option_specified) {
2463 cmdarg_err("This version of Ethereal was not built with support for capturing packets.");
2471 if (start_capture && list_link_layer_types) {
2472 /* Specifying *both* is bogus. */
2473 cmdarg_err("You can't specify both -L and a live capture.");
2477 if (list_link_layer_types) {
2478 /* We're supposed to list the link-layer types for an interface;
2479 did the user also specify a capture file to be read? */
2481 /* Yes - that's bogus. */
2482 cmdarg_err("You can't specify -L and a capture file to be read.");
2485 /* No - did they specify a ring buffer option? */
2486 if (capture_opts->multi_files_on) {
2487 cmdarg_err("Ring buffer requested, but a capture isn't being done.");
2491 /* We're supposed to do a live capture; did the user also specify
2492 a capture file to be read? */
2493 if (start_capture && cf_name) {
2494 /* Yes - that's bogus. */
2495 cmdarg_err("You can't specify both a live capture and a capture file to be read.");
2499 /* No - was the ring buffer option specified and, if so, does it make
2501 if (capture_opts->multi_files_on) {
2502 /* Ring buffer works only under certain conditions:
2503 a) ring buffer does not work with temporary files;
2504 b) real_time_mode and multi_files_on are mutually exclusive -
2505 real_time_mode takes precedence;
2506 c) it makes no sense to enable the ring buffer if the maximum
2507 file size is set to "infinite". */
2508 if (capture_opts->save_file == NULL) {
2509 cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
2510 capture_opts->multi_files_on = FALSE;
2512 /* if (capture_opts->real_time_mode) {
2513 cmdarg_err("Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2514 capture_opts->multi_files_on = FALSE;
2516 if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2517 cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
2518 /* XXX - this must be redesigned as the conditions changed */
2519 /* capture_opts->multi_files_on = FALSE;*/
2524 if (start_capture || list_link_layer_types) {
2525 /* Did the user specify an interface to use? */
2526 if (!capture_opts_trim_iface(capture_opts,
2527 (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) {
2532 if (list_link_layer_types) {
2533 capture_opts_list_link_layer_types(capture_opts);
2537 capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
2538 capture_opts_trim_ring_num_files(capture_opts);
2539 #endif /* HAVE_LIBPCAP */
2541 /* Notify all registered modules that have had any of their preferences
2542 changed either from one of the preferences file or from the command
2543 line that their preferences have changed. */
2546 /* disabled protocols as per configuration file */
2547 if (gdp_path == NULL && dp_path == NULL) {
2548 set_disabled_protos_list();
2551 /* Build the column format array */
2552 col_setup(&cfile.cinfo, prefs->num_cols);
2553 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2554 cfile.cinfo.col_fmt[i] = get_column_format(i);
2555 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2556 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2558 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2559 cfile.cinfo.col_data[i] = NULL;
2560 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2561 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2563 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2564 cfile.cinfo.col_fence[i] = 0;
2565 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2566 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2569 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2572 for (j = 0; j < NUM_COL_FMTS; j++) {
2573 if (!cfile.cinfo.fmt_matx[i][j])
2576 if (cfile.cinfo.col_first[j] == -1)
2577 cfile.cinfo.col_first[j] = i;
2578 cfile.cinfo.col_last[j] = i;
2582 /* read in rc file from global and personal configuration paths. */
2583 rc_file = get_datafile_path(RC_FILE);
2584 gtk_rc_parse(rc_file);
2585 rc_file = get_persconffile_path(RC_FILE, FALSE);
2586 gtk_rc_parse(rc_file);
2589 font_init(capture_child);
2594 /* close the splash screen, as we are going to open the main window now */
2595 splash_destroy(splash_win);
2599 /* Is this a "child" ethereal, which is only supposed to pop up a
2600 capture box to let us stop the capture, and run a capture
2601 to a file that our parent will read? */
2602 if (capture_child) {
2603 /* This is the child process of a capture session,
2604 so just do the low-level work of a capture - don't create
2605 a temporary file and fork off *another* child process (so don't
2606 call "capture_start()"). */
2608 /* Pop up any queued-up alert boxes. */
2609 display_queued_messages();
2611 /* Now start the capture.
2612 After the capture is done; there's nothing more for us to do. */
2614 /* XXX - hand these stats to the parent process */
2615 if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2619 /* capture failed */
2625 /***********************************************************************/
2626 /* Everything is prepared now, preferences and command line was read in,
2627 we are NOT a child window for a synced capture. */
2629 /* Pop up the main window. */
2630 create_main_window(pl_size, tv_size, bv_size, prefs);
2632 /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2633 recent_read_dynamic(&rf_path, &rf_open_errno);
2634 color_filters_enable(recent.packet_list_colorize);
2636 /* rearrange all the widgets as we now have all recent settings ready for this */
2637 main_widgets_rearrange();
2639 /* Fill in column titles. This must be done after the top level window
2642 XXX - is that still true, with fixed-width columns? */
2643 packet_list_set_column_titles();
2645 menu_recent_read_finished();
2647 switch (user_font_apply()) {
2650 case FA_FONT_NOT_RESIZEABLE:
2651 /* "user_font_apply()" popped up an alert box. */
2652 /* turn off zooming - font can't be resized */
2653 case FA_FONT_NOT_AVAILABLE:
2654 /* XXX - did we successfully load the un-zoomed version earlier?
2655 If so, this *probably* means the font is available, but not at
2656 this particular zoom level, but perhaps some other failure
2657 occurred; I'm not sure you can determine which is the case,
2659 /* turn off zooming - zoom level is unavailable */
2661 /* in any other case than FA_SUCCESS, turn off zooming */
2662 recent.gui_zoom_level = 0;
2663 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2666 dnd_init(top_level);
2669 color_filters_init();
2672 /* the window can be sized only, if it's not already shown, so do it now! */
2673 main_load_window_geometry(top_level);
2675 /* If we were given the name of a capture file, read it in now;
2676 we defer it until now, so that, if we can't open it, and pop
2677 up an alert box, the alert box is more likely to come up on
2678 top of the main window - but before the preference-file-error
2679 alert box, so, if we get one of those, it's more likely to come
2682 show_main_window(TRUE);
2683 if (rfilter != NULL) {
2684 if (!dfilter_compile(rfilter, &rfcode)) {
2685 bad_dfilter_alert_box(rfilter);
2686 rfilter_parse_failed = TRUE;
2689 if (!rfilter_parse_failed) {
2690 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2691 /* "cf_open()" succeeded, so it closed the previous
2692 capture file, and thus destroyed any previous read filter
2693 attached to "cf". */
2695 cfile.rfcode = rfcode;
2696 /* Open stat windows; we do so after creating the main window,
2697 to avoid GTK warnings, and after successfully opening the
2698 capture file, so we know we have something to compute stats
2699 on, and after registering all dissectors, so that MATE will
2700 have registered its field array and we can have a tap filter
2701 with one of MATE's late-registered fields as part of the
2703 start_requested_stats();
2705 /* Read the capture file. */
2706 switch (cf_read(&cfile)) {
2710 /* Just because we got an error, that doesn't mean we were unable
2711 to read any of the file; we handle what we could get from the
2713 /* if the user told us to jump to a specific packet, do it now */
2714 if(go_to_packet != 0) {
2715 cf_goto_frame(&cfile, go_to_packet);
2719 case CF_READ_ABORTED:
2724 /* Save the name of the containing directory specified in the
2725 path name, if any; we can write over cf_name, which is a
2726 good thing, given that "get_dirname()" does write over its
2728 s = get_dirname(cf_name);
2729 /* we might already set this from the recent file, don't overwrite this */
2730 if(get_last_open_dir() == NULL)
2731 set_last_open_dir(s);
2736 dfilter_free(rfcode);
2737 cfile.rfcode = NULL;
2738 show_main_window(FALSE);
2739 set_menus_for_capture_in_progress(FALSE);
2744 if (start_capture) {
2745 if (capture_opts->save_file != NULL) {
2746 /* Save the directory name for future file dialogs. */
2747 /* (get_dirname overwrites filename) */
2748 s = get_dirname(g_strdup(capture_opts->save_file));
2749 set_last_open_dir(s);
2752 /* "-k" was specified; start a capture. */
2753 show_main_window(TRUE);
2754 if (capture_start(capture_opts)) {
2755 /* The capture started. Open stat windows; we do so after creating
2756 the main window, to avoid GTK warnings, and after successfully
2757 opening the capture file, so we know we have something to compute
2758 stats on, and after registering all dissectors, so that MATE will
2759 have registered its field array and we can have a tap filter with
2760 one of MATE's late-registered fields as part of the filter. */
2761 start_requested_stats();
2765 show_main_window(FALSE);
2766 set_menus_for_capture_in_progress(FALSE);
2769 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2770 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2771 if (capture_opts->cfilter) {
2772 g_free(capture_opts->cfilter);
2774 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2776 #else /* HAVE_LIBPCAP */
2777 show_main_window(FALSE);
2778 set_menus_for_capture_in_progress(FALSE);
2779 #endif /* HAVE_LIBPCAP */
2782 /* we'll enter the GTK loop now and hand the control over to GTK ... */
2784 /* ... back from GTK, we're going down now! */
2790 /* hide the (unresponsive) main window, while asking the user to close the console window */
2791 gtk_widget_hide(top_level);
2793 /* Shutdown windows sockets */
2796 /* For some unknown reason, the "atexit()" call in "create_console()"
2797 doesn't arrange that "destroy_console()" be called when we exit,
2798 so we call it here if a console was created. */
2804 /* This isn't reached, but we need it to keep GCC from complaining
2805 that "main()" returns without returning a value - it knows that
2806 "exit()" never returns, but it doesn't know that "gtk_exit()"
2807 doesn't, as GTK+ doesn't declare it with the attribute
2809 return 0; /* not reached */
2814 /* We build this as a GUI subsystem application on Win32, so
2815 "WinMain()", not "main()", gets called.
2817 Hack shamelessly stolen from the Win32 port of the GIMP. */
2819 #define _stdcall __attribute__((stdcall))
2823 WinMain (struct HINSTANCE__ *hInstance,
2824 struct HINSTANCE__ *hPrevInstance,
2828 has_console = FALSE;
2829 return main (__argc, __argv);
2833 * If this application has no console window to which its standard output
2834 * would go, create one.
2837 create_console(void)
2840 /* We have no console to which to print the version string, so
2841 create one and make it the standard input, output, and error. */
2842 if (!AllocConsole())
2843 return; /* couldn't create console */
2844 eth_freopen("CONIN$", "r", stdin);
2845 eth_freopen("CONOUT$", "w", stdout);
2846 eth_freopen("CONOUT$", "w", stderr);
2848 /* Well, we have a console now. */
2851 /* Now register "destroy_console()" as a routine to be called just
2852 before the application exits, so that we can destroy the console
2853 after the user has typed a key (so that the console doesn't just
2854 disappear out from under them, giving the user no chance to see
2855 the message(s) we put in there). */
2856 atexit(destroy_console);
2859 SetConsoleTitle("Ethereal Capture Child Debug Console");
2861 SetConsoleTitle("Ethereal Debug Console");
2867 destroy_console(void)
2869 if (has_console && !capture_child) {
2870 printf("\n\nPress any key to exit\n");
2878 /* This routine should not be necessary, at least as I read the GLib
2879 source code, as it looks as if GLib is, on Win32, *supposed* to
2880 create a console window into which to display its output.
2882 That doesn't happen, however. I suspect there's something completely
2883 broken about that code in GLib-for-Win32, and that it may be related
2884 to the breakage that forces us to just call "printf()" on the message
2885 rather than passing the message on to "g_log_default_handler()"
2886 (which is the routine that does the aforementioned non-functional
2887 console window creation). */
2889 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2890 const char *message, gpointer user_data _U_)
2897 /* ignore log message, if log_level isn't interesting */
2898 if( !(log_level & G_LOG_LEVEL_MASK & prefs.console_log_level)) {
2902 /* create a "timestamp" */
2904 today = localtime(&curr);
2907 if (prefs.gui_console_open != console_open_never) {
2911 /* For some unknown reason, the above doesn't appear to actually cause
2912 anything to be sent to the standard output, so we'll just splat the
2913 message out directly, just to make sure it gets out. */
2915 switch(log_level & G_LOG_LEVEL_MASK) {
2916 case G_LOG_LEVEL_ERROR:
2919 case G_LOG_LEVEL_CRITICAL:
2922 case G_LOG_LEVEL_WARNING:
2925 case G_LOG_LEVEL_MESSAGE:
2928 case G_LOG_LEVEL_INFO:
2931 case G_LOG_LEVEL_DEBUG:
2935 fprintf(stderr, "unknown log_level %u\n", log_level);
2937 g_assert_not_reached();
2940 /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2941 fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2942 today->tm_hour, today->tm_min, today->tm_sec,
2943 log_domain != NULL ? log_domain : "",
2947 g_log_default_handler(log_domain, log_level, message, user_data);
2953 static GtkWidget *info_bar_new(void)
2955 /* tip: tooltips don't work on statusbars! */
2956 info_bar = gtk_statusbar_new();
2957 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2958 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2959 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2960 #if GTK_MAJOR_VERSION >= 2
2961 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2963 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2968 static GtkWidget *packets_bar_new(void)
2970 /* tip: tooltips don't work on statusbars! */
2971 packets_bar = gtk_statusbar_new();
2972 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2973 packets_bar_update();
2980 * Helper for main_widgets_rearrange()
2982 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2983 gtk_container_remove(GTK_CONTAINER(data), widget);
2986 static GtkWidget *main_widget_layout(gint layout_content)
2988 switch(layout_content) {
2989 case(layout_pane_content_none):
2992 case(layout_pane_content_plist):
2995 case(layout_pane_content_pdetails):
2998 case(layout_pane_content_pbytes):
3002 g_assert_not_reached();
3009 * Rearrange the main window widgets
3011 void main_widgets_rearrange(void) {
3012 GtkWidget *first_pane_widget1, *first_pane_widget2;
3013 GtkWidget *second_pane_widget1, *second_pane_widget2;
3014 gboolean split_top_left;
3016 /* be a bit faster */
3017 gtk_widget_hide(main_vbox);
3019 /* be sure, we don't loose a widget while rearranging */
3020 gtk_widget_ref(menubar);
3021 gtk_widget_ref(main_tb);
3022 gtk_widget_ref(filter_tb);
3023 gtk_widget_ref(pkt_scrollw);
3024 gtk_widget_ref(tv_scrollw);
3025 gtk_widget_ref(byte_nb_ptr);
3026 gtk_widget_ref(stat_hbox);
3027 gtk_widget_ref(info_bar);
3028 gtk_widget_ref(packets_bar);
3029 gtk_widget_ref(status_pane);
3030 gtk_widget_ref(main_pane_v1);
3031 gtk_widget_ref(main_pane_v2);
3032 gtk_widget_ref(main_pane_h1);
3033 gtk_widget_ref(main_pane_h2);
3034 gtk_widget_ref(welcome_pane);
3036 /* empty all containers participating */
3037 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
3038 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
3039 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
3040 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
3041 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
3042 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
3043 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
3045 /* add the menubar always at the top */
3046 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
3049 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
3051 /* filter toolbar in toolbar area */
3052 if (!prefs.filter_toolbar_show_in_statusbar) {
3053 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
3056 /* fill the main layout panes */
3057 switch(prefs.gui_layout_type) {
3058 case(layout_type_5):
3059 main_first_pane = main_pane_v1;
3060 main_second_pane = main_pane_v2;
3061 split_top_left = FALSE;
3063 case(layout_type_2):
3064 main_first_pane = main_pane_v1;
3065 main_second_pane = main_pane_h1;
3066 split_top_left = FALSE;
3068 case(layout_type_1):
3069 main_first_pane = main_pane_v1;
3070 main_second_pane = main_pane_h1;
3071 split_top_left = TRUE;
3073 case(layout_type_4):
3074 main_first_pane = main_pane_h1;
3075 main_second_pane = main_pane_v1;
3076 split_top_left = FALSE;
3078 case(layout_type_3):
3079 main_first_pane = main_pane_h1;
3080 main_second_pane = main_pane_v1;
3081 split_top_left = TRUE;
3083 case(layout_type_6):
3084 main_first_pane = main_pane_h1;
3085 main_second_pane = main_pane_h2;
3086 split_top_left = FALSE;
3089 main_first_pane = NULL;
3090 main_second_pane = NULL;
3091 split_top_left = FALSE;
3092 g_assert_not_reached();
3094 if (split_top_left) {
3095 first_pane_widget1 = main_second_pane;
3096 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
3097 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
3098 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
3100 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
3101 first_pane_widget2 = main_second_pane;
3102 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
3103 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
3105 if (first_pane_widget1 != NULL)
3106 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
3107 if (first_pane_widget2 != NULL)
3108 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
3109 if (second_pane_widget1 != NULL)
3110 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
3111 if (second_pane_widget2 != NULL)
3112 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
3114 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
3117 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
3119 /* statusbar hbox */
3120 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
3122 /* filter toolbar in statusbar hbox */
3123 if (prefs.filter_toolbar_show_in_statusbar) {
3124 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
3128 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
3129 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
3130 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
3132 /* hide widgets on users recent settings */
3133 main_widgets_show_or_hide();
3135 gtk_widget_show(main_vbox);
3139 is_widget_visible(GtkWidget *widget, gpointer data)
3141 gboolean *is_visible = data;
3144 if (GTK_WIDGET_VISIBLE(widget))
3150 #ifdef SHOW_WELCOME_PAGE
3151 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
3152 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
3154 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
3156 GtkWidget *w, *item_hb;
3157 #if GTK_MAJOR_VERSION >= 2
3158 gchar *formatted_message;
3162 item_hb = gtk_hbox_new(FALSE, 1);
3164 w = BUTTON_NEW_FROM_STOCK(stock_item);
3165 WIDGET_SET_SIZE(w, 60, 60);
3166 #if GTK_MAJOR_VERSION >= 2
3167 gtk_button_set_label(GTK_BUTTON(w), label);
3169 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
3170 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
3172 w = gtk_label_new(message);
3173 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3174 #if GTK_MAJOR_VERSION >= 2
3175 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
3176 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
3177 g_free(formatted_message);
3180 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
3186 /* XXX - the layout has to be improved */
3190 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
3191 GtkWidget *w, *icon;
3195 welcome_scrollw = scrolled_window_new(NULL, NULL);
3197 welcome_hb = gtk_hbox_new(FALSE, 1);
3198 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
3200 welcome_vb = gtk_vbox_new(FALSE, 1);
3202 item_hb = gtk_hbox_new(FALSE, 1);
3204 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
3205 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
3207 #if GTK_MAJOR_VERSION < 2
3208 message = "Welcome to Ethereal!";
3210 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
3212 w = gtk_label_new(message);
3213 #if GTK_MAJOR_VERSION >= 2
3214 gtk_label_set_markup(GTK_LABEL(w), message);
3216 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3217 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3219 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3221 w = gtk_label_new("What would you like to do?");
3222 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
3223 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3226 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
3228 "Capture live data from your network",
3229 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
3230 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3233 item_hb = welcome_item(GTK_STOCK_OPEN,
3235 "Open a previously captured file",
3236 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
3237 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3239 #if (GLIB_MAJOR_VERSION >= 2)
3240 item_hb = welcome_item(GTK_STOCK_HOME,
3242 "Visit the Ethereal homepage",
3243 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
3244 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3246 item_hb = welcome_item(ETHEREAL_STOCK_WEB_SUPPORT,
3248 "Open the Ethereal User's Guide",
3249 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
3250 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3254 w = gtk_label_new("");
3255 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
3257 w = gtk_label_new("");
3258 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3260 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3262 w = gtk_label_new("");
3263 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3265 gtk_widget_show_all(welcome_hb);
3267 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3269 gtk_widget_show_all(welcome_scrollw);
3271 return welcome_scrollw;
3277 /* this is just a dummy to fill up window space, simply showing nothing */
3278 return scrolled_window_new(NULL, NULL);
3285 * XXX - this doesn't appear to work with the paned widgets in
3286 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3287 * and the other pane doesn't grow to take up the rest of the pane.
3288 * It does appear to work with GTK+ 2.x.
3291 main_widgets_show_or_hide(void)
3293 gboolean main_second_pane_show;
3295 if (recent.main_toolbar_show) {
3296 gtk_widget_show(main_tb);
3298 gtk_widget_hide(main_tb);
3302 * Show the status hbox if either:
3304 * 1) we're showing the filter toolbar and we want it in the status
3309 * 2) we're showing the status bar.
3311 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3312 recent.statusbar_show) {
3313 gtk_widget_show(stat_hbox);
3315 gtk_widget_hide(stat_hbox);
3318 if (recent.statusbar_show) {
3319 gtk_widget_show(status_pane);
3321 gtk_widget_hide(status_pane);
3324 if (recent.filter_toolbar_show) {
3325 gtk_widget_show(filter_tb);
3327 gtk_widget_hide(filter_tb);
3330 if (recent.packet_list_show && have_capture_file) {
3331 gtk_widget_show(pkt_scrollw);
3333 gtk_widget_hide(pkt_scrollw);
3336 if (recent.tree_view_show && have_capture_file) {
3337 gtk_widget_show(tv_scrollw);
3339 gtk_widget_hide(tv_scrollw);
3342 if (recent.byte_view_show && have_capture_file) {
3343 gtk_widget_show(byte_nb_ptr);
3345 gtk_widget_hide(byte_nb_ptr);
3348 if (have_capture_file) {
3349 gtk_widget_show(main_first_pane);
3351 gtk_widget_hide(main_first_pane);
3355 * Is anything in "main_second_pane" visible?
3356 * If so, show it, otherwise hide it.
3358 main_second_pane_show = FALSE;
3359 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3360 &main_second_pane_show);
3361 if (main_second_pane_show) {
3362 gtk_widget_show(main_second_pane);
3364 gtk_widget_hide(main_second_pane);
3367 if (!have_capture_file) {
3369 gtk_widget_show(welcome_pane);
3372 gtk_widget_hide(welcome_pane);
3377 #if GTK_MAJOR_VERSION >= 2
3378 /* called, when the window state changes (minimized, maximized, ...) */
3380 window_state_event_cb (GtkWidget *widget _U_,
3384 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3386 if( (event->type) == (GDK_WINDOW_STATE)) {
3387 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3388 /* we might have dialogs popped up while we where iconified,
3390 display_queued_messages();
3399 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3402 *filter_bt, *filter_cm, *filter_te,
3403 *filter_add_expr_bt,
3406 GList *dfilter_list = NULL;
3407 GtkTooltips *tooltips;
3408 GtkAccelGroup *accel;
3410 /* Display filter construct dialog has an Apply button, and "OK" not
3411 only sets our text widget, it activates it (i.e., it causes us to
3412 filter the capture). */
3413 static construct_args_t args = {
3414 "Ethereal: Display Filter",
3420 /* use user-defined title if preference is set */
3421 title = create_user_window_title("The Ethereal Network Analyzer");
3424 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3427 tooltips = gtk_tooltips_new();
3430 #if GTK_MAJOR_VERSION < 2
3431 /* has to be done, after top_level window is created */
3432 app_font_gtk1_init(top_level);
3436 gtk_widget_set_name(top_level, "main window");
3437 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3439 #if GTK_MAJOR_VERSION >= 2
3440 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3441 G_CALLBACK (window_state_event_cb), NULL);
3444 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3446 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3447 main_vbox = gtk_vbox_new(FALSE, 1);
3448 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3449 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3450 gtk_widget_show(main_vbox);
3453 menubar = main_menu_new(&accel);
3454 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3455 gtk_widget_show(menubar);
3458 main_tb = toolbar_new();
3459 gtk_widget_show (main_tb);
3462 pkt_scrollw = packet_list_new(prefs);
3463 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3464 gtk_widget_show(pkt_scrollw);
3467 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3468 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3469 gtk_widget_show(tv_scrollw);
3471 #if GTK_MAJOR_VERSION < 2
3472 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3473 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3476 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3477 "changed", tree_view_selection_changed_cb, NULL);
3479 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3480 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3481 gtk_widget_show(tree_view);
3484 byte_nb_ptr = byte_view_new();
3485 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3486 gtk_widget_show(byte_nb_ptr);
3488 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3489 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3492 /* Panes for the packet list, tree, and byte view */
3493 main_pane_v1 = gtk_vpaned_new();
3494 gtk_widget_show(main_pane_v1);
3495 main_pane_v2 = gtk_vpaned_new();
3496 gtk_widget_show(main_pane_v2);
3497 main_pane_h1 = gtk_hpaned_new();
3498 gtk_widget_show(main_pane_h1);
3499 main_pane_h2 = gtk_hpaned_new();
3500 gtk_widget_show(main_pane_h2);
3502 /* filter toolbar */
3503 #if GTK_MAJOR_VERSION < 2
3504 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3507 filter_tb = gtk_toolbar_new();
3508 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3509 GTK_ORIENTATION_HORIZONTAL);
3510 #endif /* GTK_MAJOR_VERSION */
3511 gtk_widget_show(filter_tb);
3513 /* Create the "Filter:" button */
3514 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3515 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3516 gtk_widget_show(filter_bt);
3517 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3519 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3520 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3522 /* Create the filter combobox */
3523 filter_cm = gtk_combo_new();
3524 dfilter_list = NULL;
3525 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3526 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3527 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3528 filter_te = GTK_COMBO(filter_cm)->entry;
3529 main_display_filter_widget=filter_te;
3530 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3531 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3532 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3533 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3534 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3535 WIDGET_SET_SIZE(filter_cm, 400, -1);
3536 gtk_widget_show(filter_cm);
3537 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3539 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3540 gtk_tooltips_set_tip(tooltips, filter_te,
3541 "Enter a display filter, or choose one of your recently used filters. "
3542 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3545 /* Create the "Add Expression..." button, to pop up a dialog
3546 for constructing filter comparison expressions. */
3547 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3548 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3549 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3550 gtk_widget_show(filter_add_expr_bt);
3551 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3552 "Add an expression to this filter string", "Private");
3554 /* Create the "Clear" button */
3555 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3556 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3557 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3558 gtk_widget_show(filter_reset);
3559 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3560 "Clear this filter string and update the display", "Private");
3562 /* Create the "Apply" button */
3563 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3564 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3565 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3566 gtk_widget_show(filter_apply);
3567 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3568 "Apply this filter string to the display", "Private");
3570 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3571 * of any widget that ends up calling a callback which needs
3572 * that text entry pointer */
3573 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3574 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3576 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3578 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3580 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3582 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3584 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3586 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3588 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3590 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3592 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3594 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3596 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3598 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3600 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3602 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3603 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3604 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3606 /* info (main) statusbar */
3607 info_bar = info_bar_new();
3608 gtk_widget_show(info_bar);
3610 /* packets statusbar */
3611 packets_bar = packets_bar_new();
3612 gtk_widget_show(packets_bar);
3614 /* Filter/status hbox */
3615 stat_hbox = gtk_hbox_new(FALSE, 1);
3616 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3617 gtk_widget_show(stat_hbox);
3619 /* Pane for the statusbar */
3620 status_pane = gtk_hpaned_new();
3621 gtk_widget_show(status_pane);
3623 /* Pane for the welcome screen */
3624 welcome_pane = welcome_new();
3625 gtk_widget_show(welcome_pane);
3629 show_main_window(gboolean doing_work)
3631 main_set_for_capture_file(doing_work);
3633 /*** we have finished all init things, show the main window ***/
3634 gtk_widget_show(top_level);
3636 /* the window can be maximized only, if it's visible, so do it after show! */
3637 main_load_window_geometry(top_level);
3639 /* process all pending GUI events before continue */
3640 while (gtk_events_pending()) gtk_main_iteration();
3642 /* Pop up any queued-up alert boxes. */
3643 display_queued_messages();