3 * $Id: main.c,v 1.442 2004/06/17 16:35:25 ulfl Exp $
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.
32 * - Multiple window support
33 * - Add cut/copy/paste
34 * - Create header parsing routines
35 * - Make byte view selections more fancy?
56 #include <io.h> /* open/close on win32 */
59 #ifdef NEED_STRERROR_H
67 #ifdef WIN32 /* Needed for console I/O */
72 #include <epan/epan.h>
73 #include <epan/filesystem.h>
74 #include <epan/epan_dissect.h>
75 #include <epan/timestamp.h>
76 #include <epan/packet.h>
77 #include <epan/plugins.h>
78 #include <epan/dfilter/dfilter.h>
79 #include <epan/strutil.h>
80 #include <epan/resolv.h>
82 /* general (not GTK specific) */
83 #include "cvsversion.h"
87 #include "disabled_protos.h"
89 #include "filter_prefs.h"
90 #include "layout_prefs.h"
92 #include "color_filters.h"
93 #include "color_utils.h"
95 #include "simple_dialog.h"
97 #include "prefs-int.h"
98 #include "ringbuffer.h"
99 #include "../ui_util.h" /* beware: ui_util.h exists twice! */
102 #include "version_info.h"
105 #include "pcap-util.h"
108 #include "capture-wpcap.h"
112 #include "statusbar.h"
113 #include "alert_box.h"
114 #include "dlg_utils.h"
115 #include "gtkglobals.h"
117 #include "ui_util.h" /* beware: ui_util.h exists twice! */
118 #include "compat_macros.h"
123 #include "file_dlg.h"
125 #include "proto_draw.h"
127 #include "packet_win.h"
129 #include "find_dlg.h"
130 #include "packet_list.h"
132 #include "follow_dlg.h"
133 #include "font_utils.h"
137 * File under personal preferences directory in which GTK settings for
138 * Ethereal are stored.
140 #define RC_FILE "gtkrc"
143 #define DEF_READY_MESSAGE " Ready to load or capture"
145 #define DEF_READY_MESSAGE " Ready to load file"
149 GtkWidget *main_display_filter_widget=NULL;
150 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
151 static GtkWidget *none_lb, *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
152 static GtkWidget *main_first_pane, *main_second_pane;
153 static GtkWidget *status_pane;
154 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
155 static GtkWidget *info_bar;
156 static GtkWidget *packets_bar = NULL;
157 static guint main_ctx, file_ctx, help_ctx;
158 static guint packets_ctx;
159 static gchar *packets_str = NULL;
160 GString *comp_info_str, *runtime_info_str;
161 gchar *ethereal_path = NULL;
164 static gboolean has_console; /* TRUE if app has console */
165 /*static void create_console(void);*/
166 static void destroy_console(void);
167 static void console_log_handler(const char *log_domain,
168 GLogLevelFlags log_level, const char *message, gpointer user_data);
172 static gboolean list_link_layer_types;
175 static void create_main_window(gint, gint, gint, e_prefs*);
176 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_);
177 static void main_save_window_geometry(GtkWidget *widget);
179 #define E_DFILTER_CM_KEY "display_filter_combo"
180 #define E_DFILTER_FL_KEY "display_filter_list"
184 /* Match selected byte pattern */
186 match_selected_cb_do(gpointer data, int action, gchar *text)
188 GtkWidget *filter_te;
189 char *cur_filter, *new_filter;
194 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
197 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
199 switch (action&MATCH_SELECTED_MASK) {
201 case MATCH_SELECTED_REPLACE:
202 new_filter = g_strdup(text);
205 case MATCH_SELECTED_AND:
206 if ((!cur_filter) || (0 == strlen(cur_filter)))
207 new_filter = g_strdup(text);
209 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
212 case MATCH_SELECTED_OR:
213 if ((!cur_filter) || (0 == strlen(cur_filter)))
214 new_filter = g_strdup(text);
216 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
219 case MATCH_SELECTED_NOT:
220 new_filter = g_strconcat("!(", text, ")", NULL);
223 case MATCH_SELECTED_AND_NOT:
224 if ((!cur_filter) || (0 == strlen(cur_filter)))
225 new_filter = g_strconcat("!(", text, ")", NULL);
227 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
230 case MATCH_SELECTED_OR_NOT:
231 if ((!cur_filter) || (0 == strlen(cur_filter)))
232 new_filter = g_strconcat("!(", text, ")", NULL);
234 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
238 g_assert_not_reached();
243 /* Free up the copy we got of the old filter text. */
246 /* create a new one and set the display filter entry accordingly */
247 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
249 /* Run the display filter so it goes in effect. */
250 if (action&MATCH_SELECTED_APPLY_NOW)
251 main_filter_packets(&cfile, new_filter, FALSE);
253 /* Free up the new filter text. */
256 /* Free up the generated text we were handed. */
261 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
263 if (cfile.finfo_selected)
264 match_selected_cb_do((data ? data : w),
266 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
271 get_text_from_packet_list(gpointer data)
273 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
274 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
275 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
283 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
284 cfile.pd, fdata->cap_len, &err, &err_info)) {
285 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
286 cf_read_error_message(err, err_info), cfile.filename);
290 edt = epan_dissect_new(FALSE, FALSE);
291 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
293 epan_dissect_fill_in_columns(edt);
295 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
296 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
297 len = strlen(cfile.cinfo.col_expr[column]) +
298 strlen(cfile.cinfo.col_expr_val[column]) + 5;
299 buf = g_malloc0(len);
300 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
301 cfile.cinfo.col_expr_val[column]);
304 epan_dissect_free(edt);
311 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
313 match_selected_cb_do(data,
315 get_text_from_packet_list(data));
320 /* XXX: use a preference for this setting! */
321 static guint dfilter_combo_max_recent = 10;
323 /* add a display filter to the combo box */
324 /* Note: a new filter string will replace an old identical one */
326 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
328 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
331 /* GtkCombos don't let us get at their list contents easily, so we maintain
332 our own filter list, and feed it to gtk_combo_set_popdown_strings when
333 a new filter is added. */
334 li = g_list_first(filter_list);
336 /* If the filter is already in the list, remove the old one and
337 * append the new one at the latest position (at g_list_append() below) */
338 if (li->data && strcmp(s, li->data) == 0) {
339 filter_list = g_list_remove(filter_list, li->data);
345 filter_list = g_list_append(filter_list, s);
346 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
347 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
348 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data);
354 /* write all non empty display filters (until maximum count)
355 * of the combo box GList to the user's recent file */
357 dfilter_recent_combo_write_all(FILE *rf) {
358 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
359 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
364 /* write all non empty display filter strings to the recent file (until max count) */
365 li = g_list_first(filter_list);
366 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
367 if (strlen(li->data)) {
368 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
374 /* empty the combobox entry field */
376 dfilter_combo_add_empty(void) {
377 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
379 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
383 /* add a display filter coming from the user's recent file to the dfilter combo box */
385 dfilter_combo_add_recent(gchar *s) {
386 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
390 if (!dfilter_combo_add(filter_cm, dup)) {
399 /* call filter_packets() and add this filter string to the recent filter list */
401 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
403 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
404 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
406 gboolean add_filter = TRUE;
407 gboolean free_filter = TRUE;
409 gboolean filter_packets_ret;
411 s = g_strdup(dftext);
413 /* GtkCombos don't let us get at their list contents easily, so we maintain
414 our own filter list, and feed it to gtk_combo_set_popdown_strings when
415 a new filter is added. */
416 if ((filter_packets_ret = filter_packets(cf, s, force))) {
417 li = g_list_first(filter_list);
419 if (li->data && strcmp(s, li->data) == 0)
425 /* trim list size first */
426 while (g_list_length(filter_list) >= dfilter_combo_max_recent) {
427 filter_list = g_list_remove(filter_list, g_list_first(filter_list)->data);
431 filter_list = g_list_append(filter_list, s);
432 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
433 gtk_combo_set_popdown_strings(filter_cm, filter_list);
434 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
440 return filter_packets_ret;
444 /* Run the current display filter on the current packet set, and
447 filter_activate_cb(GtkWidget *w _U_, gpointer data)
451 s = gtk_entry_get_text(GTK_ENTRY(data));
453 main_filter_packets(&cfile, s, FALSE);
456 /* redisplay with no display filter */
458 filter_reset_cb(GtkWidget *w, gpointer data _U_)
460 GtkWidget *filter_te = NULL;
462 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
463 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
465 main_filter_packets(&cfile, "", FALSE);
468 /* mark as reference time frame */
470 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
474 frame->flags.ref_time=1;
476 frame->flags.ref_time=0;
478 reftime_packets(&cfile);
482 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
487 if (cfile.current_frame) {
488 /* XXX hum, should better have a "cfile->current_row" here ... */
489 set_frame_reftime(!cfile.current_frame->flags.ref_time,
491 packet_list_find_row_from_data(cfile.current_frame));
494 case REFTIME_FIND_NEXT:
495 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
497 case REFTIME_FIND_PREV:
498 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
503 #if GTK_MAJOR_VERSION < 2
505 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
506 gpointer user_data _U_)
509 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
513 gchar *help_str = NULL;
514 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
516 gboolean has_blurb = FALSE;
517 guint length = 0, byte_len;
518 GtkWidget *byte_view;
519 const guint8 *byte_data;
520 #if GTK_MAJOR_VERSION >= 2
525 #if GTK_MAJOR_VERSION >= 2
526 /* if nothing is selected */
527 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
530 * Which byte view is displaying the current protocol tree
533 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
534 if (byte_view == NULL)
537 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
538 if (byte_data == NULL)
541 unselect_field(&cfile);
542 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
543 cfile.current_frame, NULL, byte_len);
546 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
549 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
553 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
555 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
556 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
557 g_assert(byte_data != NULL);
559 cfile.finfo_selected = finfo;
560 set_menus_for_selected_tree_row(&cfile);
563 if (finfo->hfinfo->blurb != NULL &&
564 finfo->hfinfo->blurb[0] != '\0') {
566 length = strlen(finfo->hfinfo->blurb);
568 length = strlen(finfo->hfinfo->name);
570 if (finfo->length == 0) {
572 } else if (finfo->length == 1) {
573 strcpy (len_str, ", 1 byte");
575 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
577 statusbar_pop_field_msg(); /* get rid of current help msg */
579 help_str = g_strdup_printf("%s (%s)%s",
580 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
581 finfo->hfinfo->abbrev, len_str);
582 statusbar_push_field_msg(help_str);
586 * Don't show anything if the field name is zero-length;
587 * the pseudo-field for "proto_tree_add_text()" is such
588 * a field, and we don't want "Text (text)" showing up
589 * on the status line if you've selected such a field.
591 * XXX - there are zero-length fields for which we *do*
592 * want to show the field name.
594 * XXX - perhaps the name and abbrev field should be null
595 * pointers rather than null strings for that pseudo-field,
596 * but we'd have to add checks for null pointers in some
597 * places if we did that.
599 * Or perhaps protocol tree items added with
600 * "proto_tree_add_text()" should have -1 as the field index,
601 * with no pseudo-field being used, but that might also
602 * require special checks for -1 to be added.
604 statusbar_push_field_msg("");
608 #if GTK_MAJOR_VERSION < 2
609 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
612 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
617 #if GTK_MAJOR_VERSION < 2
619 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
620 gpointer user_data _U_)
622 GtkWidget *byte_view;
627 * Which byte view is displaying the current protocol tree
630 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
631 if (byte_view == NULL)
634 data = get_byte_view_data_and_length(byte_view, &len);
638 unselect_field(&cfile);
639 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
644 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
646 collapse_all_tree(cfile.edt->tree, tree_view);
649 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
651 expand_all_tree(cfile.edt->tree, tree_view);
654 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
655 #if GTK_MAJOR_VERSION < 2
661 #if GTK_MAJOR_VERSION < 2
662 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
664 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
666 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
668 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
669 gtk_tree_path_free(path);
673 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
674 if (cfile.edt->tree) {
675 guint32 tmp = g_resolv_flags;
676 g_resolv_flags = RESOLV_ALL;
677 proto_tree_draw(cfile.edt->tree, tree_view);
678 g_resolv_flags = tmp;
683 * Push a message referring to file access onto the statusbar.
686 statusbar_push_file_msg(gchar *msg)
688 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
692 * Pop a message referring to file access off the statusbar.
695 statusbar_pop_file_msg(void)
697 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
701 * XXX - do we need multiple statusbar contexts?
705 * Push a message referring to the currently-selected field onto the statusbar.
708 statusbar_push_field_msg(gchar *msg)
710 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
714 * Pop a message referring to the currently-selected field off the statusbar.
717 statusbar_pop_field_msg(void)
719 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
723 * update the packets statusbar to the current values
725 void packets_bar_update(void)
729 /* remove old status */
732 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
735 /* do we have any packets? */
737 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
738 cfile.count, cfile.displayed_count, cfile.marked_count);
740 packets_str = g_strdup(" No Packets");
742 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
753 /* get the current geometry, before writing it to disk */
754 main_save_window_geometry(top_level);
756 /* write user's recent file to disk
757 * It is no problem to write this file, even if we do not quit */
758 write_recent(&rec_path);
760 /* XXX - should we check whether the capture file is an
761 unsaved temporary file for a live capture and, if so,
762 pop up a "do you want to exit without saving the capture
763 file?" dialog, and then just return, leaving said dialog
764 box to forcibly quit if the user clicks "OK"?
766 If so, note that this should be done in a subroutine that
767 returns TRUE if we do so, and FALSE otherwise, and if it
768 returns TRUE we should return TRUE without nuking anything.
770 Note that, if we do that, we might also want to check if
771 an "Update list of packets in real time" capture is in
772 progress and, if so, ask whether they want to terminate
773 the capture and discard it, and return TRUE, before nuking
774 any child capture, if they say they don't want to do so. */
777 /* Nuke any child capture in progress. */
778 kill_capture_child();
781 /* Are we in the middle of reading a capture? */
782 if (cfile.state == FILE_READ_IN_PROGRESS) {
783 /* Yes, so we can't just close the file and quit, as
784 that may yank the rug out from under the read in
785 progress; instead, just set the state to
786 "FILE_READ_ABORTED" and return - the code doing the read
787 will check for that and, if it sees that, will clean
789 cfile.state = FILE_READ_ABORTED;
791 /* Say that the window should *not* be deleted;
792 that'll be done by the code that cleans up. */
795 /* Close any capture file we have open; on some OSes, you
796 can't unlink a temporary capture file if you have it
798 "cf_close()" will unlink it after closing it if
799 it's a temporary file.
801 We do this here, rather than after the main loop returns,
802 as, after the main loop returns, the main window may have
803 been destroyed (if this is called due to a "destroy"
804 even on the main window rather than due to the user
805 selecting a menu item), and there may be a crash
806 or other problem when "cf_close()" tries to
807 clean up stuff in the main window.
809 XXX - is there a better place to put this?
810 Or should we have a routine that *just* closes the
811 capture file, and doesn't do anything with the UI,
812 which we'd call here, and another routine that
813 calls that routine and also cleans up the UI, which
814 we'd call elsewhere? */
817 /* Exit by leaving the main loop, so that any quit functions
818 we registered get called. */
821 /* Say that the window should be deleted. */
827 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
831 if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
832 /* user didn't saved his current file, ask him */
833 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
834 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
835 "If you quit the program without saving, your capture data will be discarded.");
836 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
839 /* unchanged file, just exit */
840 /* "main_do_quit()" indicates whether the main window should be deleted. */
841 return main_do_quit();
848 main_load_window_geometry(GtkWidget *widget)
850 window_geometry_t geom;
852 geom.set_pos = prefs.gui_geometry_save_position;
853 geom.x = recent.gui_geometry_main_x;
854 geom.y = recent.gui_geometry_main_y;
855 geom.set_size = prefs.gui_geometry_save_size;
856 geom.width = recent.gui_geometry_main_width;
857 geom.height = recent.gui_geometry_main_height;
858 geom.set_maximized = prefs.gui_geometry_save_maximized;
859 geom.maximized = recent.gui_geometry_main_maximized;
861 window_set_geometry(widget, &geom);
863 #if GTK_MAJOR_VERSION >= 2
864 /* XXX - rename recent settings? */
865 if (recent.gui_geometry_main_upper_pane)
866 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
867 if (recent.gui_geometry_main_lower_pane)
868 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
869 if (recent.gui_geometry_status_pane)
870 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
876 main_save_window_geometry(GtkWidget *widget)
878 window_geometry_t geom;
880 window_get_geometry(widget, &geom);
882 if (prefs.gui_geometry_save_position) {
883 recent.gui_geometry_main_x = geom.x;
884 recent.gui_geometry_main_y = geom.y;
887 if (prefs.gui_geometry_save_size) {
888 recent.gui_geometry_main_width = geom.width,
889 recent.gui_geometry_main_height = geom.height;
892 #if GTK_MAJOR_VERSION >= 2
893 if(prefs.gui_geometry_save_maximized) {
894 recent.gui_geometry_main_maximized = geom.maximized;
897 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
898 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
899 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
903 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
907 /* save file first */
908 file_save_as_cmd(after_save_exit, NULL);
913 case(ESD_BTN_CANCEL):
916 g_assert_not_reached();
921 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
925 if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
926 /* user didn't saved his current file, ask him */
927 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
928 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
929 "If you quit the program without saving, your capture data will be discarded.");
930 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
932 /* unchanged file, just exit */
938 print_usage(gboolean print_ver) {
944 fprintf(output, "This is GNU " PACKAGE " " VERSION
949 comp_info_str->str, runtime_info_str->str);
954 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n",
956 fprintf(output, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
957 fprintf(output, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
958 fprintf(output, "\t[ -i <interface> ] [ -m <medium font> ] [ -N <resolving> ]\n");
959 fprintf(output, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
960 fprintf(output, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
961 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
962 fprintf(output, "\t[ -w <savefile> ] [ -y <link type> ] [ -z <statistics string> ]\n");
963 fprintf(output, "\t[ <infile> ]\n");
965 fprintf(output, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n",
967 fprintf(output, "\t[ -N <resolving> ] [ -o <preference setting> ...\n");
968 fprintf(output, "\t[ -P <packet list height> ] [ -r <infile> ] [ -R <read filter> ]\n");
969 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
970 fprintf(output, "\t[ -z <statistics string> ] [ <infile> ]\n");
981 printf(PACKAGE " " VERSION
986 comp_info_str->str, runtime_info_str->str);
990 get_natural_int(const char *string, const char *name)
995 number = strtol(string, &p, 10);
996 if (p == string || *p != '\0') {
997 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1002 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1006 if (number > INT_MAX) {
1007 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1008 name, string, INT_MAX);
1015 get_positive_int(const char *string, const char *name)
1019 number = get_natural_int(string, name);
1022 fprintf(stderr, "ethereal: The specified %s is zero\n",
1032 * Given a string of the form "<autostop criterion>:<value>", as might appear
1033 * as an argument to a "-a" option, parse it and set the criterion in
1034 * question. Return an indication of whether it succeeded or failed
1038 set_autostop_criterion(const char *autostoparg)
1042 colonp = strchr(autostoparg, ':');
1050 * Skip over any white space (there probably won't be any, but
1051 * as we allow it in the preferences file, we might as well
1054 while (isspace((guchar)*p))
1058 * Put the colon back, so if our caller uses, in an
1059 * error message, the string they passed us, the message
1065 if (strcmp(autostoparg,"duration") == 0) {
1066 capture_opts.has_autostop_duration = TRUE;
1067 capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1068 } else if (strcmp(autostoparg,"filesize") == 0) {
1069 capture_opts.has_autostop_filesize = TRUE;
1070 capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1074 *colonp = ':'; /* put the colon back */
1079 * Given a string of the form "<ring buffer file>:<duration>", as might appear
1080 * as an argument to a "-b" option, parse it and set the arguments in
1081 * question. Return an indication of whether it succeeded or failed
1085 get_ring_arguments(const char *arg)
1087 gchar *p = NULL, *colonp;
1089 colonp = strchr(arg, ':');
1091 if (colonp != NULL) {
1096 capture_opts.ring_num_files =
1097 get_natural_int(arg, "number of ring buffer files");
1103 * Skip over any white space (there probably won't be any, but
1104 * as we allow it in the preferences file, we might as well
1107 while (isspace((guchar)*p))
1111 * Put the colon back, so if our caller uses, in an
1112 * error message, the string they passed us, the message
1119 capture_opts.has_file_duration = TRUE;
1120 capture_opts.file_duration = get_positive_int(p,
1121 "ring buffer duration");
1123 *colonp = ':'; /* put the colon back */
1128 #if defined WIN32 || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1130 Once every 3 seconds we get a callback here which we use to update
1131 the tap extensions. Since Gtk1 is single threaded we dont have to
1132 worry about any locking or critical regions.
1135 update_cb(gpointer data _U_)
1137 draw_tap_listeners(FALSE);
1142 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1143 use threads all updte_thread_mutex can be dropped and protect/unprotect
1144 would just be empty functions.
1146 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1147 gtk1-ethereal and it will just work.
1149 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1151 update_thread(gpointer data _U_)
1155 g_get_current_time(&tv1);
1156 g_static_mutex_lock(&update_thread_mutex);
1157 gdk_threads_enter();
1158 draw_tap_listeners(FALSE);
1159 gdk_threads_leave();
1160 g_static_mutex_unlock(&update_thread_mutex);
1162 g_get_current_time(&tv2);
1163 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1164 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1165 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1166 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1173 protect_thread_critical_region(void)
1175 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1176 g_static_mutex_lock(&update_thread_mutex);
1180 unprotect_thread_critical_region(void)
1182 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1183 g_static_mutex_unlock(&update_thread_mutex);
1187 /* structure to keep track of what tap listeners have been registered.
1189 typedef struct _ethereal_tap_list {
1190 struct _ethereal_tap_list *next;
1192 void (*func)(char *arg);
1193 } ethereal_tap_list;
1194 static ethereal_tap_list *tap_list=NULL;
1197 register_ethereal_tap(char *cmd, void (*func)(char *arg))
1199 ethereal_tap_list *newtl;
1201 newtl=malloc(sizeof(ethereal_tap_list));
1202 newtl->next=tap_list;
1210 enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL };
1213 dnd_open_file_cmd(gpointer cf_name)
1218 /* open and read the capture file (this will close an existing file) */
1219 if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
1221 add_menu_recent_capture_file(cf_name);
1223 /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */
1230 dnd_open_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1234 /* save file first */
1235 file_save_as_cmd(after_save_open_dnd_file, data);
1239 dnd_open_file_cmd(data);
1241 case(ESD_BTN_CANCEL):
1245 g_assert_not_reached();
1250 dnd_uri2filename(gchar *cf_name)
1259 * Remove URI header.
1260 * On win32 (at least WinXP), this string looks like (UNC or local filename):
1261 * file:////servername/sharename/dir1/dir2/capture-file.cap
1263 * file:///d:/dir1/dir2/capture-file.cap
1264 * we have to remove the prefix to get a valid filename.
1266 * On UNIX (at least KDE 3.0 Konqueror), this string looks like:
1267 * file:/dir1/dir2/capture-file.cap
1268 * we have to remove the file: to get a valid filename.
1270 if (strncmp("file:////", cf_name, 9) == 0) {
1271 /* now becoming: //servername/sharename/dir1/dir2/capture-file.cap */
1273 } else if (strncmp("file:///", cf_name, 8) == 0) {
1274 /* now becoming: d:/dir1/dir2/capture-file.cap */
1276 } else if (strncmp("file:", cf_name, 5) == 0) {
1277 /* now becoming: /dir1/dir2/capture-file.cap */
1282 * unescape the escaped URI characters (spaces, ...)
1284 * we have to replace escaped chars to their equivalents,
1285 * e.g. %20 (always a two digit hexstring) -> ' '
1286 * the percent character '%' is escaped be a double one "%%"
1288 * we do this conversation "in place" as the result is always
1289 * equal or smaller in size.
1297 /* this is an escaped '%' char (was: "%%") */
1302 /* convert escaped hexnumber to unscaped character */
1306 ret = sscanf(esc, "%x", &i);
1312 /* somethings wrong, just jump over that char
1313 * this will result in a wrong string, but we might get
1314 * user feedback and can fix it later ;-) */
1330 dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_,
1331 GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_)
1333 gchar *cf_name, *cf_name_ori;
1336 if (info == DND_TARGET_URL) {
1337 /* DND_TARGET_URL on Win32:
1338 * The selection_data->data is a single string, containing one or more URI's,
1339 * seperated by CR/NL chars. The length of the whole field can be found
1340 * in the selection_data->length field. As we can't handle more than one
1341 * capture file at a time, we only try to load the first one. */
1343 /* XXX: how does this string look like on other platforms? */
1345 /* XXX: if more than one file is in the string, we might want to have
1346 * a dialog box asking to merge these files together? */
1348 /* the name might not be zero terminated -> make a copy of it */
1349 cf_name_ori = g_strndup((gchar *)selection_data->data, selection_data->length);
1350 cf_name = cf_name_ori;
1352 /* replace trailing CR NL simply with zeroes */
1353 g_strdelimit(cf_name, "\r\n", '\0');
1355 /* convert the URI to a local filename */
1356 cf_name = dnd_uri2filename(cf_name);
1358 /* we need a clean name for later call to g_free() */
1359 cf_name = strdup(cf_name);
1360 g_free(cf_name_ori);
1362 /* ask the user to save it's current capture file first */
1363 if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
1364 /* user didn't saved his current file, ask him */
1365 dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
1366 ESD_BTNS_YES_NO_CANCEL,
1367 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1368 "If you open a new capture file without saving, your current capture data will be discarded.");
1369 simple_dialog_set_cb(dialog, dnd_open_file_answered_cb, cf_name);
1371 /* unchanged file */
1372 dnd_open_file_cmd(cf_name);
1378 dnd_init(GtkWidget *w)
1380 /* we are only interested in the URI list containing filenames */
1381 static GtkTargetEntry target_entry[] = {
1382 /*{"STRING", 0, DND_TARGET_STRING},*/
1383 /*{"text/plain", 0, DND_TARGET_STRING},*/
1384 {"text/uri-list", 0, DND_TARGET_URL}
1387 /* set this window as a dnd destination */
1389 w, GTK_DEST_DEFAULT_ALL, target_entry,
1390 sizeof(target_entry) / sizeof(GtkTargetEntry),
1391 (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) );
1393 /* get notified, if some dnd coming in */
1394 gtk_signal_connect(GTK_OBJECT(w), "drag_data_received",
1395 GTK_SIGNAL_FUNC(dnd_data_received), NULL);
1399 /* And now our feature presentation... [ fade to music ] */
1401 main(int argc, char *argv[])
1409 extern char *optarg;
1410 gboolean arg_error = FALSE;
1418 char *gpf_path, *pf_path;
1419 char *cf_path, *df_path;
1420 char *gdp_path, *dp_path;
1421 int gpf_open_errno, gpf_read_errno;
1422 int pf_open_errno, pf_read_errno;
1423 int cf_open_errno, df_open_errno;
1424 int gdp_open_errno, gdp_read_errno;
1425 int dp_open_errno, dp_read_errno;
1428 gboolean start_capture = FALSE;
1429 gchar *save_file = NULL;
1432 GList *lt_list, *lt_entry;
1433 data_link_info_t *data_link_info;
1434 gchar err_str[PCAP_ERRBUF_SIZE];
1435 gchar *cant_get_if_list_errstr;
1436 gboolean stats_known;
1437 struct pcap_stat stats;
1439 gboolean capture_option_specified = FALSE;
1441 gint pl_size = 280, tv_size = 95, bv_size = 75;
1442 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1443 dfilter_t *rfcode = NULL;
1444 gboolean rfilter_parse_failed = FALSE;
1447 ethereal_tap_list *tli = NULL;
1448 gchar *tap_opt = NULL;
1450 #define OPTSTRING_INIT "a:b:B:c:f:hi:klLm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:"
1454 #define OPTSTRING_CHILD "W:Z:"
1456 #define OPTSTRING_CHILD "W:"
1459 #define OPTSTRING_CHILD ""
1460 #endif /* HAVE_LIBPCAP */
1462 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1465 ethereal_path = argv[0];
1468 /* Arrange that if we have no console window, and a GLib message logging
1469 routine is called to log a message, we pop up a console window.
1471 We do that by inserting our own handler for all messages logged
1472 to the default domain; that handler pops up a console if necessary,
1473 and then calls the default handler. */
1474 g_log_set_handler(NULL,
1476 G_LOG_LEVEL_CRITICAL|
1477 G_LOG_LEVEL_WARNING|
1478 G_LOG_LEVEL_MESSAGE|
1481 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1482 console_log_handler, NULL);
1486 command_name = get_basename(ethereal_path);
1487 /* Set "capture_child" to indicate whether this is going to be a child
1488 process for a "-S" capture. */
1489 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1491 strcat(optstring, OPTSTRING_CHILD);
1494 /* Register all dissectors; we must do this before checking for the
1495 "-G" flag, as the "-G" flag dumps information registered by the
1496 dissectors, and we must do it before we read the preferences, in
1497 case any dissectors register preferences. */
1498 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1499 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1501 /* Register all tap listeners; we do this before we parse the arguments,
1502 as the "-z" argument can specify a registered tap. */
1503 register_all_tap_listeners();
1505 /* Now register the preferences for any non-dissector modules.
1506 We must do that before we read the preferences as well. */
1507 prefs_register_modules();
1509 /* If invoked with the "-G" flag, we dump out information based on
1510 the argument to the "-G" flag; if no argument is specified,
1511 for backwards compatibility we dump out a glossary of display
1514 We must do this before calling "gtk_init()", because "gtk_init()"
1515 tries to open an X display, and we don't want to have to do any X
1516 stuff just to do a build.
1518 Given that we call "gtk_init()" before doing the regular argument
1519 list processing, so that it can handle X and GTK+ arguments and
1520 remove them from the list at which we look, this means we must do
1521 this before doing the regular argument list processing, as well.
1525 you must give the "-G" flag as the first flag on the command line;
1527 you must give it as "-G", nothing more, nothing less;
1529 the first argument after the "-G" flag, if present, will be used
1530 to specify the information to dump;
1532 arguments after that will not be used. */
1533 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1535 proto_registrar_dump_fields();
1537 if (strcmp(argv[2], "fields") == 0)
1538 proto_registrar_dump_fields();
1539 else if (strcmp(argv[2], "protocols") == 0)
1540 proto_registrar_dump_protocols();
1542 fprintf(stderr, "ethereal: Invalid \"%s\" option for -G flag\n",
1550 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1551 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined G_THREADS_ENABLED && defined USE_THREADS
1554 g_thread_init(NULL);
1556 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1557 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1559 #else /* WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1560 /* this is to keep tap extensions updating once every 3 seconds */
1561 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1562 #endif /* !WIN32 && GTK2 && G_THREADS_ENABLED */
1565 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1569 /* Set the current locale according to the program environment.
1570 * We haven't localized anything, but some GTK widgets are localized
1571 * (the file selection dialogue, for example).
1572 * This also sets the C-language locale to the native environment. */
1575 /* Let GTK get its args */
1576 gtk_init (&argc, &argv);
1578 /* Read the preference files. */
1579 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1580 &pf_open_errno, &pf_read_errno, &pf_path);
1581 if (gpf_path != NULL) {
1582 if (gpf_open_errno != 0) {
1583 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1584 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1585 strerror(gpf_open_errno));
1587 if (gpf_read_errno != 0) {
1588 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1589 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1590 strerror(gpf_read_errno));
1593 if (pf_path != NULL) {
1594 if (pf_open_errno != 0) {
1595 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1596 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1597 strerror(pf_open_errno));
1599 if (pf_read_errno != 0) {
1600 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1601 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1602 strerror(pf_read_errno));
1609 if (prefs->gui_console_open == console_open_always) {
1615 capture_opts.has_snaplen = FALSE;
1616 capture_opts.snaplen = MIN_PACKET_SIZE;
1617 capture_opts.linktype = -1;
1619 capture_opts.buffer_size = 1;
1622 capture_opts.has_autostop_packets = FALSE;
1623 capture_opts.autostop_packets = 1;
1624 capture_opts.has_autostop_duration = FALSE;
1625 capture_opts.autostop_duration = 1;
1626 capture_opts.has_autostop_filesize = FALSE;
1627 capture_opts.autostop_filesize = 1;
1628 capture_opts.has_autostop_files = FALSE;
1629 capture_opts.autostop_files = 1;
1631 capture_opts.multi_files_on = FALSE;
1632 capture_opts.has_ring_num_files = TRUE;
1633 capture_opts.ring_num_files = 2;
1634 capture_opts.has_file_duration = FALSE;
1635 capture_opts.file_duration = 1;
1637 /* If this is a capture child process, it should pay no attention
1638 to the "prefs.capture_prom_mode" setting in the preferences file;
1639 it should do what the parent process tells it to do, and if
1640 the parent process wants it not to run in promiscuous mode, it'll
1641 tell it so with a "-p" flag.
1643 Otherwise, set promiscuous mode from the preferences setting. */
1645 capture_opts.promisc_mode = TRUE;
1647 capture_opts.promisc_mode = prefs->capture_prom_mode;
1649 /* Set "Update list of packets in real time" mode from the preferences
1651 capture_opts.sync_mode = prefs->capture_real_time;
1653 /* And do the same for "Automatic scrolling in live capture" mode. */
1654 auto_scroll_live = prefs->capture_auto_scroll;
1657 /* Set the name resolution code's flags from the preferences. */
1658 g_resolv_flags = prefs->name_resolve;
1660 /* Read the capture filter file. */
1661 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1662 if (cf_path != NULL) {
1663 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1664 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1665 strerror(cf_open_errno));
1669 /* Read the display filter file. */
1670 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1671 if (df_path != NULL) {
1672 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1673 "Could not open your display filter file\n\"%s\": %s.", df_path,
1674 strerror(df_open_errno));
1678 /* Read the disabled protocols file. */
1679 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1680 &dp_path, &dp_open_errno, &dp_read_errno);
1681 if (gdp_path != NULL) {
1682 if (gdp_open_errno != 0) {
1683 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1684 "Could not open global disabled protocols file\n\"%s\": %s.",
1685 gdp_path, strerror(gdp_open_errno));
1687 if (gdp_read_errno != 0) {
1688 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1689 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1690 gdp_path, strerror(gdp_read_errno));
1694 if (dp_path != NULL) {
1695 if (dp_open_errno != 0) {
1696 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1697 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1698 strerror(dp_open_errno));
1700 if (dp_read_errno != 0) {
1701 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1702 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
1703 strerror(dp_read_errno));
1708 init_cap_file(&cfile);
1711 /* Load wpcap if possible. Do this before collecting the run-time version information */
1714 /* Start windows sockets */
1715 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1718 /* Assemble the compile-time version information string */
1719 comp_info_str = g_string_new("Compiled ");
1720 g_string_append(comp_info_str, "with ");
1721 g_string_sprintfa(comp_info_str,
1722 #ifdef GTK_MAJOR_VERSION
1723 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1726 "GTK+ (version unknown)");
1729 g_string_append(comp_info_str, ", ");
1730 get_compiled_version_info(comp_info_str);
1732 /* Assemble the run-time version information string */
1733 runtime_info_str = g_string_new("Running ");
1734 get_runtime_version_info(runtime_info_str);
1736 /* Now get our args */
1737 while ((opt = getopt(argc, argv, optstring)) != -1) {
1739 case 'a': /* autostop criteria */
1741 if (set_autostop_criterion(optarg) == FALSE) {
1742 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1746 capture_option_specified = TRUE;
1750 case 'b': /* Ringbuffer option */
1752 capture_opts.multi_files_on = TRUE;
1753 capture_opts.has_ring_num_files = TRUE;
1754 if (get_ring_arguments(optarg) == FALSE) {
1755 fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
1759 capture_option_specified = TRUE;
1763 case 'B': /* Byte view pane height */
1764 bv_size = get_positive_int(optarg, "byte view pane height");
1766 case 'c': /* Capture xxx packets */
1768 capture_opts.has_autostop_packets = TRUE;
1769 capture_opts.autostop_packets = get_positive_int(optarg, "packet count");
1771 capture_option_specified = TRUE;
1778 g_free(cfile.cfilter);
1779 cfile.cfilter = g_strdup(optarg);
1781 capture_option_specified = TRUE;
1785 case 'h': /* Print help and exit */
1789 case 'i': /* Use interface xxx */
1791 cfile.iface = g_strdup(optarg);
1793 capture_option_specified = TRUE;
1797 case 'k': /* Start capture immediately */
1799 start_capture = TRUE;
1801 capture_option_specified = TRUE;
1805 case 'l': /* Automatic scrolling in live capture mode */
1807 auto_scroll_live = TRUE;
1809 capture_option_specified = TRUE;
1813 case 'L': /* Print list of link-layer types and exit */
1815 list_link_layer_types = TRUE;
1817 capture_option_specified = TRUE;
1821 case 'm': /* Fixed-width font for the display */
1822 if (prefs->PREFS_GUI_FONT_NAME != NULL)
1823 g_free(prefs->PREFS_GUI_FONT_NAME);
1824 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
1826 case 'n': /* No name resolution */
1827 g_resolv_flags = RESOLV_NONE;
1829 case 'N': /* Select what types of addresses/port #s to resolve */
1830 if (g_resolv_flags == RESOLV_ALL)
1831 g_resolv_flags = RESOLV_NONE;
1832 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1833 if (badopt != '\0') {
1834 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1839 case 'o': /* Override preference from command line */
1840 switch (prefs_set_pref(optarg)) {
1842 case PREFS_SET_SYNTAX_ERR:
1843 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1847 case PREFS_SET_NO_SUCH_PREF:
1848 case PREFS_SET_OBSOLETE:
1849 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1855 case 'p': /* Don't capture in promiscuous mode */
1857 capture_opts.promisc_mode = FALSE;
1859 capture_option_specified = TRUE;
1863 case 'P': /* Packet list pane height */
1864 pl_size = get_positive_int(optarg, "packet list pane height");
1866 case 'Q': /* Quit after capture (just capture to file) */
1868 quit_after_cap = TRUE;
1869 start_capture = TRUE; /*** -Q implies -k !! ***/
1871 capture_option_specified = TRUE;
1875 case 'r': /* Read capture file xxx */
1876 /* We may set "last_open_dir" to "cf_name", and if we change
1877 "last_open_dir" later, we free the old value, so we have to
1878 set "cf_name" to something that's been allocated. */
1879 cf_name = g_strdup(optarg);
1881 case 'R': /* Read file filter */
1884 case 's': /* Set the snapshot (capture) length */
1886 capture_opts.has_snaplen = TRUE;
1887 capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
1889 capture_option_specified = TRUE;
1893 case 'S': /* "Sync" mode: used for following file ala tail -f */
1895 capture_opts.sync_mode = TRUE;
1897 capture_option_specified = TRUE;
1901 case 't': /* Time stamp type */
1902 if (strcmp(optarg, "r") == 0)
1903 set_timestamp_setting(TS_RELATIVE);
1904 else if (strcmp(optarg, "a") == 0)
1905 set_timestamp_setting(TS_ABSOLUTE);
1906 else if (strcmp(optarg, "ad") == 0)
1907 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
1908 else if (strcmp(optarg, "d") == 0)
1909 set_timestamp_setting(TS_DELTA);
1911 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1913 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1914 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1918 case 'T': /* Tree view pane height */
1919 tv_size = get_positive_int(optarg, "tree view pane height");
1921 case 'v': /* Show version and exit */
1928 case 'w': /* Write to capture file xxx */
1930 save_file = g_strdup(optarg);
1932 capture_option_specified = TRUE;
1936 case 'y': /* Set the pcap data link type */
1938 #ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
1939 capture_opts.linktype = pcap_datalink_name_to_val(optarg);
1940 if (capture_opts.linktype == -1) {
1941 fprintf(stderr, "ethereal: The specified data link type \"%s\" is not valid\n",
1945 #else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
1946 /* XXX - just treat it as a number */
1947 capture_opts.linktype = get_natural_int(optarg, "data link type");
1948 #endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
1949 #else /* HAVE_LIBPCAP */
1950 capture_option_specified = TRUE;
1952 #endif /* HAVE_LIBPCAP */
1955 /* This is a hidden option supporting Sync mode, so we don't set
1956 * the error flags for the user in the non-libpcap case.
1958 case 'W': /* Write to capture file FD xxx */
1959 cfile.save_file_fd = atoi(optarg);
1963 for(tli=tap_list;tli;tli=tli->next){
1964 if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
1965 tap_opt = g_strdup(optarg);
1970 fprintf(stderr,"ethereal: invalid -z argument.\n");
1971 fprintf(stderr," -z argument must be one of :\n");
1972 for(tli=tap_list;tli;tli=tli->next){
1973 fprintf(stderr," %s\n",tli->cmd);
1981 /* Hidden option supporting Sync mode */
1982 case 'Z': /* Write to pipe FD XXX */
1983 /* associate stdout with pipe */
1985 if (dup2(i, 1) < 0) {
1986 fprintf(stderr, "Unable to dup pipe handle\n");
1990 #endif /* HAVE_LIBPCAP */
1994 case '?': /* Bad flag - print usage message */
2002 if (cf_name != NULL) {
2004 * Input file name specified with "-r" *and* specified as a regular
2005 * command-line argument.
2010 * Input file name not specified with "-r", and a command-line argument
2011 * was specified; treat it as the input file name.
2013 * Yes, this is different from tethereal, where non-flag command-line
2014 * arguments are a filter, but this works better on GUI desktops
2015 * where a command can be specified to be run to open a particular
2016 * file - yes, you could have "-r" as the last part of the command,
2017 * but that's a bit ugly.
2019 cf_name = g_strdup(argv[0]);
2027 * Extra command line arguments were specified; complain.
2029 fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2033 #ifndef HAVE_LIBPCAP
2034 if (capture_option_specified)
2035 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2043 if (start_capture && list_link_layer_types) {
2044 /* Specifying *both* is bogus. */
2045 fprintf(stderr, "ethereal: You cannot specify both -L and a live capture.\n");
2049 if (list_link_layer_types) {
2050 /* We're supposed to list the link-layer types for an interface;
2051 did the user also specify a capture file to be read? */
2053 /* Yes - that's bogus. */
2054 fprintf(stderr, "ethereal: You cannot specify -L and a capture file to be read.\n");
2057 /* No - did they specify a ring buffer option? */
2058 if (capture_opts.multi_files_on) {
2059 fprintf(stderr, "ethereal: Ring buffer requested, but a capture is not being done.\n");
2063 /* We're supposed to do a live capture; did the user also specify
2064 a capture file to be read? */
2065 if (start_capture && cf_name) {
2066 /* Yes - that's bogus. */
2067 fprintf(stderr, "ethereal: You cannot specify both a live capture and a capture file to be read.\n");
2071 /* No - was the ring buffer option specified and, if so, does it make
2073 if (capture_opts.multi_files_on) {
2074 /* Ring buffer works only under certain conditions:
2075 a) ring buffer does not work with temporary files;
2076 b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
2077 sync_mode takes precedence;
2078 c) it makes no sense to enable the ring buffer if the maximum
2079 file size is set to "infinite". */
2080 if (save_file == NULL) {
2081 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2082 capture_opts.multi_files_on = FALSE;
2084 if (capture_opts.sync_mode) {
2085 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2086 capture_opts.multi_files_on = FALSE;
2088 if (!capture_opts.has_autostop_filesize) {
2089 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
2090 capture_opts.multi_files_on = FALSE;
2095 if (start_capture || list_link_layer_types) {
2096 /* Did the user specify an interface to use? */
2097 if (cfile.iface == NULL) {
2098 /* No - is a default specified in the preferences file? */
2099 if (prefs->capture_device != NULL) {
2101 cfile.iface = g_strdup(prefs->capture_device);
2103 /* No - pick the first one from the list of interfaces. */
2104 if_list = get_interface_list(&err, err_str);
2105 if (if_list == NULL) {
2108 case CANT_GET_INTERFACE_LIST:
2109 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2110 fprintf(stderr, "%s\n", cant_get_if_list_errstr);
2111 g_free(cant_get_if_list_errstr);
2114 case NO_INTERFACES_FOUND:
2115 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2120 if_info = if_list->data; /* first interface */
2121 cfile.iface = g_strdup(if_info->name);
2122 free_interface_list(if_list);
2127 if (capture_child) {
2128 if (cfile.save_file_fd == -1) {
2129 /* XXX - send this to the standard output as something our parent
2130 should put in an error message box? */
2131 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2136 if (list_link_layer_types) {
2137 /* Get the list of link-layer types for the capture device. */
2138 lt_list = get_pcap_linktype_list(cfile.iface, err_str);
2139 if (lt_list == NULL) {
2140 if (err_str[0] != '\0') {
2141 fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2142 "Please check to make sure you have sufficient permissions, and that\n"
2143 "you have the proper interface or pipe specified.\n", err_str);
2145 fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2148 fprintf(stderr, "Data link types (use option -y to set):\n");
2149 for (lt_entry = lt_list; lt_entry != NULL;
2150 lt_entry = g_list_next(lt_entry)) {
2151 data_link_info = lt_entry->data;
2152 fprintf(stderr, " %s", data_link_info->name);
2153 if (data_link_info->description != NULL)
2154 fprintf(stderr, " (%s)", data_link_info->description);
2156 fprintf(stderr, " (not supported)");
2159 free_pcap_linktype_list(lt_list);
2165 /* Notify all registered modules that have had any of their preferences
2166 changed either from one of the preferences file or from the command
2167 line that their preferences have changed. */
2170 /* disabled protocols as per configuration file */
2171 if (gdp_path == NULL && dp_path == NULL) {
2172 set_disabled_protos_list();
2175 /* Build the column format array */
2176 col_setup(&cfile.cinfo, prefs->num_cols);
2177 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2178 cfile.cinfo.col_fmt[i] = get_column_format(i);
2179 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2180 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2182 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2183 cfile.cinfo.col_data[i] = NULL;
2184 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2185 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2187 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2188 cfile.cinfo.col_fence[i] = 0;
2189 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2190 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2193 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2196 for (j = 0; j < NUM_COL_FMTS; j++) {
2197 if (!cfile.cinfo.fmt_matx[i][j])
2200 if (cfile.cinfo.col_first[j] == -1)
2201 cfile.cinfo.col_first[j] = i;
2202 cfile.cinfo.col_last[j] = i;
2207 if (capture_opts.has_snaplen) {
2208 if (capture_opts.snaplen < 1)
2209 capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
2210 else if (capture_opts.snaplen < MIN_PACKET_SIZE)
2211 capture_opts.snaplen = MIN_PACKET_SIZE;
2214 /* Check the value range of the ringbuffer_num_files parameter */
2215 if (capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2216 capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2217 #if RINGBUFFER_MIN_NUM_FILES > 0
2218 else if (capture_opts.num_files < RINGBUFFER_MIN_NUM_FILES)
2219 capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2223 /* read in rc file from global and personal configuration paths. */
2224 /* XXX - is this a good idea? */
2225 gtk_rc_parse(RC_FILE);
2226 rc_file = get_persconffile_path(RC_FILE, FALSE);
2227 gtk_rc_parse(rc_file);
2232 /* Is this a "child" ethereal, which is only supposed to pop up a
2233 capture box to let us stop the capture, and run a capture
2234 to a file that our parent will read? */
2235 if (!capture_child) {
2237 /* No. Pop up the main window, and read in a capture file if
2239 create_main_window(pl_size, tv_size, bv_size, prefs);
2241 /* Read the recent file, as we have the gui now ready for it. */
2242 read_recent(&rf_path, &rf_open_errno);
2244 /* rearrange all the widgets as we now have the recent settings for this */
2245 main_widgets_rearrange();
2247 /* Fill in column titles. This must be done after the top level window
2250 XXX - is that still true, with fixed-width columns? */
2251 packet_list_set_column_titles();
2253 menu_recent_read_finished();
2255 switch (user_font_apply()) {
2258 case FA_FONT_NOT_RESIZEABLE:
2259 /* "user_font_apply()" popped up an alert box. */
2260 /* turn off zooming - font can't be resized */
2261 case FA_FONT_NOT_AVAILABLE:
2262 /* XXX - did we successfully load the un-zoomed version earlier?
2263 If so, this *probably* means the font is available, but not at
2264 this particular zoom level, but perhaps some other failure
2265 occurred; I'm not sure you can determine which is the case,
2267 /* turn off zooming - zoom level is unavailable */
2269 /* in any other case than FA_SUCCESS, turn off zooming */
2270 recent.gui_zoom_level = 0;
2271 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2274 dnd_init(top_level);
2279 /* the window can be sized only, if it's not already shown, so do it now! */
2280 main_load_window_geometry(top_level);
2282 /*** we have finished all init things, show the main window ***/
2283 gtk_widget_show(top_level);
2285 /* the window can be maximized only, if it's visible, so do it after show! */
2286 main_load_window_geometry(top_level);
2288 /* process all pending GUI events before continue */
2289 while (gtk_events_pending()) gtk_main_iteration();
2291 /* Pop up any queued-up alert boxes. */
2292 display_queued_messages();
2294 /* If we were given the name of a capture file, read it in now;
2295 we defer it until now, so that, if we can't open it, and pop
2296 up an alert box, the alert box is more likely to come up on
2297 top of the main window - but before the preference-file-error
2298 alert box, so, if we get one of those, it's more likely to come
2301 if (rfilter != NULL) {
2302 if (!dfilter_compile(rfilter, &rfcode)) {
2303 bad_dfilter_alert_box(rfilter);
2304 rfilter_parse_failed = TRUE;
2307 if (!rfilter_parse_failed) {
2308 if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
2309 /* "cf_open()" succeeded, so it closed the previous
2310 capture file, and thus destroyed any previous read filter
2311 attached to "cf". */
2312 cfile.rfcode = rfcode;
2314 /* Open tap windows; we do so after creating the main window,
2315 to avoid GTK warnings, and after successfully opening the
2316 capture file, so we know we have something to tap. */
2317 if (tap_opt && tli) {
2318 (*tli->func)(tap_opt);
2322 /* Read the capture file. */
2323 switch (cf_read(&cfile)) {
2327 /* Just because we got an error, that doesn't mean we were unable
2328 to read any of the file; we handle what we could get from the
2337 /* Save the name of the containing directory specified in the
2338 path name, if any; we can write over cf_name, which is a
2339 good thing, given that "get_dirname()" does write over its
2341 s = get_dirname(cf_name);
2342 /* we might already set this from the recent file, don't overwrite this */
2343 if(get_last_open_dir() == NULL)
2344 set_last_open_dir(s);
2349 dfilter_free(rfcode);
2350 cfile.rfcode = NULL;
2355 if (start_capture) {
2356 /* "-k" was specified; start a capture. */
2357 if (do_capture(save_file)) {
2358 /* The capture started. Open tap windows; we do so after creating
2359 the main window, to avoid GTK warnings, and after starting the
2360 capture, so we know we have something to tap. */
2361 if (tap_opt && tli) {
2362 (*tli->func)(tap_opt);
2366 if (save_file != NULL) {
2367 /* Save the directory name for future file dialogs. */
2368 s = get_dirname(save_file); /* Overwrites save_file */
2369 set_last_open_dir(s);
2375 set_menus_for_capture_in_progress(FALSE);
2378 /* This is the child process for a sync mode or fork mode capture,
2379 so just do the low-level work of a capture - don't create
2380 a temporary file and fork off *another* child process (so don't
2381 call "do_capture()"). */
2383 /* Pop up any queued-up alert boxes. */
2384 display_queued_messages();
2386 /* XXX - hand these stats to the parent process */
2387 capture(&stats_known, &stats);
2389 /* The capture is done; there's nothing more for us to do. */
2392 if (!start_capture && (cfile.cfilter == NULL || strlen(cfile.cfilter) == 0)) {
2393 if (cfile.cfilter) {
2394 g_free(cfile.cfilter);
2396 cfile.cfilter = g_strdup(get_conn_cfilter());
2398 #else /* HAVE_LIBPCAP */
2399 set_menus_for_capture_in_progress(FALSE);
2400 #endif /* HAVE_LIBPCAP */
2408 /* Shutdown windows sockets */
2411 /* For some unknown reason, the "atexit()" call in "create_console()"
2412 doesn't arrange that "destroy_console()" be called when we exit,
2413 so we call it here if a console was created. */
2419 /* This isn't reached, but we need it to keep GCC from complaining
2420 that "main()" returns without returning a value - it knows that
2421 "exit()" never returns, but it doesn't know that "gtk_exit()"
2422 doesn't, as GTK+ doesn't declare it with the attribute
2424 return 0; /* not reached */
2429 /* We build this as a GUI subsystem application on Win32, so
2430 "WinMain()", not "main()", gets called.
2432 Hack shamelessly stolen from the Win32 port of the GIMP. */
2434 #define _stdcall __attribute__((stdcall))
2438 WinMain (struct HINSTANCE__ *hInstance,
2439 struct HINSTANCE__ *hPrevInstance,
2443 has_console = FALSE;
2444 return main (__argc, __argv);
2448 * If this application has no console window to which its standard output
2449 * would go, create one.
2452 create_console(void)
2454 if (!has_console && prefs.gui_console_open != console_open_never) {
2455 /* We have no console to which to print the version string, so
2456 create one and make it the standard input, output, and error. */
2457 if (!AllocConsole())
2458 return; /* couldn't create console */
2459 freopen("CONIN$", "r", stdin);
2460 freopen("CONOUT$", "w", stdout);
2461 freopen("CONOUT$", "w", stderr);
2463 /* Well, we have a console now. */
2466 /* Now register "destroy_console()" as a routine to be called just
2467 before the application exits, so that we can destroy the console
2468 after the user has typed a key (so that the console doesn't just
2469 disappear out from under them, giving the user no chance to see
2470 the message(s) we put in there). */
2471 atexit(destroy_console);
2476 destroy_console(void)
2479 printf("\n\nPress any key to exit\n");
2485 /* This routine should not be necessary, at least as I read the GLib
2486 source code, as it looks as if GLib is, on Win32, *supposed* to
2487 create a console window into which to display its output.
2489 That doesn't happen, however. I suspect there's something completely
2490 broken about that code in GLib-for-Win32, and that it may be related
2491 to the breakage that forces us to just call "printf()" on the message
2492 rather than passing the message on to "g_log_default_handler()"
2493 (which is the routine that does the aforementioned non-functional
2494 console window creation). */
2496 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2497 const char *message, gpointer user_data)
2501 /* For some unknown reason, the above doesn't appear to actually cause
2502 anything to be sent to the standard output, so we'll just splat the
2503 message out directly, just to make sure it gets out. */
2504 printf("%s\n", message);
2506 g_log_default_handler(log_domain, log_level, message, user_data);
2511 GtkWidget *info_bar_new(void)
2513 /* tip: tooltips don't work on statusbars! */
2514 info_bar = gtk_statusbar_new();
2515 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2516 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2517 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2518 #if GTK_MAJOR_VERSION >= 2
2519 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2521 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2526 GtkWidget *packets_bar_new(void)
2528 /* tip: tooltips don't work on statusbars! */
2529 packets_bar = gtk_statusbar_new();
2530 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2531 packets_bar_update();
2538 * Helper for main_widgets_rearrange()
2540 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2541 gtk_container_remove(GTK_CONTAINER(data), widget);
2544 GtkWidget *main_widget_layout(gint layout_content)
2546 switch(layout_content) {
2547 case(layout_pane_content_none):
2550 case(layout_pane_content_plist):
2553 case(layout_pane_content_pdetails):
2556 case(layout_pane_content_pbytes):
2560 g_assert_not_reached();
2567 * Rearrange the main window widgets
2569 void main_widgets_rearrange(void) {
2570 GtkWidget *pane_content[3];
2572 /* be a bit faster */
2573 gtk_widget_hide(main_vbox);
2575 /* be sure, we don't loose a widget while rearranging */
2576 gtk_widget_ref(menubar);
2577 gtk_widget_ref(main_tb);
2578 gtk_widget_ref(filter_tb);
2579 gtk_widget_ref(pkt_scrollw);
2580 gtk_widget_ref(tv_scrollw);
2581 gtk_widget_ref(byte_nb_ptr);
2582 gtk_widget_ref(stat_hbox);
2583 gtk_widget_ref(info_bar);
2584 gtk_widget_ref(packets_bar);
2585 gtk_widget_ref(status_pane);
2586 gtk_widget_ref(none_lb);
2587 gtk_widget_ref(main_pane_v1);
2588 gtk_widget_ref(main_pane_v2);
2589 gtk_widget_ref(main_pane_h1);
2590 gtk_widget_ref(main_pane_h2);
2592 /* empty all containers participating */
2593 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2594 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2595 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2596 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2597 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2598 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2599 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2601 /* add the menubar always at the top */
2602 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2605 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2607 /* filter toolbar in toolbar area */
2608 if (!prefs.filter_toolbar_show_in_statusbar) {
2609 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2612 /* get the corresponding widgets to the content setting */
2613 pane_content[0] = main_widget_layout(prefs.gui_layout_content_1);
2614 pane_content[1] = main_widget_layout(prefs.gui_layout_content_2);
2615 pane_content[2] = main_widget_layout(prefs.gui_layout_content_3);
2617 /* fill the main layout panes */
2618 switch(prefs.gui_layout_type) {
2619 case(layout_type_5):
2620 main_first_pane = main_pane_v1;
2621 main_second_pane = main_pane_v2;
2622 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2623 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2624 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2625 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2627 case(layout_type_2):
2628 main_first_pane = main_pane_v1;
2629 main_second_pane = main_pane_h1;
2630 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2631 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2632 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2633 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2635 case(layout_type_1):
2636 main_first_pane = main_pane_v1;
2637 main_second_pane = main_pane_h1;
2638 gtk_paned_add1(GTK_PANED(main_first_pane), main_second_pane);
2639 gtk_paned_add2(GTK_PANED(main_first_pane), pane_content[2]);
2640 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[0], TRUE, TRUE);
2641 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[1], FALSE, FALSE);
2643 case(layout_type_4):
2644 main_first_pane = main_pane_h1;
2645 main_second_pane = main_pane_v1;
2646 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2647 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2648 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2649 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2651 case(layout_type_3):
2652 main_first_pane = main_pane_h1;
2653 main_second_pane = main_pane_v1;
2654 gtk_paned_add1(GTK_PANED(main_first_pane), main_second_pane);
2655 gtk_paned_add2(GTK_PANED(main_first_pane), pane_content[2]);
2656 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[0], TRUE, TRUE);
2657 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[1], FALSE, FALSE);
2659 case(layout_type_6):
2660 main_first_pane = main_pane_h1;
2661 main_second_pane = main_pane_h2;
2662 gtk_paned_add1(GTK_PANED(main_first_pane), pane_content[0]);
2663 gtk_paned_add2(GTK_PANED(main_first_pane), main_second_pane);
2664 gtk_paned_pack1(GTK_PANED(main_second_pane), pane_content[1], TRUE, TRUE);
2665 gtk_paned_pack2(GTK_PANED(main_second_pane), pane_content[2], FALSE, FALSE);
2668 g_assert_not_reached();
2671 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2673 /* statusbar hbox */
2674 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2676 /* filter toolbar in statusbar hbox */
2677 if (prefs.filter_toolbar_show_in_statusbar) {
2678 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2682 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2683 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2684 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2686 /* hide widgets on users recent settings */
2687 main_widgets_show_or_hide();
2689 gtk_widget_show(main_vbox);
2693 is_widget_visible(GtkWidget *widget, gpointer data)
2695 gboolean *is_visible = data;
2698 if (GTK_WIDGET_VISIBLE(widget))
2704 * XXX - this doesn't appear to work with the paned widgets in
2705 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
2706 * and the other pane doesn't grow to take up the rest of the pane.
2707 * It does appear to work with GTK+ 2.x.
2710 main_widgets_show_or_hide(void)
2712 gboolean main_second_pane_show;
2714 if (recent.main_toolbar_show) {
2715 gtk_widget_show(main_tb);
2717 gtk_widget_hide(main_tb);
2721 * Show the status hbox if either:
2723 * 1) we're showing the filter toolbar and we want it in the status
2728 * 2) we're showing the status bar.
2730 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
2731 recent.statusbar_show) {
2732 gtk_widget_show(stat_hbox);
2734 gtk_widget_hide(stat_hbox);
2737 if (recent.statusbar_show) {
2738 gtk_widget_show(status_pane);
2740 gtk_widget_hide(status_pane);
2743 if (recent.filter_toolbar_show) {
2744 gtk_widget_show(filter_tb);
2746 gtk_widget_hide(filter_tb);
2749 if (recent.packet_list_show) {
2750 gtk_widget_show(pkt_scrollw);
2752 gtk_widget_hide(pkt_scrollw);
2755 if (recent.tree_view_show) {
2756 gtk_widget_show(tv_scrollw);
2758 gtk_widget_hide(tv_scrollw);
2761 if (recent.byte_view_show) {
2762 gtk_widget_show(byte_nb_ptr);
2764 gtk_widget_hide(byte_nb_ptr);
2768 * Is anything in "main_second_pane" visible?
2769 * If so, show it, otherwise hide it.
2771 main_second_pane_show = FALSE;
2772 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
2773 &main_second_pane_show);
2774 if (main_second_pane_show) {
2775 gtk_widget_show(main_second_pane);
2777 gtk_widget_hide(main_second_pane);
2782 #if GTK_MAJOR_VERSION >= 2
2783 /* called, when the window state changes (minimized, maximized, ...) */
2785 window_state_event_cb (GtkWidget *widget _U_,
2789 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
2791 if( (event->type) == (GDK_WINDOW_STATE)) {
2792 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
2793 /* we might have dialogs popped up while we where iconified,
2795 display_queued_messages();
2804 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2807 *filter_bt, *filter_cm, *filter_te,
2808 *filter_add_expr_bt,
2811 GList *filter_list = NULL;
2812 GtkTooltips *tooltips;
2813 GtkAccelGroup *accel;
2814 /* Display filter construct dialog has an Apply button, and "OK" not
2815 only sets our text widget, it activates it (i.e., it causes us to
2816 filter the capture). */
2817 static construct_args_t args = {
2818 "Ethereal: Display Filter",
2824 top_level = window_new(GTK_WINDOW_TOPLEVEL, "The Ethereal Network Analyzer");
2826 tooltips = gtk_tooltips_new();
2829 #if GTK_MAJOR_VERSION < 2
2830 /* has to be done, after top_level window is created */
2831 app_font_gtk1_init(top_level);
2835 gtk_widget_set_name(top_level, "main window");
2836 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
2838 #if GTK_MAJOR_VERSION >= 2
2839 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
2840 G_CALLBACK (window_state_event_cb), NULL);
2843 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2845 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
2846 main_vbox = gtk_vbox_new(FALSE, 1);
2847 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2848 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2849 gtk_widget_show(main_vbox);
2852 menubar = main_menu_new(&accel);
2853 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2854 gtk_widget_show(menubar);
2857 main_tb = toolbar_new();
2858 gtk_widget_show (main_tb);
2861 pkt_scrollw = packet_list_new(prefs);
2862 WIDGET_SET_SIZE(packet_list, -1, pl_size);
2863 gtk_widget_show(pkt_scrollw);
2866 tv_scrollw = main_tree_view_new(prefs, &tree_view);
2867 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
2868 gtk_widget_show(tv_scrollw);
2870 #if GTK_MAJOR_VERSION < 2
2871 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
2872 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
2875 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
2876 "changed", tree_view_selection_changed_cb, NULL);
2878 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
2879 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
2880 gtk_widget_show(tree_view);
2883 byte_nb_ptr = byte_view_new();
2884 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
2885 gtk_widget_show(byte_nb_ptr);
2887 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
2888 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
2891 /* Panes for the packet list, tree, and byte view */
2892 none_lb = gtk_label_new("None");
2894 main_pane_v1 = gtk_vpaned_new();
2895 gtk_widget_show(main_pane_v1);
2896 main_pane_v2 = gtk_vpaned_new();
2897 gtk_widget_show(main_pane_v2);
2898 main_pane_h1 = gtk_hpaned_new();
2899 gtk_widget_show(main_pane_h1);
2900 main_pane_h2 = gtk_hpaned_new();
2901 gtk_widget_show(main_pane_h2);
2903 /* filter toolbar */
2904 #if GTK_MAJOR_VERSION < 2
2905 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
2908 filter_tb = gtk_toolbar_new();
2909 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
2910 GTK_ORIENTATION_HORIZONTAL);
2911 #endif /* GTK_MAJOR_VERSION */
2912 gtk_widget_show(filter_tb);
2914 /* Create the "Filter:" button */
2915 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
2916 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
2917 gtk_widget_show(filter_bt);
2918 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
2920 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
2921 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
2923 /* Create the filter combobox */
2924 filter_cm = gtk_combo_new();
2926 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
2927 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
2928 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
2929 filter_te = GTK_COMBO(filter_cm)->entry;
2930 main_display_filter_widget=filter_te;
2931 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
2932 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
2933 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
2934 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
2935 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
2936 WIDGET_SET_SIZE(filter_cm, 400, -1);
2937 gtk_widget_show(filter_cm);
2938 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
2940 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
2941 gtk_tooltips_set_tip(tooltips, filter_te,
2942 "Enter a display filter, or choose one of your recently used filters. "
2943 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
2946 /* Create the "Add Expression..." button, to pop up a dialog
2947 for constructing filter comparison expressions. */
2948 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
2949 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
2950 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
2951 gtk_widget_show(filter_add_expr_bt);
2952 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
2953 "Add an expression to this filter string", "Private");
2955 /* Create the "Clear" button */
2956 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
2957 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
2958 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
2959 gtk_widget_show(filter_reset);
2960 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
2961 "Clear this filter string and update the display", "Private");
2963 /* Create the "Apply" button */
2964 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
2965 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
2966 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
2967 gtk_widget_show(filter_apply);
2968 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
2969 "Apply this filter string to the display", "Private");
2971 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
2972 * of any widget that ends up calling a callback which needs
2973 * that text entry pointer */
2974 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
2975 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
2977 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
2979 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
2981 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
2983 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
2985 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
2987 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
2989 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
2991 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
2993 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
2995 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
2997 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
2999 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3001 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3003 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3004 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3005 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3007 /* info (main) statusbar */
3008 info_bar = info_bar_new();
3009 gtk_widget_show(info_bar);
3011 /* packets statusbar */
3012 packets_bar = packets_bar_new();
3013 gtk_widget_show(packets_bar);
3015 /* Filter/status hbox */
3016 stat_hbox = gtk_hbox_new(FALSE, 1);
3017 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3018 gtk_widget_show(stat_hbox);
3020 /* Pane for the statusbar */
3021 status_pane = gtk_hpaned_new();
3022 gtk_widget_show(status_pane);