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.
47 #include <io.h> /* open/close on win32 */
50 #ifdef NEED_STRERROR_H
58 #ifdef _WIN32 /* Needed for console I/O */
63 #include <epan/epan.h>
64 #include <epan/filesystem.h>
65 #include <epan/epan_dissect.h>
66 #include <epan/timestamp.h>
67 #include <epan/packet.h>
68 #include <epan/plugins.h>
69 #include <epan/dfilter/dfilter.h>
70 #include <epan/strutil.h>
71 #include <epan/addr_resolv.h>
73 /* general (not GTK specific) */
74 #include "svnversion.h"
78 #include "disabled_protos.h"
79 #include <epan/prefs.h>
80 #include "filter_dlg.h"
81 #include "layout_prefs.h"
83 #include "color_filters.h"
85 #include "simple_dialog.h"
87 #include <epan/prefs-int.h>
88 #include "ringbuffer.h"
89 #include "../ui_util.h" /* beware: ui_util.h exists twice! */
92 #include "clopts_common.h"
93 #include "version_info.h"
97 #include "pcap-util.h"
100 #include "capture-wpcap.h"
102 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
103 #include "ethclist.h"
107 #include "statusbar.h"
108 #include "alert_box.h"
109 #include "dlg_utils.h"
110 #include "gtkglobals.h"
112 #include "ui_util.h" /* beware: ui_util.h exists twice! */
113 #include "compat_macros.h"
117 #include "../main_window.h"
119 #include "file_dlg.h"
120 #include <epan/column.h>
121 #include "proto_draw.h"
123 #include "packet_win.h"
125 #include "find_dlg.h"
126 #include "packet_list.h"
128 #include "follow_dlg.h"
129 #include "font_utils.h"
130 #include "about_dlg.h"
131 #include "help_dlg.h"
132 #include "decode_as_dlg.h"
133 #include "webbrowser.h"
134 #include "capture_dlg.h"
136 #include "../image/eicon3d64.xpm"
138 #include "capture_ui_utils.h"
143 * File under personal preferences directory in which GTK settings for
144 * Ethereal are stored.
146 #define RC_FILE "gtkrc"
149 #define DEF_READY_MESSAGE " Ready to load or capture"
151 #define DEF_READY_MESSAGE " Ready to load file"
155 GtkWidget *main_display_filter_widget=NULL;
156 GtkWidget *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
157 static GtkWidget *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
158 static GtkWidget *main_first_pane, *main_second_pane;
159 static GtkWidget *status_pane;
160 static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
161 static GtkWidget *info_bar;
162 static GtkWidget *packets_bar = NULL;
163 static GtkWidget *welcome_pane;
164 static guint main_ctx, file_ctx, help_ctx;
165 static guint packets_ctx;
166 static gchar *packets_str = NULL;
167 GString *comp_info_str, *runtime_info_str;
168 gchar *ethereal_path = NULL;
169 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
172 static gboolean has_console; /* TRUE if app has console */
173 /*static void create_console(void);*/
174 static void destroy_console(void);
175 static void console_log_handler(const char *log_domain,
176 GLogLevelFlags log_level, const char *message, gpointer user_data);
180 static gboolean list_link_layer_types;
181 capture_options global_capture_opts;
182 capture_options *capture_opts = &global_capture_opts;
186 static void create_main_window(gint, gint, gint, e_prefs*);
187 static void show_main_window(gboolean);
188 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
189 static void main_save_window_geometry(GtkWidget *widget);
191 #define E_DFILTER_CM_KEY "display_filter_combo"
192 #define E_DFILTER_FL_KEY "display_filter_list"
196 /* Match selected byte pattern */
198 match_selected_cb_do(gpointer data, int action, gchar *text)
200 GtkWidget *filter_te;
201 char *cur_filter, *new_filter;
206 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
209 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
211 switch (action&MATCH_SELECTED_MASK) {
213 case MATCH_SELECTED_REPLACE:
214 new_filter = g_strdup(text);
217 case MATCH_SELECTED_AND:
218 if ((!cur_filter) || (0 == strlen(cur_filter)))
219 new_filter = g_strdup(text);
221 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
224 case MATCH_SELECTED_OR:
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_NOT:
232 new_filter = g_strconcat("!(", text, ")", NULL);
235 case MATCH_SELECTED_AND_NOT:
236 if ((!cur_filter) || (0 == strlen(cur_filter)))
237 new_filter = g_strconcat("!(", text, ")", NULL);
239 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
242 case MATCH_SELECTED_OR_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);
250 g_assert_not_reached();
255 /* Free up the copy we got of the old filter text. */
258 /* create a new one and set the display filter entry accordingly */
259 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
261 /* Run the display filter so it goes in effect. */
262 if (action&MATCH_SELECTED_APPLY_NOW)
263 main_filter_packets(&cfile, new_filter, FALSE);
265 /* Free up the new filter text. */
268 /* Free up the generated text we were handed. */
273 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
275 if (cfile.finfo_selected)
276 match_selected_cb_do((data ? data : w),
278 proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
282 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
284 gchar *selected_proto_url;
285 gchar *proto_abbrev = data;
290 if (cfile.finfo_selected) {
291 /* open wiki page using the protocol abbreviation */
292 selected_proto_url = g_strdup_printf("http://wiki.ethereal.com/Protocols/%s", proto_abbrev);
293 browser_open_url(selected_proto_url);
294 g_free(selected_proto_url);
297 case(ESD_BTN_CANCEL):
300 g_assert_not_reached();
306 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
313 if (cfile.finfo_selected) {
314 /* convert selected field to protocol abbreviation */
315 /* XXX - could this conversion be simplified? */
316 field_id = cfile.finfo_selected->hfinfo->id;
317 /* if the selected field isn't a protocol, get it's parent */
318 if(!proto_registrar_is_protocol(field_id)) {
319 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
322 proto_abbrev = proto_registrar_get_abbrev(field_id);
324 /* ask the user if the wiki page really should be opened */
325 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
326 PRIMARY_TEXT_START "Open Ethereal Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
328 "This will open the \"%s\" related Ethereal Wiki page in your Web browser.\n"
330 "The Ethereal Wiki is a collaborative approach to provide information\n"
331 "about Ethereal in several ways (not limited to protocol specifics).\n"
333 "This Wiki is new, so the page of the selected protocol\n"
334 "may not exist and/or may not contain valuable information.\n"
336 "As everyone can edit the Wiki and add new content (or extend existing),\n"
337 "you are encouraged to add information if you can.\n"
339 "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
341 "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
342 "which will save you a lot of editing and will give a consistent look over the pages.",
343 proto_abbrev, proto_abbrev);
344 simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, proto_abbrev);
350 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
354 gchar *selected_proto_url;
357 if (cfile.finfo_selected) {
358 /* convert selected field to protocol abbreviation */
359 /* XXX - could this conversion be simplified? */
360 field_id = cfile.finfo_selected->hfinfo->id;
361 /* if the selected field isn't a protocol, get it's parent */
362 if(!proto_registrar_is_protocol(field_id)) {
363 field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
366 proto_abbrev = proto_registrar_get_abbrev(field_id);
368 /* open reference page using the protocol abbreviation */
369 selected_proto_url = g_strdup_printf("http://www.ethereal.com/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
370 browser_open_url(selected_proto_url);
371 g_free(selected_proto_url);
377 get_text_from_packet_list(gpointer data)
379 gint row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
380 gint column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
381 frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
389 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
390 cfile.pd, fdata->cap_len, &err, &err_info)) {
391 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
392 cf_read_error_message(err, err_info), cfile.filename);
396 edt = epan_dissect_new(FALSE, FALSE);
397 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
399 epan_dissect_fill_in_columns(edt);
401 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
402 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
403 len = strlen(cfile.cinfo.col_expr[column]) +
404 strlen(cfile.cinfo.col_expr_val[column]) + 5;
405 buf = g_malloc0(len);
406 g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
407 cfile.cinfo.col_expr_val[column]);
410 epan_dissect_free(edt);
417 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
419 match_selected_cb_do(data,
421 get_text_from_packet_list(data));
426 /* XXX: use a preference for this setting! */
427 static guint dfilter_combo_max_recent = 10;
429 /* add a display filter to the combo box */
430 /* Note: a new filter string will replace an old identical one */
432 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
434 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
437 /* GtkCombos don't let us get at their list contents easily, so we maintain
438 our own filter list, and feed it to gtk_combo_set_popdown_strings when
439 a new filter is added. */
440 li = g_list_first(filter_list);
442 /* If the filter is already in the list, remove the old one and
443 * append the new one at the latest position (at g_list_append() below) */
444 if (li->data && strcmp(s, li->data) == 0) {
445 filter_list = g_list_remove(filter_list, li->data);
451 filter_list = g_list_append(filter_list, s);
452 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
453 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
454 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data);
460 /* write all non empty display filters (until maximum count)
461 * of the combo box GList to the user's recent file */
463 dfilter_recent_combo_write_all(FILE *rf) {
464 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
465 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
470 /* write all non empty display filter strings to the recent file (until max count) */
471 li = g_list_first(filter_list);
472 while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
473 if (strlen(li->data)) {
474 fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
480 /* empty the combobox entry field */
482 dfilter_combo_add_empty(void) {
483 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
485 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
489 /* add a display filter coming from the user's recent file to the dfilter combo box */
491 dfilter_combo_add_recent(gchar *s) {
492 GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
496 if (!dfilter_combo_add(filter_cm, dup)) {
505 /* call cf_filter_packets() and add this filter string to the recent filter list */
507 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
509 GtkCombo *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
510 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
512 gboolean add_filter = TRUE;
513 gboolean free_filter = TRUE;
515 cf_status_t cf_status;
517 /* we'll crash later on if dftext is NULL */
518 g_assert(dftext != NULL);
520 s = g_strdup(dftext);
522 /* GtkCombos don't let us get at their list contents easily, so we maintain
523 our own filter list, and feed it to gtk_combo_set_popdown_strings when
524 a new filter is added. */
525 cf_status = cf_filter_packets(cf, s, force);
526 if (cf_status == CF_OK) {
527 li = g_list_first(filter_list);
529 if (li->data && strcmp(s, li->data) == 0)
535 /* trim list size first */
536 while (g_list_length(filter_list) >= dfilter_combo_max_recent) {
537 filter_list = g_list_remove(filter_list, g_list_first(filter_list)->data);
541 filter_list = g_list_append(filter_list, s);
542 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
543 gtk_combo_set_popdown_strings(filter_cm, filter_list);
544 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
550 return (cf_status == CF_OK);
554 /* Run the current display filter on the current packet set, and
557 filter_activate_cb(GtkWidget *w _U_, gpointer data)
561 s = gtk_entry_get_text(GTK_ENTRY(data));
563 main_filter_packets(&cfile, s, FALSE);
566 /* redisplay with no display filter */
568 filter_reset_cb(GtkWidget *w, gpointer data _U_)
570 GtkWidget *filter_te = NULL;
572 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
573 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
575 main_filter_packets(&cfile, "", FALSE);
578 /* mark as reference time frame */
580 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
584 frame->flags.ref_time=1;
586 frame->flags.ref_time=0;
588 cf_reftime_packets(&cfile);
592 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
597 if (cfile.current_frame) {
598 /* XXX hum, should better have a "cfile->current_row" here ... */
599 set_frame_reftime(!cfile.current_frame->flags.ref_time,
601 packet_list_find_row_from_data(cfile.current_frame));
604 case REFTIME_FIND_NEXT:
605 find_previous_next_frame_with_filter("frame.ref_time", FALSE);
607 case REFTIME_FIND_PREV:
608 find_previous_next_frame_with_filter("frame.ref_time", TRUE);
613 #if GTK_MAJOR_VERSION < 2
615 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
616 gpointer user_data _U_)
619 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
623 gchar *help_str = NULL;
624 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
626 gboolean has_blurb = FALSE;
627 guint length = 0, byte_len;
628 GtkWidget *byte_view;
629 const guint8 *byte_data;
630 #if GTK_MAJOR_VERSION >= 2
635 #if GTK_MAJOR_VERSION >= 2
636 /* if nothing is selected */
637 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
640 * Which byte view is displaying the current protocol tree
643 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
644 if (byte_view == NULL)
647 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
648 if (byte_data == NULL)
651 cf_unselect_field(&cfile);
652 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
653 cfile.current_frame, NULL, byte_len);
656 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
659 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
663 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
665 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
666 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
667 g_assert(byte_data != NULL);
669 cfile.finfo_selected = finfo;
670 set_menus_for_selected_tree_row(&cfile);
673 if (finfo->hfinfo->blurb != NULL &&
674 finfo->hfinfo->blurb[0] != '\0') {
676 length = strlen(finfo->hfinfo->blurb);
678 length = strlen(finfo->hfinfo->name);
680 if (finfo->length == 0) {
682 } else if (finfo->length == 1) {
683 strcpy (len_str, ", 1 byte");
685 g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
687 statusbar_pop_field_msg(); /* get rid of current help msg */
689 help_str = g_strdup_printf("%s (%s)%s",
690 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
691 finfo->hfinfo->abbrev, len_str);
692 statusbar_push_field_msg(help_str);
696 * Don't show anything if the field name is zero-length;
697 * the pseudo-field for "proto_tree_add_text()" is such
698 * a field, and we don't want "Text (text)" showing up
699 * on the status line if you've selected such a field.
701 * XXX - there are zero-length fields for which we *do*
702 * want to show the field name.
704 * XXX - perhaps the name and abbrev field should be null
705 * pointers rather than null strings for that pseudo-field,
706 * but we'd have to add checks for null pointers in some
707 * places if we did that.
709 * Or perhaps protocol tree items added with
710 * "proto_tree_add_text()" should have -1 as the field index,
711 * with no pseudo-field being used, but that might also
712 * require special checks for -1 to be added.
714 statusbar_push_field_msg("");
718 #if GTK_MAJOR_VERSION < 2
719 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
722 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
727 #if GTK_MAJOR_VERSION < 2
729 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
730 gpointer user_data _U_)
732 GtkWidget *byte_view;
737 * Which byte view is displaying the current protocol tree
740 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
741 if (byte_view == NULL)
744 data = get_byte_view_data_and_length(byte_view, &len);
748 cf_unselect_field(&cfile);
749 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
754 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
756 collapse_all_tree(cfile.edt->tree, tree_view);
759 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
761 expand_all_tree(cfile.edt->tree, tree_view);
764 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
765 #if GTK_MAJOR_VERSION < 2
771 #if GTK_MAJOR_VERSION < 2
772 node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
774 gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
776 path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
778 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
779 gtk_tree_path_free(path);
783 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
784 if (cfile.edt->tree) {
785 guint32 tmp = g_resolv_flags;
786 g_resolv_flags = RESOLV_ALL;
787 proto_tree_draw(cfile.edt->tree, tree_view);
788 g_resolv_flags = tmp;
793 * Push a message referring to file access onto the statusbar.
796 statusbar_push_file_msg(gchar *msg)
798 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
802 * Pop a message referring to file access off the statusbar.
805 statusbar_pop_file_msg(void)
807 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
811 * XXX - do we need multiple statusbar contexts?
815 * Push a message referring to the currently-selected field onto the statusbar.
818 statusbar_push_field_msg(gchar *msg)
820 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
824 * Pop a message referring to the currently-selected field off the statusbar.
827 statusbar_pop_field_msg(void)
829 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
833 * update the packets statusbar to the current values
835 void packets_bar_update(void)
839 /* remove old status */
842 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
845 /* do we have any packets? */
847 packets_str = g_strdup_printf(" P: %u D: %u M: %u",
848 cfile.count, cfile.displayed_count, cfile.marked_count);
850 packets_str = g_strdup(" No Packets");
852 gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
857 main_set_for_capture_file(gboolean have_capture_file_in)
859 have_capture_file = have_capture_file_in;
861 main_widgets_show_or_hide();
870 /* get the current geometry, before writing it to disk */
871 main_save_window_geometry(top_level);
873 /* write user's recent file to disk
874 * It is no problem to write this file, even if we do not quit */
875 write_recent(&rec_path);
877 /* XXX - should we check whether the capture file is an
878 unsaved temporary file for a live capture and, if so,
879 pop up a "do you want to exit without saving the capture
880 file?" dialog, and then just return, leaving said dialog
881 box to forcibly quit if the user clicks "OK"?
883 If so, note that this should be done in a subroutine that
884 returns TRUE if we do so, and FALSE otherwise, and if it
885 returns TRUE we should return TRUE without nuking anything.
887 Note that, if we do that, we might also want to check if
888 an "Update list of packets in real time" capture is in
889 progress and, if so, ask whether they want to terminate
890 the capture and discard it, and return TRUE, before nuking
891 any child capture, if they say they don't want to do so. */
894 /* Nuke any child capture in progress. */
895 capture_kill_child(capture_opts);
898 /* Are we in the middle of reading a capture? */
899 if (cfile.state == FILE_READ_IN_PROGRESS) {
900 /* Yes, so we can't just close the file and quit, as
901 that may yank the rug out from under the read in
902 progress; instead, just set the state to
903 "FILE_READ_ABORTED" and return - the code doing the read
904 will check for that and, if it sees that, will clean
906 cfile.state = FILE_READ_ABORTED;
908 /* Say that the window should *not* be deleted;
909 that'll be done by the code that cleans up. */
912 /* Close any capture file we have open; on some OSes, you
913 can't unlink a temporary capture file if you have it
915 "cf_close()" will unlink it after closing it if
916 it's a temporary file.
918 We do this here, rather than after the main loop returns,
919 as, after the main loop returns, the main window may have
920 been destroyed (if this is called due to a "destroy"
921 even on the main window rather than due to the user
922 selecting a menu item), and there may be a crash
923 or other problem when "cf_close()" tries to
924 clean up stuff in the main window.
926 XXX - is there a better place to put this?
927 Or should we have a routine that *just* closes the
928 capture file, and doesn't do anything with the UI,
929 which we'd call here, and another routine that
930 calls that routine and also cleans up the UI, which
931 we'd call elsewhere? */
934 /* Exit by leaving the main loop, so that any quit functions
935 we registered get called. */
938 /* Say that the window should be deleted. */
944 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
948 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
949 #if GTK_MAJOR_VERSION >= 2
950 gtk_window_present(GTK_WINDOW(top_level));
952 /* user didn't saved his current file, ask him */
953 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
954 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
955 "If you quit the program without saving, your capture data will be discarded.");
956 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
959 /* unchanged file, just exit */
960 /* "main_do_quit()" indicates whether the main window should be deleted. */
961 return main_do_quit();
968 main_load_window_geometry(GtkWidget *widget)
970 window_geometry_t geom;
972 geom.set_pos = prefs.gui_geometry_save_position;
973 geom.x = recent.gui_geometry_main_x;
974 geom.y = recent.gui_geometry_main_y;
975 geom.set_size = prefs.gui_geometry_save_size;
976 if (recent.gui_geometry_main_width > 0 &&
977 recent.gui_geometry_main_height > 0) {
978 geom.width = recent.gui_geometry_main_width;
979 geom.height = recent.gui_geometry_main_height;
980 geom.set_maximized = prefs.gui_geometry_save_maximized;
982 /* We assume this means the width and height weren't set in
983 the "recent" file (or that there is no "recent" file),
984 and weren't set to a default value, so we don't set the
985 size. (The "recent" file code rejects non-positive width
986 and height values.) */
987 geom.set_size = FALSE;
989 geom.maximized = recent.gui_geometry_main_maximized;
991 window_set_geometry(widget, &geom);
993 #if GTK_MAJOR_VERSION >= 2
994 /* XXX - rename recent settings? */
995 if (recent.gui_geometry_main_upper_pane)
996 gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
997 if (recent.gui_geometry_main_lower_pane)
998 gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
999 if (recent.gui_geometry_status_pane)
1000 gtk_paned_set_position(GTK_PANED(status_pane), recent.gui_geometry_status_pane);
1006 main_save_window_geometry(GtkWidget *widget)
1008 window_geometry_t geom;
1010 window_get_geometry(widget, &geom);
1012 if (prefs.gui_geometry_save_position) {
1013 recent.gui_geometry_main_x = geom.x;
1014 recent.gui_geometry_main_y = geom.y;
1017 if (prefs.gui_geometry_save_size) {
1018 recent.gui_geometry_main_width = geom.width,
1019 recent.gui_geometry_main_height = geom.height;
1022 #if GTK_MAJOR_VERSION >= 2
1023 if(prefs.gui_geometry_save_maximized) {
1024 recent.gui_geometry_main_maximized = geom.maximized;
1027 recent.gui_geometry_main_upper_pane = gtk_paned_get_position(GTK_PANED(main_first_pane));
1028 recent.gui_geometry_main_lower_pane = gtk_paned_get_position(GTK_PANED(main_second_pane));
1029 recent.gui_geometry_status_pane = gtk_paned_get_position(GTK_PANED(status_pane));
1033 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1037 /* save file first */
1038 file_save_as_cmd(after_save_exit, NULL);
1040 case(ESD_BTN_DONT_SAVE):
1043 case(ESD_BTN_CANCEL):
1046 g_assert_not_reached();
1051 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1055 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1056 /* user didn't saved his current file, ask him */
1057 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1058 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1059 "If you quit the program without saving, your capture data will be discarded.");
1060 simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1062 /* unchanged file, just exit */
1068 print_usage(gboolean print_ver) {
1074 fprintf(output, "This is GNU " PACKAGE " " VERSION
1079 comp_info_str->str, runtime_info_str->str);
1084 fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n",
1086 fprintf(output, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
1087 fprintf(output, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
1088 fprintf(output, "\t[ -i <interface> ] [ -m <medium font> ] [ -N <resolving> ]\n");
1089 fprintf(output, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1090 fprintf(output, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1091 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1092 fprintf(output, "\t[ -w <savefile> ] [ -y <link type> ] [ -z <statistics string> ]\n");
1093 fprintf(output, "\t[ <infile> ]\n");
1095 fprintf(output, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1097 fprintf(output, "\t[ -N <resolving> ] [ -o <preference setting> ...\n");
1098 fprintf(output, "\t[ -P <packet list height> ] [ -r <infile> ] [ -R <read filter> ]\n");
1099 fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1100 fprintf(output, "\t[ -z <statistics string> ] [ <infile> ]\n");
1111 printf(PACKAGE " " VERSION
1116 comp_info_str->str, runtime_info_str->str);
1120 get_natural_int(const char *string, const char *name)
1125 number = strtol(string, &p, 10);
1126 if (p == string || *p != '\0') {
1127 fprintf(stderr, "ethereal: The specified %s \"%s\" isn't a decimal number\n",
1132 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1136 if (number > INT_MAX) {
1137 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1138 name, string, INT_MAX);
1145 get_positive_int(const char *string, const char *name)
1149 number = get_natural_int(string, name);
1152 fprintf(stderr, "ethereal: The specified %s is zero\n",
1160 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1162 Once every 3 seconds we get a callback here which we use to update
1163 the tap extensions. Since Gtk1 is single threaded we dont have to
1164 worry about any locking or critical regions.
1167 update_cb(gpointer data _U_)
1169 draw_tap_listeners(FALSE);
1174 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1175 use threads all updte_thread_mutex can be dropped and protect/unprotect
1176 would just be empty functions.
1178 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1179 gtk1-ethereal and it will just work.
1181 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1183 update_thread(gpointer data _U_)
1187 g_get_current_time(&tv1);
1188 g_static_mutex_lock(&update_thread_mutex);
1189 gdk_threads_enter();
1190 draw_tap_listeners(FALSE);
1191 gdk_threads_leave();
1192 g_static_mutex_unlock(&update_thread_mutex);
1194 g_get_current_time(&tv2);
1195 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1196 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1197 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1198 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1205 protect_thread_critical_region(void)
1207 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1208 g_static_mutex_lock(&update_thread_mutex);
1212 unprotect_thread_critical_region(void)
1214 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1215 g_static_mutex_unlock(&update_thread_mutex);
1219 /* structure to keep track of what tap listeners have been registered.
1221 typedef struct _ethereal_tap_list {
1222 struct _ethereal_tap_list *next;
1224 void (*func)(char *arg);
1225 } ethereal_tap_list;
1226 static ethereal_tap_list *tap_list=NULL;
1229 register_ethereal_tap(char *cmd, void (*func)(char *arg))
1231 ethereal_tap_list *newtl;
1233 newtl=malloc(sizeof(ethereal_tap_list));
1234 newtl->next=tap_list;
1241 /* Set the file name in the status line, in the name for the main window,
1242 and in the name for the main window's icon. */
1244 set_display_filename(capture_file *cf)
1246 const gchar *name_ptr;
1248 static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
1249 static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
1251 gchar *win_name_fmt = "%s - Ethereal";
1255 name_ptr = cf_get_display_name(cf);
1257 if (!cf->is_tempfile) {
1258 /* Add this filename to the list of recent files in the "Recent Files" submenu */
1259 add_menu_recent_capture_file(cf->filename);
1262 if (cf->f_len/1024/1024 > 10) {
1263 size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
1264 } else if (cf->f_len/1024 > 10) {
1265 size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
1267 size_str = g_strdup_printf("%ld bytes", cf->f_len);
1270 if (cf->drops_known) {
1271 done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str,
1272 cf->esec/3600, cf->esec%3600/60, cf->esec%60, cf->drops);
1274 done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
1275 cf->esec/3600, cf->esec%3600/60, cf->esec%60);
1277 statusbar_push_file_msg(done_msg);
1280 msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
1281 win_name = g_malloc(msg_len);
1282 snprintf(win_name, msg_len, win_name_fmt, name_ptr);
1283 set_main_window_name(win_name);
1289 main_cf_cb_file_closed(capture_file *cf)
1291 /* Destroy all windows, which refer to the
1292 capture file we're closing. */
1293 destroy_cfile_wins();
1295 /* Clear any file-related status bar messages.
1296 XXX - should be "clear *ALL* file-related status bar messages;
1297 will there ever be more than one on the stack? */
1298 statusbar_pop_file_msg();
1300 /* Restore the standard title bar message. */
1301 set_main_window_name("The Ethereal Network Analyzer");
1303 /* Disable all menu items that make sense only if you have a capture. */
1304 set_menus_for_capture_file(FALSE);
1305 set_menus_for_unsaved_capture_file(FALSE);
1306 set_menus_for_captured_packets(FALSE);
1307 set_menus_for_selected_packet(cf);
1308 set_menus_for_capture_in_progress(FALSE);
1309 set_menus_for_selected_tree_row(cf);
1311 /* Set up main window for no capture file. */
1312 main_set_for_capture_file(FALSE);
1316 main_cf_cb_file_read_start(capture_file *cf)
1318 const gchar *name_ptr;
1321 name_ptr = get_basename(cf->filename);
1323 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1324 statusbar_push_file_msg(load_msg);
1329 main_cf_cb_file_read_finished(capture_file *cf)
1331 statusbar_pop_file_msg();
1332 set_display_filename(cf);
1334 /* Enable menu items that make sense if you have a capture file you've
1335 finished reading. */
1336 set_menus_for_capture_file(TRUE);
1337 set_menus_for_unsaved_capture_file(!cf->user_saved);
1339 /* Enable menu items that make sense if you have some captured packets. */
1340 set_menus_for_captured_packets(TRUE);
1342 /* Set up main window for a capture file. */
1343 main_set_for_capture_file(TRUE);
1348 main_cf_cb_live_capture_prepare(capture_options *capture_opts)
1353 title = g_strdup_printf("%s: Capturing - Ethereal",
1354 get_interface_descriptive_name(capture_opts->iface));
1355 set_main_window_name(title);
1360 main_cf_cb_live_capture_started(capture_options *capture_opts)
1364 /* Disable menu items that make no sense if you're currently running
1366 set_menus_for_capture_in_progress(TRUE);
1368 /* Enable menu items that make sense if you have some captured
1369 packets (yes, I know, we don't have any *yet*). */
1370 set_menus_for_captured_packets(TRUE);
1372 capture_msg = g_strdup_printf(" %s: <live capture in progress>", get_interface_descriptive_name(capture_opts->iface));
1374 statusbar_push_file_msg(capture_msg);
1376 g_free(capture_msg);
1378 /* Set up main window for a capture file. */
1379 main_set_for_capture_file(TRUE);
1383 main_cf_cb_live_capture_finished(capture_file *cf)
1385 /* Pop the "<live capture in progress>" message off the status bar. */
1386 statusbar_pop_file_msg();
1388 set_display_filename(cf);
1390 /* Enable menu items that make sense if you're not currently running
1392 set_menus_for_capture_in_progress(FALSE);
1394 /* Enable menu items that make sense if you have a capture file
1395 you've finished reading. */
1396 set_menus_for_capture_file(TRUE);
1397 set_menus_for_unsaved_capture_file(!cf->user_saved);
1399 /* Set up main window for a capture file. */
1400 main_set_for_capture_file(TRUE);
1405 main_cf_cb_packet_selected(gpointer data)
1407 capture_file *cf = data;
1409 /* Display the GUI protocol tree and hex dump.
1410 XXX - why do we dump core if we call "proto_tree_draw()"
1411 before calling "add_byte_views()"? */
1412 add_main_byte_views(cf->edt);
1413 main_proto_tree_draw(cf->edt->tree);
1415 /* A packet is selected. */
1416 set_menus_for_selected_packet(cf);
1420 main_cf_cb_packet_unselected(capture_file *cf)
1422 /* Clear out the display of that packet. */
1423 clear_tree_and_hex_views();
1425 /* No packet is selected. */
1426 set_menus_for_selected_packet(cf);
1430 main_cf_cb_field_unselected(capture_file *cf)
1432 statusbar_pop_field_msg();
1433 set_menus_for_selected_tree_row(cf);
1437 main_cf_cb_file_safe_started(gchar * filename)
1439 const gchar *name_ptr;
1442 name_ptr = get_basename(filename);
1444 save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1446 statusbar_push_file_msg(save_msg);
1451 main_cf_cb_file_safe_finished(gpointer data _U_)
1453 /* Pop the "Saving:" message off the status bar. */
1454 statusbar_pop_file_msg();
1458 main_cf_cb_file_safe_failed(gpointer data _U_)
1460 /* Pop the "Saving:" message off the status bar. */
1461 statusbar_pop_file_msg();
1465 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1467 set_menus_for_unsaved_capture_file(FALSE);
1470 void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1473 case(cf_cb_file_closed):
1474 main_cf_cb_file_closed(data);
1476 case(cf_cb_file_read_start):
1477 main_cf_cb_file_read_start(data);
1479 case(cf_cb_file_read_finished):
1480 main_cf_cb_file_read_finished(data);
1483 case(cf_cb_live_capture_prepare):
1484 main_cf_cb_live_capture_prepare(data);
1486 case(cf_cb_live_capture_started):
1487 main_cf_cb_live_capture_started(data);
1489 case(cf_cb_live_capture_finished):
1490 main_cf_cb_live_capture_finished(data);
1493 case(cf_cb_packet_selected):
1494 main_cf_cb_packet_selected(data);
1496 case(cf_cb_packet_unselected):
1497 main_cf_cb_packet_unselected(data);
1499 case(cf_cb_field_unselected):
1500 main_cf_cb_field_unselected(data);
1502 case(cf_cb_file_safe_started):
1503 main_cf_cb_file_safe_started(data);
1505 case(cf_cb_file_safe_finished):
1506 main_cf_cb_file_safe_finished(data);
1508 case(cf_cb_file_safe_reload_finished):
1509 main_cf_cb_file_safe_reload_finished(data);
1511 case(cf_cb_file_safe_failed):
1512 main_cf_cb_file_safe_failed(data);
1515 g_warning("main_cf_callback: event %u unknown", event);
1516 g_assert_not_reached();
1520 /* And now our feature presentation... [ fade to music ] */
1522 main(int argc, char *argv[])
1525 const char *command_name;
1530 extern char *optarg;
1531 gboolean arg_error = FALSE;
1539 char *gpf_path, *pf_path;
1540 char *cf_path, *df_path;
1541 char *gdp_path, *dp_path;
1542 int gpf_open_errno, gpf_read_errno;
1543 int pf_open_errno, pf_read_errno;
1544 int cf_open_errno, df_open_errno;
1545 int gdp_open_errno, gdp_read_errno;
1546 int dp_open_errno, dp_read_errno;
1549 gboolean start_capture = FALSE;
1552 GList *lt_list, *lt_entry;
1553 data_link_info_t *data_link_info;
1554 gchar err_str[PCAP_ERRBUF_SIZE];
1555 gchar *cant_get_if_list_errstr;
1556 gboolean stats_known;
1557 struct pcap_stat stats;
1559 gboolean capture_option_specified = FALSE;
1561 gint pl_size = 280, tv_size = 95, bv_size = 75;
1562 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1563 dfilter_t *rfcode = NULL;
1564 gboolean rfilter_parse_failed = FALSE;
1567 ethereal_tap_list *tli = NULL;
1568 gchar *tap_opt = NULL;
1569 GtkWidget *splash_win = NULL;
1571 #define OPTSTRING_INIT "a:b:B:c:f:Hhi:klLm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:"
1575 #define OPTSTRING_CHILD "W:Z:"
1577 #define OPTSTRING_CHILD "W:"
1580 #define OPTSTRING_CHILD ""
1581 #endif /* HAVE_LIBPCAP */
1583 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1587 /* Set the current locale according to the program environment.
1588 * We haven't localized anything, but some GTK widgets are localized
1589 * (the file selection dialogue, for example).
1590 * This also sets the C-language locale to the native environment. */
1593 /* Let GTK get its args */
1594 gtk_init (&argc, &argv);
1596 cf_callback_add(main_cf_callback, NULL);
1598 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1599 /* initialize our GTK eth_clist_type */
1600 init_eth_clist_type();
1603 ethereal_path = argv[0];
1606 /* Arrange that if we have no console window, and a GLib message logging
1607 routine is called to log a message, we pop up a console window.
1609 We do that by inserting our own handler for all messages logged
1610 to the default domain; that handler pops up a console if necessary,
1611 and then calls the default handler. */
1612 g_log_set_handler(NULL,
1614 G_LOG_LEVEL_CRITICAL|
1615 G_LOG_LEVEL_WARNING|
1616 G_LOG_LEVEL_MESSAGE|
1619 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1620 console_log_handler, NULL);
1624 /* Set the initial values in the capture_opts. This might be overwritten
1625 by preference settings and then again by the command line parameters. */
1626 capture_opts_init(capture_opts, &cfile);
1628 capture_opts->snaplen = MIN_PACKET_SIZE;
1629 capture_opts->has_ring_num_files = TRUE;
1631 command_name = get_basename(ethereal_path);
1632 /* Set "capture_child" to indicate whether this is going to be a child
1633 process for a "-S" capture. */
1634 capture_opts->capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1635 if (capture_opts->capture_child) {
1636 strcat(optstring, OPTSTRING_CHILD);
1640 /* We want a splash screen only if we're not a child process */
1641 /* We also want it only if we're not being run with "-G".
1642 XXX - we also don't want it if we're being run with
1643 "-h" or "-v", as those are options to run Ethereal and just
1644 have it print stuff to the command line. That would require
1645 that we parse the argument list before putting up the splash
1646 screen, which means we'd need to do so before reading the
1647 preference files, as that could take enough time that we'd
1648 want the splash screen up while we're doing that. Unfortunately,
1649 that means we'd have to queue up, for example, "-o" options,
1650 so that we apply them *after* reading the preferences, as
1651 they're supposed to override saved preferences. */
1652 if ((argc < 2 || strcmp(argv[1], "-G") != 0)
1654 && !capture_opts->capture_child
1657 splash_win = splash_new("Loading Ethereal ...");
1660 splash_update(splash_win, "Registering dissectors ...");
1662 /* Register all dissectors; we must do this before checking for the
1663 "-G" flag, as the "-G" flag dumps information registered by the
1664 dissectors, and we must do it before we read the preferences, in
1665 case any dissectors register preferences. */
1666 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1667 failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1669 splash_update(splash_win, "Registering tap listeners ...");
1671 /* Register all tap listeners; we do this before we parse the arguments,
1672 as the "-z" argument can specify a registered tap. */
1673 register_all_tap_listeners();
1675 splash_update(splash_win, "Loading module preferences ...");
1677 /* Now register the preferences for any non-dissector modules.
1678 We must do that before we read the preferences as well. */
1679 prefs_register_modules();
1681 /* If invoked with the "-G" flag, we dump out information based on
1682 the argument to the "-G" flag; if no argument is specified,
1683 for backwards compatibility we dump out a glossary of display
1686 We must do this before calling "gtk_init()", because "gtk_init()"
1687 tries to open an X display, and we don't want to have to do any X
1688 stuff just to do a build.
1690 Given that we call "gtk_init()" before doing the regular argument
1691 list processing, so that it can handle X and GTK+ arguments and
1692 remove them from the list at which we look, this means we must do
1693 this before doing the regular argument list processing, as well.
1697 you must give the "-G" flag as the first flag on the command line;
1699 you must give it as "-G", nothing more, nothing less;
1701 the first argument after the "-G" flag, if present, will be used
1702 to specify the information to dump;
1704 arguments after that will not be used. */
1705 handle_dashG_option(argc, argv, "ethereal");
1707 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1708 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1711 g_thread_init(NULL);
1713 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1714 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1716 #else /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1717 /* this is to keep tap extensions updating once every 3 seconds */
1718 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1719 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1722 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1725 splash_update(splash_win, "Loading configuration files ...");
1727 /* Read the preference files. */
1728 prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1729 &pf_open_errno, &pf_read_errno, &pf_path);
1730 if (gpf_path != NULL) {
1731 if (gpf_open_errno != 0) {
1732 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1733 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1734 strerror(gpf_open_errno));
1736 if (gpf_read_errno != 0) {
1737 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1738 "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1739 strerror(gpf_read_errno));
1742 if (pf_path != NULL) {
1743 if (pf_open_errno != 0) {
1744 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1745 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1746 strerror(pf_open_errno));
1748 if (pf_read_errno != 0) {
1749 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1750 "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1751 strerror(pf_read_errno));
1758 /* if the user wants a console to be always there, well, we should open one for him */
1759 if (prefs->gui_console_open == console_open_always) {
1765 /* If this is a capture child process, it should pay no attention
1766 to the "prefs.capture_prom_mode" setting in the preferences file;
1767 it should do what the parent process tells it to do, and if
1768 the parent process wants it not to run in promiscuous mode, it'll
1769 tell it so with a "-p" flag.
1771 Otherwise, set promiscuous mode from the preferences setting. */
1772 /* the same applies to other preferences settings as well. */
1773 if (capture_opts->capture_child) {
1774 auto_scroll_live = FALSE;
1776 capture_opts->promisc_mode = prefs->capture_prom_mode;
1777 capture_opts->show_info = prefs->capture_show_info;
1778 capture_opts->sync_mode = prefs->capture_real_time;
1779 auto_scroll_live = prefs->capture_auto_scroll;
1782 #endif /* HAVE_LIBPCAP */
1784 /* Set the name resolution code's flags from the preferences. */
1785 g_resolv_flags = prefs->name_resolve;
1787 /* Read the capture filter file. */
1788 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1789 if (cf_path != NULL) {
1790 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1791 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1792 strerror(cf_open_errno));
1796 /* Read the display filter file. */
1797 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1798 if (df_path != NULL) {
1799 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1800 "Could not open your display filter file\n\"%s\": %s.", df_path,
1801 strerror(df_open_errno));
1805 /* Read the disabled protocols file. */
1806 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1807 &dp_path, &dp_open_errno, &dp_read_errno);
1808 if (gdp_path != NULL) {
1809 if (gdp_open_errno != 0) {
1810 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1811 "Could not open global disabled protocols file\n\"%s\": %s.",
1812 gdp_path, strerror(gdp_open_errno));
1814 if (gdp_read_errno != 0) {
1815 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1816 "I/O error reading global disabled protocols file\n\"%s\": %s.",
1817 gdp_path, strerror(gdp_read_errno));
1821 if (dp_path != NULL) {
1822 if (dp_open_errno != 0) {
1823 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1824 "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1825 strerror(dp_open_errno));
1827 if (dp_read_errno != 0) {
1828 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1829 "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
1830 strerror(dp_read_errno));
1835 init_cap_file(&cfile);
1838 /* Load wpcap if possible. Do this before collecting the run-time version information */
1841 /* Start windows sockets */
1842 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1845 /* Assemble the compile-time version information string */
1846 comp_info_str = g_string_new("Compiled ");
1847 g_string_append(comp_info_str, "with ");
1848 g_string_sprintfa(comp_info_str,
1849 #ifdef GTK_MAJOR_VERSION
1850 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1853 "GTK+ (version unknown)");
1856 g_string_append(comp_info_str, ", ");
1857 get_compiled_version_info(comp_info_str);
1859 /* Assemble the run-time version information string */
1860 runtime_info_str = g_string_new("Running ");
1861 get_runtime_version_info(runtime_info_str);
1863 /* Now get our args */
1864 while ((opt = getopt(argc, argv, optstring)) != -1) {
1866 /*** capture option specific ***/
1867 case 'a': /* autostop criteria */
1868 case 'b': /* Ringbuffer option */
1869 case 'c': /* Capture xxx packets */
1870 case 'f': /* capture filter */
1871 case 'k': /* Start capture immediately */
1872 case 'H': /* Hide capture info dialog box */
1873 case 'i': /* Use interface xxx */
1874 case 'p': /* Don't capture in promiscuous mode */
1875 case 'Q': /* Quit after capture (just capture to file) */
1876 case 's': /* Set the snapshot (capture) length */
1877 case 'S': /* "Sync" mode: used for following file ala tail -f */
1878 case 'w': /* Write to capture file xxx */
1879 case 'y': /* Set the pcap data link type */
1881 /* Hidden option supporting Sync mode */
1882 case 'Z': /* Write to pipe FD XXX */
1885 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
1887 capture_option_specified = TRUE;
1892 /* This is a hidden option supporting Sync mode, so we don't set
1893 * the error flags for the user in the non-libpcap case.
1895 case 'W': /* Write to capture file FD xxx */
1896 capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
1900 /*** all non capture option specific ***/
1901 case 'B': /* Byte view pane height */
1902 bv_size = get_positive_int(optarg, "byte view pane height");
1904 case 'h': /* Print help and exit */
1908 case 'l': /* Automatic scrolling in live capture mode */
1910 auto_scroll_live = TRUE;
1912 capture_option_specified = TRUE;
1916 case 'L': /* Print list of link-layer types and exit */
1918 list_link_layer_types = TRUE;
1920 capture_option_specified = TRUE;
1924 case 'm': /* Fixed-width font for the display */
1925 if (prefs->PREFS_GUI_FONT_NAME != NULL)
1926 g_free(prefs->PREFS_GUI_FONT_NAME);
1927 prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
1929 case 'n': /* No name resolution */
1930 g_resolv_flags = RESOLV_NONE;
1932 case 'N': /* Select what types of addresses/port #s to resolve */
1933 if (g_resolv_flags == RESOLV_ALL)
1934 g_resolv_flags = RESOLV_NONE;
1935 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1936 if (badopt != '\0') {
1937 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1942 case 'o': /* Override preference from command line */
1943 switch (prefs_set_pref(optarg)) {
1945 case PREFS_SET_SYNTAX_ERR:
1946 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1950 case PREFS_SET_NO_SUCH_PREF:
1951 case PREFS_SET_OBSOLETE:
1952 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1958 case 'P': /* Packet list pane height */
1959 pl_size = get_positive_int(optarg, "packet list pane height");
1961 case 'r': /* Read capture file xxx */
1962 /* We may set "last_open_dir" to "cf_name", and if we change
1963 "last_open_dir" later, we free the old value, so we have to
1964 set "cf_name" to something that's been allocated. */
1965 cf_name = g_strdup(optarg);
1967 case 'R': /* Read file filter */
1970 case 't': /* Time stamp type */
1971 if (strcmp(optarg, "r") == 0)
1972 set_timestamp_setting(TS_RELATIVE);
1973 else if (strcmp(optarg, "a") == 0)
1974 set_timestamp_setting(TS_ABSOLUTE);
1975 else if (strcmp(optarg, "ad") == 0)
1976 set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
1977 else if (strcmp(optarg, "d") == 0)
1978 set_timestamp_setting(TS_DELTA);
1980 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1982 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1983 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1987 case 'T': /* Tree view pane height */
1988 tv_size = get_positive_int(optarg, "tree view pane height");
1990 case 'v': /* Show version and exit */
1998 for(tli=tap_list;tli;tli=tli->next){
1999 if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
2000 tap_opt = g_strdup(optarg);
2005 fprintf(stderr,"ethereal: invalid -z argument.\n");
2006 fprintf(stderr," -z argument must be one of :\n");
2007 for(tli=tap_list;tli;tli=tli->next){
2008 fprintf(stderr," %s\n",tli->cmd);
2014 case '?': /* Bad flag - print usage message */
2022 if (cf_name != NULL) {
2024 * Input file name specified with "-r" *and* specified as a regular
2025 * command-line argument.
2030 * Input file name not specified with "-r", and a command-line argument
2031 * was specified; treat it as the input file name.
2033 * Yes, this is different from tethereal, where non-flag command-line
2034 * arguments are a filter, but this works better on GUI desktops
2035 * where a command can be specified to be run to open a particular
2036 * file - yes, you could have "-r" as the last part of the command,
2037 * but that's a bit ugly.
2039 cf_name = g_strdup(argv[0]);
2049 * Extra command line arguments were specified; complain.
2051 fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2056 #ifndef HAVE_LIBPCAP
2057 if (capture_option_specified) {
2058 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2066 if (start_capture && list_link_layer_types) {
2067 /* Specifying *both* is bogus. */
2068 fprintf(stderr, "ethereal: You can't specify both -L and a live capture.\n");
2072 if (list_link_layer_types) {
2073 /* We're supposed to list the link-layer types for an interface;
2074 did the user also specify a capture file to be read? */
2076 /* Yes - that's bogus. */
2077 fprintf(stderr, "ethereal: You can't specify -L and a capture file to be read.\n");
2080 /* No - did they specify a ring buffer option? */
2081 if (capture_opts->multi_files_on) {
2082 fprintf(stderr, "ethereal: Ring buffer requested, but a capture isn't being done.\n");
2086 /* We're supposed to do a live capture; did the user also specify
2087 a capture file to be read? */
2088 if (start_capture && cf_name) {
2089 /* Yes - that's bogus. */
2090 fprintf(stderr, "ethereal: You can't specify both a live capture and a capture file to be read.\n");
2094 /* No - was the ring buffer option specified and, if so, does it make
2096 if (capture_opts->multi_files_on) {
2097 /* Ring buffer works only under certain conditions:
2098 a) ring buffer does not work with temporary files;
2099 b) sync_mode and capture_opts->ringbuffer_on are mutually exclusive -
2100 sync_mode takes precedence;
2101 c) it makes no sense to enable the ring buffer if the maximum
2102 file size is set to "infinite". */
2103 if (capture_opts->save_file == NULL) {
2104 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2105 capture_opts->multi_files_on = FALSE;
2107 if (capture_opts->sync_mode) {
2108 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2109 capture_opts->multi_files_on = FALSE;
2111 if (!capture_opts->has_autostop_filesize) {
2112 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
2113 capture_opts->multi_files_on = FALSE;
2118 if (start_capture || list_link_layer_types) {
2119 /* Did the user specify an interface to use? */
2120 if (capture_opts->iface == NULL) {
2121 /* No - is a default specified in the preferences file? */
2122 if (prefs->capture_device != NULL) {
2124 capture_opts->iface = g_strdup(prefs->capture_device);
2126 /* No - pick the first one from the list of interfaces. */
2127 if_list = get_interface_list(&err, err_str);
2128 if (if_list == NULL) {
2131 case CANT_GET_INTERFACE_LIST:
2132 cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2133 fprintf(stderr, "%s\n", cant_get_if_list_errstr);
2134 g_free(cant_get_if_list_errstr);
2137 case NO_INTERFACES_FOUND:
2138 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2143 if_info = if_list->data; /* first interface */
2144 capture_opts->iface = g_strdup(if_info->name);
2145 free_interface_list(if_list);
2150 if (capture_opts->capture_child) {
2151 if (capture_opts->save_file_fd == -1) {
2152 /* XXX - send this to the standard output as something our parent
2153 should put in an error message box? */
2154 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2159 if (list_link_layer_types) {
2160 /* Get the list of link-layer types for the capture device. */
2161 lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2162 if (lt_list == NULL) {
2163 if (err_str[0] != '\0') {
2164 fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2165 "Please check to make sure you have sufficient permissions, and that\n"
2166 "you have the proper interface or pipe specified.\n", err_str);
2168 fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2171 fprintf(stderr, "Data link types (use option -y to set):\n");
2172 for (lt_entry = lt_list; lt_entry != NULL;
2173 lt_entry = g_list_next(lt_entry)) {
2174 data_link_info = lt_entry->data;
2175 fprintf(stderr, " %s", data_link_info->name);
2176 if (data_link_info->description != NULL)
2177 fprintf(stderr, " (%s)", data_link_info->description);
2179 fprintf(stderr, " (not supported)");
2182 free_pcap_linktype_list(lt_list);
2186 if (capture_opts->has_snaplen) {
2187 if (capture_opts->snaplen < 1)
2188 capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2189 else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2190 capture_opts->snaplen = MIN_PACKET_SIZE;
2193 /* Check the value range of the ringbuffer_num_files parameter */
2194 if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2195 capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2196 #if RINGBUFFER_MIN_NUM_FILES > 0
2197 else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2198 capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2200 #endif /* HAVE_LIBPCAP */
2202 /* Notify all registered modules that have had any of their preferences
2203 changed either from one of the preferences file or from the command
2204 line that their preferences have changed. */
2207 /* disabled protocols as per configuration file */
2208 if (gdp_path == NULL && dp_path == NULL) {
2209 set_disabled_protos_list();
2212 /* Build the column format array */
2213 col_setup(&cfile.cinfo, prefs->num_cols);
2214 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2215 cfile.cinfo.col_fmt[i] = get_column_format(i);
2216 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2217 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2219 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2220 cfile.cinfo.col_data[i] = NULL;
2221 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2222 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2224 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2225 cfile.cinfo.col_fence[i] = 0;
2226 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2227 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2230 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2233 for (j = 0; j < NUM_COL_FMTS; j++) {
2234 if (!cfile.cinfo.fmt_matx[i][j])
2237 if (cfile.cinfo.col_first[j] == -1)
2238 cfile.cinfo.col_first[j] = i;
2239 cfile.cinfo.col_last[j] = i;
2243 /* read in rc file from global and personal configuration paths. */
2244 /* XXX - is this a good idea? */
2245 gtk_rc_parse(RC_FILE);
2246 rc_file = get_persconffile_path(RC_FILE, FALSE);
2247 gtk_rc_parse(rc_file);
2250 font_init(capture_opts->capture_child);
2255 /* close the splash screen, as we are going to open the main window now */
2256 splash_destroy(splash_win);
2260 /* Is this a "child" ethereal, which is only supposed to pop up a
2261 capture box to let us stop the capture, and run a capture
2262 to a file that our parent will read? */
2263 if (capture_opts->capture_child) {
2264 /* This is the child process for a sync mode or fork mode capture,
2265 so just do the low-level work of a capture - don't create
2266 a temporary file and fork off *another* child process (so don't
2267 call "do_capture()"). */
2269 /* Pop up any queued-up alert boxes. */
2270 display_queued_messages();
2272 /* XXX - hand these stats to the parent process */
2273 capture_start(capture_opts, &stats_known, &stats);
2275 /* The capture is done; there's nothing more for us to do. */
2280 /***********************************************************************/
2281 /* Everything is prepared now, preferences and command line was read in,
2282 we are NOT a child window for a synced capture. */
2284 /* Pop up the main window, and read in a capture file if
2286 create_main_window(pl_size, tv_size, bv_size, prefs);
2288 /* Read the recent file, as we have the gui now ready for it. */
2289 read_recent(&rf_path, &rf_open_errno);
2291 /* rearrange all the widgets as we now have the recent settings for this */
2292 main_widgets_rearrange();
2294 /* Fill in column titles. This must be done after the top level window
2297 XXX - is that still true, with fixed-width columns? */
2298 packet_list_set_column_titles();
2300 menu_recent_read_finished();
2302 switch (user_font_apply()) {
2305 case FA_FONT_NOT_RESIZEABLE:
2306 /* "user_font_apply()" popped up an alert box. */
2307 /* turn off zooming - font can't be resized */
2308 case FA_FONT_NOT_AVAILABLE:
2309 /* XXX - did we successfully load the un-zoomed version earlier?
2310 If so, this *probably* means the font is available, but not at
2311 this particular zoom level, but perhaps some other failure
2312 occurred; I'm not sure you can determine which is the case,
2314 /* turn off zooming - zoom level is unavailable */
2316 /* in any other case than FA_SUCCESS, turn off zooming */
2317 recent.gui_zoom_level = 0;
2318 /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2321 dnd_init(top_level);
2327 /* the window can be sized only, if it's not already shown, so do it now! */
2328 main_load_window_geometry(top_level);
2330 /* If we were given the name of a capture file, read it in now;
2331 we defer it until now, so that, if we can't open it, and pop
2332 up an alert box, the alert box is more likely to come up on
2333 top of the main window - but before the preference-file-error
2334 alert box, so, if we get one of those, it's more likely to come
2337 show_main_window(TRUE);
2338 if (rfilter != NULL) {
2339 if (!dfilter_compile(rfilter, &rfcode)) {
2340 bad_dfilter_alert_box(rfilter);
2341 rfilter_parse_failed = TRUE;
2344 if (!rfilter_parse_failed) {
2345 if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2346 /* "cf_open()" succeeded, so it closed the previous
2347 capture file, and thus destroyed any previous read filter
2348 attached to "cf". */
2350 cfile.rfcode = rfcode;
2351 /* Open tap windows; we do so after creating the main window,
2352 to avoid GTK warnings, and after successfully opening the
2353 capture file, so we know we have something to tap. */
2354 if (tap_opt && tli) {
2355 (*tli->func)(tap_opt);
2359 /* Read the capture file. */
2360 switch (cf_read(&cfile)) {
2364 /* Just because we got an error, that doesn't mean we were unable
2365 to read any of the file; we handle what we could get from the
2369 case CF_READ_ABORTED:
2374 /* Save the name of the containing directory specified in the
2375 path name, if any; we can write over cf_name, which is a
2376 good thing, given that "get_dirname()" does write over its
2378 s = get_dirname(cf_name);
2379 /* we might already set this from the recent file, don't overwrite this */
2380 if(get_last_open_dir() == NULL)
2381 set_last_open_dir(s);
2386 dfilter_free(rfcode);
2387 cfile.rfcode = NULL;
2392 if (start_capture) {
2393 if (capture_opts->save_file != NULL) {
2394 /* Save the directory name for future file dialogs. */
2395 /* (get_dirname overwrites filename) */
2396 s = get_dirname(g_strdup(capture_opts->save_file));
2397 set_last_open_dir(s);
2400 /* "-k" was specified; start a capture. */
2401 show_main_window(TRUE);
2402 if (do_capture(capture_opts)) {
2403 /* The capture started. Open tap windows; we do so after creating
2404 the main window, to avoid GTK warnings, and after starting the
2405 capture, so we know we have something to tap. */
2406 if (tap_opt && tli) {
2407 (*tli->func)(tap_opt);
2413 show_main_window(FALSE);
2414 set_menus_for_capture_in_progress(FALSE);
2417 /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2418 if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2419 if (capture_opts->cfilter) {
2420 g_free(capture_opts->cfilter);
2422 capture_opts->cfilter = g_strdup(get_conn_cfilter());
2424 #else /* HAVE_LIBPCAP */
2425 show_main_window(FALSE);
2426 set_menus_for_capture_in_progress(FALSE);
2427 #endif /* HAVE_LIBPCAP */
2436 /* Shutdown windows sockets */
2439 /* For some unknown reason, the "atexit()" call in "create_console()"
2440 doesn't arrange that "destroy_console()" be called when we exit,
2441 so we call it here if a console was created. */
2447 /* This isn't reached, but we need it to keep GCC from complaining
2448 that "main()" returns without returning a value - it knows that
2449 "exit()" never returns, but it doesn't know that "gtk_exit()"
2450 doesn't, as GTK+ doesn't declare it with the attribute
2452 return 0; /* not reached */
2457 /* We build this as a GUI subsystem application on Win32, so
2458 "WinMain()", not "main()", gets called.
2460 Hack shamelessly stolen from the Win32 port of the GIMP. */
2462 #define _stdcall __attribute__((stdcall))
2466 WinMain (struct HINSTANCE__ *hInstance,
2467 struct HINSTANCE__ *hPrevInstance,
2471 has_console = FALSE;
2472 return main (__argc, __argv);
2476 * If this application has no console window to which its standard output
2477 * would go, create one.
2480 create_console(void)
2482 if (!has_console && prefs.gui_console_open != console_open_never) {
2483 /* We have no console to which to print the version string, so
2484 create one and make it the standard input, output, and error. */
2485 if (!AllocConsole())
2486 return; /* couldn't create console */
2487 freopen("CONIN$", "r", stdin);
2488 freopen("CONOUT$", "w", stdout);
2489 freopen("CONOUT$", "w", stderr);
2491 /* Well, we have a console now. */
2494 /* Now register "destroy_console()" as a routine to be called just
2495 before the application exits, so that we can destroy the console
2496 after the user has typed a key (so that the console doesn't just
2497 disappear out from under them, giving the user no chance to see
2498 the message(s) we put in there). */
2499 atexit(destroy_console);
2504 destroy_console(void)
2507 printf("\n\nPress any key to exit\n");
2513 /* This routine should not be necessary, at least as I read the GLib
2514 source code, as it looks as if GLib is, on Win32, *supposed* to
2515 create a console window into which to display its output.
2517 That doesn't happen, however. I suspect there's something completely
2518 broken about that code in GLib-for-Win32, and that it may be related
2519 to the breakage that forces us to just call "printf()" on the message
2520 rather than passing the message on to "g_log_default_handler()"
2521 (which is the routine that does the aforementioned non-functional
2522 console window creation). */
2524 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2525 const char *message, gpointer user_data)
2529 /* For some unknown reason, the above doesn't appear to actually cause
2530 anything to be sent to the standard output, so we'll just splat the
2531 message out directly, just to make sure it gets out. */
2532 printf("%s\n", message);
2534 g_log_default_handler(log_domain, log_level, message, user_data);
2539 GtkWidget *info_bar_new(void)
2541 /* tip: tooltips don't work on statusbars! */
2542 info_bar = gtk_statusbar_new();
2543 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2544 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2545 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2546 #if GTK_MAJOR_VERSION >= 2
2547 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2549 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2554 GtkWidget *packets_bar_new(void)
2556 /* tip: tooltips don't work on statusbars! */
2557 packets_bar = gtk_statusbar_new();
2558 packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2559 packets_bar_update();
2566 * Helper for main_widgets_rearrange()
2568 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2569 gtk_container_remove(GTK_CONTAINER(data), widget);
2572 GtkWidget *main_widget_layout(gint layout_content)
2574 switch(layout_content) {
2575 case(layout_pane_content_none):
2578 case(layout_pane_content_plist):
2581 case(layout_pane_content_pdetails):
2584 case(layout_pane_content_pbytes):
2588 g_assert_not_reached();
2595 * Rearrange the main window widgets
2597 void main_widgets_rearrange(void) {
2598 GtkWidget *first_pane_widget1, *first_pane_widget2;
2599 GtkWidget *second_pane_widget1, *second_pane_widget2;
2600 gboolean split_top_left;
2602 /* be a bit faster */
2603 gtk_widget_hide(main_vbox);
2605 /* be sure, we don't loose a widget while rearranging */
2606 gtk_widget_ref(menubar);
2607 gtk_widget_ref(main_tb);
2608 gtk_widget_ref(filter_tb);
2609 gtk_widget_ref(pkt_scrollw);
2610 gtk_widget_ref(tv_scrollw);
2611 gtk_widget_ref(byte_nb_ptr);
2612 gtk_widget_ref(stat_hbox);
2613 gtk_widget_ref(info_bar);
2614 gtk_widget_ref(packets_bar);
2615 gtk_widget_ref(status_pane);
2616 gtk_widget_ref(main_pane_v1);
2617 gtk_widget_ref(main_pane_v2);
2618 gtk_widget_ref(main_pane_h1);
2619 gtk_widget_ref(main_pane_h2);
2620 gtk_widget_ref(welcome_pane);
2622 /* empty all containers participating */
2623 gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
2624 gtk_container_foreach(GTK_CONTAINER(stat_hbox), foreach_remove_a_child, stat_hbox);
2625 gtk_container_foreach(GTK_CONTAINER(status_pane), foreach_remove_a_child, status_pane);
2626 gtk_container_foreach(GTK_CONTAINER(main_pane_v1), foreach_remove_a_child, main_pane_v1);
2627 gtk_container_foreach(GTK_CONTAINER(main_pane_v2), foreach_remove_a_child, main_pane_v2);
2628 gtk_container_foreach(GTK_CONTAINER(main_pane_h1), foreach_remove_a_child, main_pane_h1);
2629 gtk_container_foreach(GTK_CONTAINER(main_pane_h2), foreach_remove_a_child, main_pane_h2);
2631 /* add the menubar always at the top */
2632 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2635 gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2637 /* filter toolbar in toolbar area */
2638 if (!prefs.filter_toolbar_show_in_statusbar) {
2639 gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2642 /* fill the main layout panes */
2643 switch(prefs.gui_layout_type) {
2644 case(layout_type_5):
2645 main_first_pane = main_pane_v1;
2646 main_second_pane = main_pane_v2;
2647 split_top_left = FALSE;
2649 case(layout_type_2):
2650 main_first_pane = main_pane_v1;
2651 main_second_pane = main_pane_h1;
2652 split_top_left = FALSE;
2654 case(layout_type_1):
2655 main_first_pane = main_pane_v1;
2656 main_second_pane = main_pane_h1;
2657 split_top_left = TRUE;
2659 case(layout_type_4):
2660 main_first_pane = main_pane_h1;
2661 main_second_pane = main_pane_v1;
2662 split_top_left = FALSE;
2664 case(layout_type_3):
2665 main_first_pane = main_pane_h1;
2666 main_second_pane = main_pane_v1;
2667 split_top_left = TRUE;
2669 case(layout_type_6):
2670 main_first_pane = main_pane_h1;
2671 main_second_pane = main_pane_h2;
2672 split_top_left = FALSE;
2675 main_first_pane = NULL;
2676 main_second_pane = NULL;
2677 split_top_left = FALSE;
2678 g_assert_not_reached();
2680 if (split_top_left) {
2681 first_pane_widget1 = main_second_pane;
2682 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2683 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2684 first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2686 first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2687 first_pane_widget2 = main_second_pane;
2688 second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2689 second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2691 if (first_pane_widget1 != NULL)
2692 gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2693 if (first_pane_widget2 != NULL)
2694 gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2695 if (second_pane_widget1 != NULL)
2696 gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2697 if (second_pane_widget2 != NULL)
2698 gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2700 gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2703 gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2705 /* statusbar hbox */
2706 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2708 /* filter toolbar in statusbar hbox */
2709 if (prefs.filter_toolbar_show_in_statusbar) {
2710 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2714 gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2715 gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2716 gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2718 /* hide widgets on users recent settings */
2719 main_widgets_show_or_hide();
2721 gtk_widget_show(main_vbox);
2725 is_widget_visible(GtkWidget *widget, gpointer data)
2727 gboolean *is_visible = data;
2730 if (GTK_WIDGET_VISIBLE(widget))
2737 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2738 As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2740 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2742 GtkWidget *w, *item_hb;
2743 #if GTK_MAJOR_VERSION >= 2
2744 gchar *formatted_message;
2748 item_hb = gtk_hbox_new(FALSE, 1);
2750 w = BUTTON_NEW_FROM_STOCK(stock_item);
2751 WIDGET_SET_SIZE(w, 60, 60);
2752 #if GTK_MAJOR_VERSION >= 2
2753 gtk_button_set_label(GTK_BUTTON(w), label);
2755 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
2756 SIGNAL_CONNECT(w, "clicked", callback, callback_data);
2758 w = gtk_label_new(message);
2759 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2760 #if GTK_MAJOR_VERSION >= 2
2761 formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
2762 gtk_label_set_markup(GTK_LABEL(w), formatted_message);
2763 g_free(formatted_message);
2766 gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
2772 /* XXX - the layout has to be improved */
2776 GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
2777 GtkWidget *w, *icon;
2781 welcome_scrollw = scrolled_window_new(NULL, NULL);
2783 welcome_hb = gtk_hbox_new(FALSE, 1);
2784 /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
2786 welcome_vb = gtk_vbox_new(FALSE, 1);
2788 item_hb = gtk_hbox_new(FALSE, 1);
2790 icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
2791 gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
2793 #if GTK_MAJOR_VERSION < 2
2794 message = "Welcome to Ethereal!";
2796 message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
2798 w = gtk_label_new(message);
2799 #if GTK_MAJOR_VERSION >= 2
2800 gtk_label_set_markup(GTK_LABEL(w), message);
2802 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2803 gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
2805 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2807 w = gtk_label_new("What would you like to do?");
2808 gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
2809 gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
2812 item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
2814 "Capture live data from your network",
2815 GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
2816 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2819 item_hb = welcome_item(GTK_STOCK_OPEN,
2821 "Open a previously captured file",
2822 GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
2823 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2825 #if (GLIB_MAJOR_VERSION >= 2)
2826 item_hb = welcome_item(GTK_STOCK_HOME,
2828 "Visit the Ethereal homepage",
2829 GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
2830 gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2834 w = gtk_label_new("");
2835 gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
2837 w = gtk_label_new("");
2838 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
2840 gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
2842 w = gtk_label_new("");
2843 gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
2845 gtk_widget_show_all(welcome_hb);
2847 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
2849 gtk_widget_show_all(welcome_scrollw);
2851 return welcome_scrollw;
2858 /* this is just a dummy to fill up window space, simply showing nothing */
2859 return scrolled_window_new(NULL, NULL);
2865 * XXX - this doesn't appear to work with the paned widgets in
2866 * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
2867 * and the other pane doesn't grow to take up the rest of the pane.
2868 * It does appear to work with GTK+ 2.x.
2871 main_widgets_show_or_hide(void)
2873 gboolean main_second_pane_show;
2875 if (recent.main_toolbar_show) {
2876 gtk_widget_show(main_tb);
2878 gtk_widget_hide(main_tb);
2882 * Show the status hbox if either:
2884 * 1) we're showing the filter toolbar and we want it in the status
2889 * 2) we're showing the status bar.
2891 if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
2892 recent.statusbar_show) {
2893 gtk_widget_show(stat_hbox);
2895 gtk_widget_hide(stat_hbox);
2898 if (recent.statusbar_show) {
2899 gtk_widget_show(status_pane);
2901 gtk_widget_hide(status_pane);
2904 if (recent.filter_toolbar_show) {
2905 gtk_widget_show(filter_tb);
2907 gtk_widget_hide(filter_tb);
2910 if (recent.packet_list_show && have_capture_file) {
2911 gtk_widget_show(pkt_scrollw);
2913 gtk_widget_hide(pkt_scrollw);
2916 if (recent.tree_view_show && have_capture_file) {
2917 gtk_widget_show(tv_scrollw);
2919 gtk_widget_hide(tv_scrollw);
2922 if (recent.byte_view_show && have_capture_file) {
2923 gtk_widget_show(byte_nb_ptr);
2925 gtk_widget_hide(byte_nb_ptr);
2928 if (have_capture_file) {
2929 gtk_widget_show(main_first_pane);
2931 gtk_widget_hide(main_first_pane);
2935 * Is anything in "main_second_pane" visible?
2936 * If so, show it, otherwise hide it.
2938 main_second_pane_show = FALSE;
2939 gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
2940 &main_second_pane_show);
2941 if (main_second_pane_show) {
2942 gtk_widget_show(main_second_pane);
2944 gtk_widget_hide(main_second_pane);
2947 if (!have_capture_file) {
2949 gtk_widget_show(welcome_pane);
2952 gtk_widget_hide(welcome_pane);
2957 #if GTK_MAJOR_VERSION >= 2
2958 /* called, when the window state changes (minimized, maximized, ...) */
2960 window_state_event_cb (GtkWidget *widget _U_,
2964 GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
2966 if( (event->type) == (GDK_WINDOW_STATE)) {
2967 if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
2968 /* we might have dialogs popped up while we where iconified,
2970 display_queued_messages();
2979 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2982 *filter_bt, *filter_cm, *filter_te,
2983 *filter_add_expr_bt,
2986 GList *filter_list = NULL;
2987 GtkTooltips *tooltips;
2988 GtkAccelGroup *accel;
2990 /* Display filter construct dialog has an Apply button, and "OK" not
2991 only sets our text widget, it activates it (i.e., it causes us to
2992 filter the capture). */
2993 static construct_args_t args = {
2994 "Ethereal: Display Filter",
2999 /* use user-defined title if preference is set */
3000 title = create_user_window_title("The Ethereal Network Analyzer");
3003 top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3006 tooltips = gtk_tooltips_new();
3009 #if GTK_MAJOR_VERSION < 2
3010 /* has to be done, after top_level window is created */
3011 app_font_gtk1_init(top_level);
3015 gtk_widget_set_name(top_level, "main window");
3016 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3018 #if GTK_MAJOR_VERSION >= 2
3019 SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3020 G_CALLBACK (window_state_event_cb), NULL);
3023 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3025 /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3026 main_vbox = gtk_vbox_new(FALSE, 1);
3027 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3028 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3029 gtk_widget_show(main_vbox);
3032 menubar = main_menu_new(&accel);
3033 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3034 gtk_widget_show(menubar);
3037 main_tb = toolbar_new();
3038 gtk_widget_show (main_tb);
3041 pkt_scrollw = packet_list_new(prefs);
3042 WIDGET_SET_SIZE(packet_list, -1, pl_size);
3043 gtk_widget_show(pkt_scrollw);
3046 tv_scrollw = main_tree_view_new(prefs, &tree_view);
3047 WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3048 gtk_widget_show(tv_scrollw);
3050 #if GTK_MAJOR_VERSION < 2
3051 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3052 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3055 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3056 "changed", tree_view_selection_changed_cb, NULL);
3058 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3059 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3060 gtk_widget_show(tree_view);
3063 byte_nb_ptr = byte_view_new();
3064 WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3065 gtk_widget_show(byte_nb_ptr);
3067 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3068 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3071 /* Panes for the packet list, tree, and byte view */
3072 main_pane_v1 = gtk_vpaned_new();
3073 gtk_widget_show(main_pane_v1);
3074 main_pane_v2 = gtk_vpaned_new();
3075 gtk_widget_show(main_pane_v2);
3076 main_pane_h1 = gtk_hpaned_new();
3077 gtk_widget_show(main_pane_h1);
3078 main_pane_h2 = gtk_hpaned_new();
3079 gtk_widget_show(main_pane_h2);
3081 /* filter toolbar */
3082 #if GTK_MAJOR_VERSION < 2
3083 filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3086 filter_tb = gtk_toolbar_new();
3087 gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3088 GTK_ORIENTATION_HORIZONTAL);
3089 #endif /* GTK_MAJOR_VERSION */
3090 gtk_widget_show(filter_tb);
3092 /* Create the "Filter:" button */
3093 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3094 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3095 gtk_widget_show(filter_bt);
3096 OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3098 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt,
3099 "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3101 /* Create the filter combobox */
3102 filter_cm = gtk_combo_new();
3104 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3105 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3106 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
3107 filter_te = GTK_COMBO(filter_cm)->entry;
3108 main_display_filter_widget=filter_te;
3109 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3110 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3111 OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3112 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3113 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3114 WIDGET_SET_SIZE(filter_cm, 400, -1);
3115 gtk_widget_show(filter_cm);
3116 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm,
3118 /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3119 gtk_tooltips_set_tip(tooltips, filter_te,
3120 "Enter a display filter, or choose one of your recently used filters. "
3121 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
3124 /* Create the "Add Expression..." button, to pop up a dialog
3125 for constructing filter comparison expressions. */
3126 filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3127 OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3128 SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3129 gtk_widget_show(filter_add_expr_bt);
3130 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt,
3131 "Add an expression to this filter string", "Private");
3133 /* Create the "Clear" button */
3134 filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3135 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3136 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3137 gtk_widget_show(filter_reset);
3138 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset,
3139 "Clear this filter string and update the display", "Private");
3141 /* Create the "Apply" button */
3142 filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3143 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3144 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3145 gtk_widget_show(filter_apply);
3146 gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply,
3147 "Apply this filter string to the display", "Private");
3149 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3150 * of any widget that ends up calling a callback which needs
3151 * that text entry pointer */
3152 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3153 set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3155 set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3157 set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3159 set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3161 set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3163 set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3165 set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3167 set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3169 set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3171 set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3173 set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3175 set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3177 set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3179 set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3181 set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3182 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3183 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3185 /* info (main) statusbar */
3186 info_bar = info_bar_new();
3187 gtk_widget_show(info_bar);
3189 /* packets statusbar */
3190 packets_bar = packets_bar_new();
3191 gtk_widget_show(packets_bar);
3193 /* Filter/status hbox */
3194 stat_hbox = gtk_hbox_new(FALSE, 1);
3195 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3196 gtk_widget_show(stat_hbox);
3198 /* Pane for the statusbar */
3199 status_pane = gtk_hpaned_new();
3200 gtk_widget_show(status_pane);
3202 /* Pane for the welcome screen */
3203 welcome_pane = welcome_new();
3204 gtk_widget_show(welcome_pane);
3208 show_main_window(gboolean doing_work)
3210 main_set_for_capture_file(doing_work);
3212 /*** we have finished all init things, show the main window ***/
3213 gtk_widget_show(top_level);
3215 /* the window can be maximized only, if it's visible, so do it after show! */
3216 main_load_window_geometry(top_level);
3218 /* process all pending GUI events before continue */
3219 while (gtk_events_pending()) gtk_main_iteration();
3221 /* Pop up any queued-up alert boxes. */
3222 display_queued_messages();