3 * $Id: main.c,v 1.296 2003/06/08 09:12:23 oabad 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?
52 #include <io.h> /* open/close on win32 */
59 #ifdef NEED_SNPRINTF_H
60 # include "snprintf.h"
63 #ifdef NEED_STRERROR_H
71 #ifdef WIN32 /* Needed for console I/O */
76 #include <epan/epan.h>
77 #include <epan/filesystem.h>
78 #include <epan/epan_dissect.h>
81 #include <epan/timestamp.h>
82 #include <epan/packet.h>
91 #include "color_filters.h"
92 #include "color_utils.h"
93 #include "filter_prefs.h"
97 #include <epan/resolv.h>
99 #include "pcap-util.h"
101 #include "statusbar.h"
102 #include "simple_dialog.h"
103 #include "proto_draw.h"
104 #include <epan/dfilter/dfilter.h>
106 #include "packet_win.h"
107 #include "gtkglobals.h"
108 #include <epan/plugins.h>
110 #include <epan/strutil.h>
111 #include "register.h"
112 #include "ringbuffer.h"
114 #include "image/clist_ascend.xpm"
115 #include "image/clist_descend.xpm"
118 #include "compat_macros.h"
121 #include "capture-wpcap.h"
124 typedef struct column_arrows {
126 GtkWidget *ascend_pm;
127 GtkWidget *descend_pm;
131 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
132 *tv_scrollw, *pkt_scrollw;
133 static GtkWidget *info_bar;
134 #if GTK_MAJOR_VERSION < 2
135 GdkFont *m_r_font, *m_b_font;
136 guint m_font_height, m_font_width;
138 PangoFontDescription *m_r_font, *m_b_font;
140 static guint main_ctx, file_ctx, help_ctx;
141 static GString *comp_info_str, *runtime_info_str;
142 gchar *ethereal_path = NULL;
143 gchar *last_open_dir = NULL;
144 gint root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
146 ts_type timestamp_type = RELATIVE;
148 #if GTK_MAJOR_VERSION < 2
149 GtkStyle *item_style;
152 /* Specifies the field currently selected in the GUI protocol tree */
153 field_info *finfo_selected = NULL;
156 static gboolean has_no_console; /* TRUE if app has no console */
157 static gboolean console_was_created; /* TRUE if console was created */
158 static void create_console(void);
159 static void destroy_console(void);
160 static void console_log_handler(const char *log_domain,
161 GLogLevelFlags log_level, const char *message, gpointer user_data);
164 static void create_main_window(gint, gint, gint, e_prefs*);
166 #define E_DFILTER_CM_KEY "display_filter_combo"
167 #define E_DFILTER_FL_KEY "display_filter_list"
169 /* About Ethereal window */
171 about_ethereal( GtkWidget *w _U_, gpointer data _U_ ) {
172 simple_dialog(ESD_TYPE_INFO, NULL,
173 "Ethereal - Network Protocol Analyzer\n"
174 "Version " VERSION " (C) 1998-2003 Gerald Combs <gerald@ethereal.com>\n"
177 "Check the man page for complete documentation and\n"
178 "for the list of contributors.\n"
180 "\nSee http://www.ethereal.com/ for more information.",
181 comp_info_str->str, runtime_info_str->str);
184 #if GTK_MAJOR_VERSION < 2
186 set_fonts(GdkFont *regular, GdkFont *bold)
189 set_fonts(PangoFontDescription *regular, PangoFontDescription *bold)
192 /* Yes, assert. The code that loads the font should check
193 * for NULL and provide its own error message. */
194 g_assert(m_r_font && m_b_font);
198 #if GTK_MAJOR_VERSION < 2
199 m_font_height = m_r_font->ascent + m_r_font->descent;
200 m_font_width = gdk_string_width(m_r_font, "0");
205 * Go to frame specified by currently selected protocol tree item.
208 goto_framenum_cb(GtkWidget *w _U_, gpointer data _U_)
210 if (finfo_selected) {
211 header_field_info *hfinfo;
214 hfinfo = finfo_selected->hfinfo;
216 if (hfinfo->type == FT_FRAMENUM) {
217 framenum = fvalue_get_integer(finfo_selected->value);
219 goto_frame(&cfile, framenum);
224 /* Match selected byte pattern */
226 match_selected_cb_do(gpointer data, int action, gchar *text)
228 GtkWidget *filter_te;
229 char *cur_filter, *new_filter;
234 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
237 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
239 switch (action&MATCH_SELECTED_MASK) {
241 case MATCH_SELECTED_REPLACE:
242 new_filter = g_strdup(text);
245 case MATCH_SELECTED_AND:
246 if ((!cur_filter) || (0 == strlen(cur_filter)))
247 new_filter = g_strdup(text);
249 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
252 case MATCH_SELECTED_OR:
253 if ((!cur_filter) || (0 == strlen(cur_filter)))
254 new_filter = g_strdup(text);
256 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
259 case MATCH_SELECTED_NOT:
260 new_filter = g_strconcat("!(", text, ")", NULL);
263 case MATCH_SELECTED_AND_NOT:
264 if ((!cur_filter) || (0 == strlen(cur_filter)))
265 new_filter = g_strconcat("!(", text, ")", NULL);
267 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
270 case MATCH_SELECTED_OR_NOT:
271 if ((!cur_filter) || (0 == strlen(cur_filter)))
272 new_filter = g_strconcat("!(", text, ")", NULL);
274 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
278 g_assert_not_reached();
283 /* Free up the copy we got of the old filter text. */
286 /* create a new one and set the display filter entry accordingly */
287 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
289 /* Run the display filter so it goes in effect. */
290 if (action&MATCH_SELECTED_APPLY_NOW)
291 filter_packets(&cfile, new_filter);
293 /* Free up the new filter text. */
296 /* Free up the generated text we were handed. */
301 match_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
304 match_selected_cb_do((data ? data : w),
305 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
306 proto_construct_dfilter_string(finfo_selected, cfile.edt));
310 match_selected_cb_and_ptree(GtkWidget *w, gpointer data)
313 match_selected_cb_do((data ? data : w),
314 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
315 proto_construct_dfilter_string(finfo_selected, cfile.edt));
319 match_selected_cb_or_ptree(GtkWidget *w, gpointer data)
322 match_selected_cb_do((data ? data : w),
323 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
324 proto_construct_dfilter_string(finfo_selected, cfile.edt));
328 match_selected_cb_not_ptree(GtkWidget *w, gpointer data)
331 match_selected_cb_do((data ? data : w),
332 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
333 proto_construct_dfilter_string(finfo_selected, cfile.edt));
337 match_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
340 match_selected_cb_do((data ? data : w),
341 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
342 proto_construct_dfilter_string(finfo_selected, cfile.edt));
346 match_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
349 match_selected_cb_do((data ? data : w),
350 MATCH_SELECTED_OR_NOT,
351 proto_construct_dfilter_string(finfo_selected, cfile.edt));
355 prepare_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
358 match_selected_cb_do((data ? data : w),
359 MATCH_SELECTED_REPLACE,
360 proto_construct_dfilter_string(finfo_selected, cfile.edt));
364 prepare_selected_cb_and_ptree(GtkWidget *w, gpointer data)
367 match_selected_cb_do((data ? data : w),
369 proto_construct_dfilter_string(finfo_selected, cfile.edt));
373 prepare_selected_cb_or_ptree(GtkWidget *w, gpointer data)
376 match_selected_cb_do((data ? data : w),
378 proto_construct_dfilter_string(finfo_selected, cfile.edt));
382 prepare_selected_cb_not_ptree(GtkWidget *w, gpointer data)
385 match_selected_cb_do((data ? data : w),
387 proto_construct_dfilter_string(finfo_selected, cfile.edt));
391 prepare_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
394 match_selected_cb_do((data ? data : w),
395 MATCH_SELECTED_AND_NOT,
396 proto_construct_dfilter_string(finfo_selected, cfile.edt));
400 prepare_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
403 match_selected_cb_do((data ? data : w),
404 MATCH_SELECTED_OR_NOT,
405 proto_construct_dfilter_string(finfo_selected, cfile.edt));
409 get_text_from_packet_list(gpointer data)
411 gint row = (gint)OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY);
412 gint column = (gint)OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY);
413 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
420 /* XXX - do something with "err" */
421 wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
422 cfile.pd, fdata->cap_len, &err);
424 edt = epan_dissect_new(FALSE, FALSE);
425 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
427 epan_dissect_fill_in_columns(edt);
429 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
430 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
431 len = strlen(cfile.cinfo.col_expr[column]) +
432 strlen(cfile.cinfo.col_expr_val[column]) + 5;
433 buf = g_malloc0(len);
434 snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
435 cfile.cinfo.col_expr_val[column]);
438 epan_dissect_free(edt);
445 match_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
447 match_selected_cb_do(data,
448 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
449 get_text_from_packet_list(data));
453 match_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
455 match_selected_cb_do(data,
456 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
457 get_text_from_packet_list(data));
461 match_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
463 match_selected_cb_do(data,
464 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
465 get_text_from_packet_list(data));
469 match_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
471 match_selected_cb_do(data,
472 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
473 get_text_from_packet_list(data));
477 match_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
479 match_selected_cb_do(data,
480 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
481 get_text_from_packet_list(data));
485 match_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
487 match_selected_cb_do(data,
488 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
489 get_text_from_packet_list(data));
493 prepare_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
495 match_selected_cb_do(data,
496 MATCH_SELECTED_REPLACE,
497 get_text_from_packet_list(data));
501 prepare_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
503 match_selected_cb_do(data,
505 get_text_from_packet_list(data));
509 prepare_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
511 match_selected_cb_do(data,
513 get_text_from_packet_list(data));
517 prepare_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
519 match_selected_cb_do(data,
521 get_text_from_packet_list(data));
525 prepare_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
527 match_selected_cb_do(data,
528 MATCH_SELECTED_AND_NOT,
529 get_text_from_packet_list(data));
533 prepare_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
535 match_selected_cb_do(data,
536 MATCH_SELECTED_OR_NOT,
537 get_text_from_packet_list(data));
540 /* Run the current display filter on the current packet set, and
543 filter_activate_cb(GtkWidget *w, gpointer data)
545 GtkCombo *filter_cm = OBJECT_GET_DATA(w, E_DFILTER_CM_KEY);
546 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
548 gboolean add_filter = TRUE;
549 gboolean free_filter = TRUE;
553 s = g_strdup(gtk_entry_get_text(GTK_ENTRY(data)));
555 /* GtkCombos don't let us get at their list contents easily, so we maintain
556 our own filter list, and feed it to gtk_combo_set_popdown_strings when
557 a new filter is added. */
558 if (filter_packets(&cfile, s)) {
559 li = g_list_first(filter_list);
561 if (li->data && strcmp(s, li->data) == 0)
568 filter_list = g_list_append(filter_list, s);
569 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
570 gtk_combo_set_popdown_strings(filter_cm, filter_list);
571 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
578 /* redisplay with no display filter */
580 filter_reset_cb(GtkWidget *w, gpointer data _U_)
582 GtkWidget *filter_te = NULL;
584 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
585 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
587 filter_packets(&cfile, NULL);
590 /* GTKClist compare routine, overrides default to allow numeric comparison */
592 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
594 /* Get row text strings */
595 char *text1 = GTK_CELL_TEXT (((const GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
596 char *text2 = GTK_CELL_TEXT (((const GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
598 /* Attempt to convert to numbers */
599 double num1 = atof(text1);
600 double num2 = atof(text2);
602 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
604 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
605 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
606 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
607 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
608 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
609 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
610 (col_fmt == COL_PACKET_LENGTH)) {
612 /* Compare numeric column */
616 else if (num1 > num2)
624 /* Compare text column */
626 return (text1 != NULL);
631 return strcmp(text1, text2);
635 /* What to do when a column is clicked */
637 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
639 column_arrows *col_arrows = (column_arrows *) data;
642 gtk_clist_freeze(clist);
644 for (i = 0; i < cfile.cinfo.num_cols; i++) {
645 gtk_widget_hide(col_arrows[i].ascend_pm);
646 gtk_widget_hide(col_arrows[i].descend_pm);
649 if (column == clist->sort_column) {
650 if (clist->sort_type == GTK_SORT_ASCENDING) {
651 clist->sort_type = GTK_SORT_DESCENDING;
652 gtk_widget_show(col_arrows[column].descend_pm);
654 clist->sort_type = GTK_SORT_ASCENDING;
655 gtk_widget_show(col_arrows[column].ascend_pm);
659 clist->sort_type = GTK_SORT_ASCENDING;
660 gtk_widget_show(col_arrows[column].ascend_pm);
661 gtk_clist_set_sort_column(clist, column);
663 gtk_clist_thaw(clist);
665 gtk_clist_sort(clist);
670 set_frame_mark(gboolean set, frame_data *frame, gint row) {
676 mark_frame(&cfile, frame);
677 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
678 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
679 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
680 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
682 unmark_frame(&cfile, frame);
683 gtk_clist_set_background(GTK_CLIST(packet_list), row, NULL);
684 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, NULL);
686 file_set_save_marked_sensitive();
689 #if GTK_MAJOR_VERSION < 2
691 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
693 GdkEventButton *event_button = (GdkEventButton *)event;
696 if (w == NULL || event == NULL)
699 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
700 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
701 event_button->y, &row, &column)) {
702 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w),
704 set_frame_mark(!fdata->flags.marked, fdata, row);
709 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
711 GdkEventButton *event_button = (GdkEventButton *)event;
714 if (w == NULL || event == NULL)
717 if (event->type == GDK_BUTTON_PRESS &&
718 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
719 event_button->y, &row, &column)) {
720 if (event_button->button == 2)
722 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w), row);
723 set_frame_mark(!fdata->flags.marked, fdata, row);
726 else if (event_button->button == 1) {
727 gtk_clist_select_row(GTK_CLIST(w), row, column);
735 void mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
736 if (cfile.current_frame) {
737 /* XXX hum, should better have a "cfile->current_row" here ... */
738 set_frame_mark(!cfile.current_frame->flags.marked,
740 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
741 cfile.current_frame));
745 static void mark_all_frames(gboolean set) {
747 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
750 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
754 void update_marked_frames(void) {
756 if (cfile.plist == NULL) return;
757 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
758 if (fdata->flags.marked)
761 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
766 void mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
767 mark_all_frames(TRUE);
770 void unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
771 mark_all_frames(FALSE);
774 /* What to do when a list item is selected/unselected */
776 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
778 /* Remove the hex display tabbed pages */
779 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
780 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
782 select_packet(&cfile, row);
787 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
789 unselect_packet(&cfile);
793 #if GTK_MAJOR_VERSION < 2
795 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
796 gpointer user_data _U_)
799 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
803 gchar *help_str = NULL;
804 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
806 gboolean has_blurb = FALSE;
807 guint length = 0, byte_len;
808 GtkWidget *byte_view;
809 const guint8 *byte_data;
810 #if GTK_MAJOR_VERSION >= 2
815 #if GTK_MAJOR_VERSION >= 2
816 /* if nothing is selected */
817 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
820 * Which byte view is displaying the current protocol tree
823 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
824 if (byte_view == NULL)
827 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
828 if (byte_data == NULL)
832 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
833 cfile.current_frame, NULL, byte_len);
836 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
839 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
843 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
845 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
846 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
847 g_assert(byte_data != NULL);
849 finfo_selected = finfo;
850 set_menus_for_selected_tree_row(TRUE);
853 if (finfo->hfinfo->blurb != NULL &&
854 finfo->hfinfo->blurb[0] != '\0') {
856 length = strlen(finfo->hfinfo->blurb);
858 length = strlen(finfo->hfinfo->name);
860 if (finfo->length == 0) {
862 } else if (finfo->length == 1) {
863 strcpy (len_str, ", 1 byte");
865 snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
867 statusbar_pop_field_msg(); /* get rid of current help msg */
869 length += strlen(finfo->hfinfo->abbrev) + strlen(len_str) + 10;
870 help_str = g_malloc(sizeof(gchar) * length);
871 sprintf(help_str, "%s (%s)%s",
872 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
873 finfo->hfinfo->abbrev, len_str);
874 statusbar_push_field_msg(help_str);
878 * Don't show anything if the field name is zero-length;
879 * the pseudo-field for "proto_tree_add_text()" is such
880 * a field, and we don't want "Text (text)" showing up
881 * on the status line if you've selected such a field.
883 * XXX - there are zero-length fields for which we *do*
884 * want to show the field name.
886 * XXX - perhaps the name and abbrev field should be null
887 * pointers rather than null strings for that pseudo-field,
888 * but we'd have to add checks for null pointers in some
889 * places if we did that.
891 * Or perhaps protocol tree items added with
892 * "proto_tree_add_text()" should have -1 as the field index,
893 * with no pseudo-field being used, but that might also
894 * require special checks for -1 to be added.
896 statusbar_push_field_msg("");
900 #if GTK_MAJOR_VERSION < 2
901 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
904 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
909 #if GTK_MAJOR_VERSION < 2
911 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
912 gpointer user_data _U_)
914 GtkWidget *byte_view;
919 * Which byte view is displaying the current protocol tree
922 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
923 if (byte_view == NULL)
926 data = get_byte_view_data_and_length(byte_view, &len);
931 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
936 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
938 collapse_all_tree(cfile.edt->tree, tree_view);
941 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
943 expand_all_tree(cfile.edt->tree, tree_view);
946 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
947 if (cfile.edt->tree) {
948 guint32 tmp = g_resolv_flags;
949 g_resolv_flags = RESOLV_ALL;
950 proto_tree_draw(cfile.edt->tree, tree_view);
951 g_resolv_flags = tmp;
955 /* Set the selection mode of the packet list window. */
957 set_plist_sel_browse(gboolean val)
962 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
964 if (val == old_val) {
966 * The mode isn't changing, so don't do anything.
967 * In particular, don't gratuitiously unselect the
970 * XXX - why do we have to unselect the current packet
971 * ourselves? The documentation for the GtkCList at
973 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
975 * says "Note that setting the widget's selection mode to
976 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
977 * cause all the items in the GtkCList to become deselected."
983 unselect_packet(&cfile);
985 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
986 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
988 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
991 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
995 /* Set the font of the packet list window. */
996 #if GTK_MAJOR_VERSION < 2
998 set_plist_font(GdkFont *font)
1001 set_plist_font(PangoFontDescription *font)
1005 #if GTK_MAJOR_VERSION < 2
1008 style = gtk_style_new();
1009 gdk_font_unref(style->font);
1013 gtk_widget_set_style(packet_list, style);
1015 PangoLayout *layout;
1017 gtk_widget_modify_font(packet_list, font);
1020 /* Compute static column sizes to use during a "-S" capture, so that
1021 the columns don't resize during a live capture. */
1022 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1023 #if GTK_MAJOR_VERSION < 2
1024 cfile.cinfo.col_width[i] = gdk_string_width(font,
1025 get_column_longest_string(get_column_format(i)));
1027 layout = gtk_widget_create_pango_layout(packet_list,
1028 get_column_longest_string(get_column_format(i)));
1029 pango_layout_get_pixel_size(layout, &cfile.cinfo.col_width[i],
1031 g_object_unref(G_OBJECT(layout));
1037 * Push a message referring to file access onto the statusbar.
1040 statusbar_push_file_msg(gchar *msg)
1042 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
1046 * Pop a message referring to file access off the statusbar.
1049 statusbar_pop_file_msg(void)
1051 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1055 * XXX - do we need multiple statusbar contexts?
1059 * Push a message referring to the currently-selected field onto the statusbar.
1062 statusbar_push_field_msg(gchar *msg)
1064 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
1068 * Pop a message referring to the currently-selected field off the statusbar.
1071 statusbar_pop_field_msg(void)
1073 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
1079 /* XXX - should we check whether the capture file is an
1080 unsaved temporary file for a live capture and, if so,
1081 pop up a "do you want to exit without saving the capture
1082 file?" dialog, and then just return, leaving said dialog
1083 box to forcibly quit if the user clicks "OK"?
1085 If so, note that this should be done in a subroutine that
1086 returns TRUE if we do so, and FALSE otherwise, and if it
1087 returns TRUE we should return TRUE without nuking anything.
1089 Note that, if we do that, we might also want to check if
1090 an "Update list of packets in real time" capture is in
1091 progress and, if so, ask whether they want to terminate
1092 the capture and discard it, and return TRUE, before nuking
1093 any child capture, if they say they don't want to do so. */
1096 /* Nuke any child capture in progress. */
1097 kill_capture_child();
1100 /* Are we in the middle of reading a capture? */
1101 if (cfile.state == FILE_READ_IN_PROGRESS) {
1102 /* Yes, so we can't just close the file and quit, as
1103 that may yank the rug out from under the read in
1104 progress; instead, just set the state to
1105 "FILE_READ_ABORTED" and return - the code doing the read
1106 will check for that and, if it sees that, will clean
1108 cfile.state = FILE_READ_ABORTED;
1110 /* Say that the window should *not* be deleted;
1111 that'll be done by the code that cleans up. */
1114 /* Close any capture file we have open; on some OSes, you
1115 can't unlink a temporary capture file if you have it
1117 "close_cap_file()" will unlink it after closing it if
1118 it's a temporary file.
1120 We do this here, rather than after the main loop returns,
1121 as, after the main loop returns, the main window may have
1122 been destroyed (if this is called due to a "destroy"
1123 even on the main window rather than due to the user
1124 selecting a menu item), and there may be a crash
1125 or other problem when "close_cap_file()" tries to
1126 clean up stuff in the main window.
1128 XXX - is there a better place to put this?
1129 Or should we have a routine that *just* closes the
1130 capture file, and doesn't do anything with the UI,
1131 which we'd call here, and another routine that
1132 calls that routine and also cleans up the UI, which
1133 we'd call elsewhere? */
1134 close_cap_file(&cfile);
1136 /* Exit by leaving the main loop, so that any quit functions
1137 we registered get called. */
1140 /* Say that the window should be deleted. */
1146 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1148 gint desk_x, desk_y;
1150 /* Try to grab our geometry */
1151 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1152 if (gdk_window_get_deskrelative_origin(top_level->window,
1153 &desk_x, &desk_y)) {
1154 if (desk_x <= root_x && desk_y <= root_y) {
1160 /* XXX - Is this the "approved" method? */
1161 gdk_window_get_size(top_level->window, &top_width, &top_height);
1163 /* "do_quit()" indicates whether the main window should be deleted. */
1168 file_quit_cmd_cb (GtkWidget *widget _U_, gpointer data _U_)
1174 print_usage(gboolean print_ver) {
1177 fprintf(stderr, "This is GNU " PACKAGE " " VERSION "\n%s\n%s\n",
1178 comp_info_str->str, runtime_info_str->str);
1181 fprintf(stderr, "\n%s [ -vh ] [ -klpQS ] [ -a <capture autostop condition> ] ...\n",
1183 fprintf(stderr, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
1184 fprintf(stderr, "\t[ -B <byte view height> ]\n");
1185 fprintf(stderr, "\t[ -c <count> ] [ -f <capture filter> ] [ -i <interface> ]\n");
1186 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -N <resolving> ]\n");
1187 fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1188 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1189 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1190 fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n");
1192 fprintf(stderr, "\n%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1194 fprintf(stderr, "\t[ -n ] [ -N <resolving> ]\n");
1195 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
1196 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
1197 fprintf(stderr, "\t[ -T <tree view height> ] [ <infile> ]\n");
1208 printf("%s %s\n%s\n%s\n", PACKAGE, VERSION, comp_info_str->str,
1209 runtime_info_str->str);
1213 get_positive_int(const char *string, const char *name)
1218 number = strtol(string, &p, 10);
1219 if (p == string || *p != '\0') {
1220 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1225 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1230 fprintf(stderr, "ethereal: The specified %s \"%s\" is zero\n",
1234 if (number > INT_MAX) {
1235 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1236 name, string, INT_MAX);
1244 * Given a string of the form "<autostop criterion>:<value>", as might appear
1245 * as an argument to a "-a" option, parse it and set the criterion in
1246 * question. Return an indication of whether it succeeded or failed
1250 set_autostop_criterion(const char *autostoparg)
1254 colonp = strchr(autostoparg, ':');
1262 * Skip over any white space (there probably won't be any, but
1263 * as we allow it in the preferences file, we might as well
1270 * Put the colon back, so if our caller uses, in an
1271 * error message, the string they passed us, the message
1277 if (strcmp(autostoparg,"duration") == 0) {
1278 capture_opts.has_autostop_duration = TRUE;
1279 capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1280 } else if (strcmp(autostoparg,"filesize") == 0) {
1281 capture_opts.has_autostop_filesize = TRUE;
1282 capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1286 *colonp = ':'; /* put the colon back */
1291 * Given a string of the form "<ring buffer file>:<duration>", as might appear
1292 * as an argument to a "-b" option, parse it and set the arguments in
1293 * question. Return an indication of whether it succeeded or failed
1297 get_ring_arguments(const char *arg)
1299 guchar *p = NULL, *colonp;
1301 colonp = strchr(arg, ':');
1303 if (colonp != NULL) {
1308 capture_opts.ringbuffer_num_files =
1309 get_positive_int(arg, "number of ring buffer files");
1315 * Skip over any white space (there probably won't be any, but
1316 * as we allow it in the preferences file, we might as well
1323 * Put the colon back, so if our caller uses, in an
1324 * error message, the string they passed us, the message
1331 capture_opts.has_ring_duration = TRUE;
1332 capture_opts.ringbuffer_duration = get_positive_int(p,
1333 "ring buffer duration");
1335 *colonp = ':'; /* put the colon back */
1340 #if defined WIN32 || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1342 Once every 3 seconds we get a callback here which we use to update
1343 the tap extensions. Since Gtk1 is single threaded we dont have to
1344 worry about any locking or critical regions.
1347 update_cb(gpointer data _U_)
1349 draw_tap_listeners(FALSE);
1354 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1355 use threads all updte_thread_mutex can be dropped and protect/unprotect
1356 would just be empty functions.
1358 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1359 gtk1-ethereal and it will just work.
1361 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1363 update_thread(gpointer data _U_)
1367 g_get_current_time(&tv1);
1368 g_static_mutex_lock(&update_thread_mutex);
1369 gdk_threads_enter();
1370 draw_tap_listeners(FALSE);
1371 gdk_threads_leave();
1372 g_static_mutex_unlock(&update_thread_mutex);
1374 g_get_current_time(&tv2);
1375 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1376 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1377 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1378 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1385 protect_thread_critical_region(void)
1387 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1388 g_static_mutex_lock(&update_thread_mutex);
1392 unprotect_thread_critical_region(void)
1394 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1395 g_static_mutex_unlock(&update_thread_mutex);
1399 /* structure to keep track of what tap listeners have been registered.
1401 typedef struct _ethereal_tap_list {
1402 struct _ethereal_tap_list *next;
1404 void (*func)(char *arg);
1405 } ethereal_tap_list;
1406 static ethereal_tap_list *tap_list=NULL;
1409 register_ethereal_tap(char *cmd, void (*func)(char *arg))
1411 ethereal_tap_list *newtl;
1413 newtl=malloc(sizeof(ethereal_tap_list));
1414 newtl->next=tap_list;
1421 /* And now our feature presentation... [ fade to music ] */
1423 main(int argc, char *argv[])
1431 extern char *optarg;
1432 gboolean arg_error = FALSE;
1438 char *gpf_path, *cf_path, *df_path;
1440 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
1443 gboolean start_capture = FALSE;
1444 gchar *save_file = NULL;
1446 gchar err_str[PCAP_ERRBUF_SIZE];
1447 gboolean stats_known;
1448 struct pcap_stat stats;
1450 gboolean capture_option_specified = FALSE;
1452 gint pl_size = 280, tv_size = 95, bv_size = 75;
1453 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1454 dfilter_t *rfcode = NULL;
1455 gboolean rfilter_parse_failed = FALSE;
1458 #if GTK_MAJOR_VERSION < 2
1459 char *bold_font_name;
1461 gint desk_x, desk_y;
1462 gboolean prefs_write_needed = FALSE;
1463 ethereal_tap_list *tli = NULL;
1464 gchar *tap_opt = NULL;
1466 #define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vz:"
1470 #define OPTSTRING_CHILD "W:Z:"
1472 #define OPTSTRING_CHILD "W:"
1475 #define OPTSTRING_CHILD ""
1476 #endif /* HAVE_LIBPCAP */
1478 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1481 ethereal_path = argv[0];
1484 /* Arrange that if we have no console window, and a GLib message logging
1485 routine is called to log a message, we pop up a console window.
1487 We do that by inserting our own handler for all messages logged
1488 to the default domain; that handler pops up a console if necessary,
1489 and then calls the default handler. */
1490 g_log_set_handler(NULL,
1492 G_LOG_LEVEL_CRITICAL|
1493 G_LOG_LEVEL_WARNING|
1494 G_LOG_LEVEL_MESSAGE|
1497 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1498 console_log_handler, NULL);
1502 command_name = get_basename(ethereal_path);
1503 /* Set "capture_child" to indicate whether this is going to be a child
1504 process for a "-S" capture. */
1505 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1507 strcat(optstring, OPTSTRING_CHILD);
1510 /* Register all dissectors; we must do this before checking for the
1511 "-G" flag, as the "-G" flag dumps information registered by the
1512 dissectors, and we must do it before we read the preferences, in
1513 case any dissectors register preferences. */
1514 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
1516 /* Register all tap listeners; we do this before we parse the arguments,
1517 as the "-z" argument can specify a registered tap. */
1518 register_all_tap_listeners();
1520 /* Now register the preferences for any non-dissector modules.
1521 We must do that before we read the preferences as well. */
1522 prefs_register_modules();
1524 /* If invoked with the "-G" flag, we dump out information based on
1525 the argument to the "-G" flag; if no argument is specified,
1526 for backwards compatibility we dump out a glossary of display
1529 We must do this before calling "gtk_init()", because "gtk_init()"
1530 tries to open an X display, and we don't want to have to do any X
1531 stuff just to do a build.
1533 Given that we call "gtk_init()" before doing the regular argument
1534 list processing, so that it can handle X and GTK+ arguments and
1535 remove them from the list at which we look, this means we must do
1536 this before doing the regular argument list processing, as well.
1540 you must give the "-G" flag as the first flag on the command line;
1542 you must give it as "-G", nothing more, nothing less;
1544 the first argument after the "-G" flag, if present, will be used
1545 to specify the information to dump;
1547 arguments after that will not be used. */
1548 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1550 proto_registrar_dump_fields();
1552 if (strcmp(argv[2], "fields") == 0)
1553 proto_registrar_dump_fields();
1554 else if (strcmp(argv[2], "protocols") == 0)
1555 proto_registrar_dump_protocols();
1557 fprintf(stderr, "ethereal: Invalid \"%s\" option for -G flag\n",
1565 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1566 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined G_THREADS_ENABLED && defined USE_THREADS
1569 g_thread_init(NULL);
1571 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1572 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1574 #else /* WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1575 /* this is to keep tap extensions updating once every 3 seconds */
1576 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1577 #endif /* !WIN32 && GTK2 && G_THREADS_ENABLED */
1580 gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1584 /* Set the current locale according to the program environment.
1585 * We haven't localized anything, but some GTK widgets are localized
1586 * (the file selection dialogue, for example).
1587 * This also sets the C-language locale to the native environment. */
1590 /* Let GTK get its args */
1591 gtk_init (&argc, &argv);
1593 /* Read the preference files. */
1594 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1597 capture_opts.has_snaplen = FALSE;
1598 capture_opts.snaplen = MIN_PACKET_SIZE;
1599 capture_opts.has_autostop_count = FALSE;
1600 capture_opts.autostop_count = 1;
1601 capture_opts.has_autostop_duration = FALSE;
1602 capture_opts.autostop_duration = 1;
1603 capture_opts.has_autostop_filesize = FALSE;
1604 capture_opts.autostop_filesize = 1;
1605 capture_opts.ringbuffer_on = FALSE;
1606 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1607 capture_opts.has_ring_duration = FALSE;
1608 capture_opts.ringbuffer_duration = 1;
1610 /* If this is a capture child process, it should pay no attention
1611 to the "prefs.capture_prom_mode" setting in the preferences file;
1612 it should do what the parent process tells it to do, and if
1613 the parent process wants it not to run in promiscuous mode, it'll
1614 tell it so with a "-p" flag.
1616 Otherwise, set promiscuous mode from the preferences setting. */
1618 capture_opts.promisc_mode = TRUE;
1620 capture_opts.promisc_mode = prefs->capture_prom_mode;
1622 /* Set "Update list of packets in real time" mode from the preferences
1624 capture_opts.sync_mode = prefs->capture_real_time;
1626 /* And do the same for "Automatic scrolling in live capture" mode. */
1627 auto_scroll_live = prefs->capture_auto_scroll;
1630 /* Set the name resolution code's flags from the preferences. */
1631 g_resolv_flags = prefs->name_resolve;
1633 /* Read the capture filter file. */
1634 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1636 /* Read the display filter file. */
1637 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1639 init_cap_file(&cfile);
1641 /* Assemble the compile-time version information string */
1642 comp_info_str = g_string_new("Compiled ");
1643 g_string_append(comp_info_str, "with ");
1644 g_string_sprintfa(comp_info_str,
1645 #ifdef GTK_MAJOR_VERSION
1646 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1649 "GTK+ (version unknown)");
1652 g_string_append(comp_info_str, ", ");
1653 get_compiled_version_info(comp_info_str);
1655 /* Assemble the run-time version information string */
1656 runtime_info_str = g_string_new("Running ");
1657 get_runtime_version_info(runtime_info_str);
1659 /* Now get our args */
1660 while ((opt = getopt(argc, argv, optstring)) != -1) {
1662 case 'a': /* autostop criteria */
1664 if (set_autostop_criterion(optarg) == FALSE) {
1665 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1669 capture_option_specified = TRUE;
1673 case 'b': /* Ringbuffer option */
1675 capture_opts.ringbuffer_on = TRUE;
1676 if (get_ring_arguments(optarg) == FALSE) {
1677 fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
1681 capture_option_specified = TRUE;
1685 case 'B': /* Byte view pane height */
1686 bv_size = get_positive_int(optarg, "byte view pane height");
1688 case 'c': /* Capture xxx packets */
1690 capture_opts.has_autostop_count = TRUE;
1691 capture_opts.autostop_count = get_positive_int(optarg, "packet count");
1693 capture_option_specified = TRUE;
1700 g_free(cfile.cfilter);
1701 cfile.cfilter = g_strdup(optarg);
1703 capture_option_specified = TRUE;
1707 case 'h': /* Print help and exit */
1711 case 'i': /* Use interface xxx */
1713 cfile.iface = g_strdup(optarg);
1715 capture_option_specified = TRUE;
1719 case 'k': /* Start capture immediately */
1721 start_capture = TRUE;
1723 capture_option_specified = TRUE;
1727 case 'l': /* Automatic scrolling in live capture mode */
1729 auto_scroll_live = TRUE;
1731 capture_option_specified = TRUE;
1735 case 'm': /* Fixed-width font for the display */
1736 if (prefs->gui_font_name != NULL)
1737 g_free(prefs->gui_font_name);
1738 prefs->gui_font_name = g_strdup(optarg);
1740 case 'n': /* No name resolution */
1741 g_resolv_flags = RESOLV_NONE;
1743 case 'N': /* Select what types of addresses/port #s to resolve */
1744 if (g_resolv_flags == RESOLV_ALL)
1745 g_resolv_flags = RESOLV_NONE;
1746 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1747 if (badopt != '\0') {
1748 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1753 case 'o': /* Override preference from command line */
1754 switch (prefs_set_pref(optarg)) {
1756 case PREFS_SET_SYNTAX_ERR:
1757 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1761 case PREFS_SET_NO_SUCH_PREF:
1762 case PREFS_SET_OBSOLETE:
1763 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1769 case 'p': /* Don't capture in promiscuous mode */
1771 capture_opts.promisc_mode = FALSE;
1773 capture_option_specified = TRUE;
1777 case 'P': /* Packet list pane height */
1778 pl_size = get_positive_int(optarg, "packet list pane height");
1780 case 'Q': /* Quit after capture (just capture to file) */
1783 start_capture = TRUE; /*** -Q implies -k !! ***/
1785 capture_option_specified = TRUE;
1789 case 'r': /* Read capture file xxx */
1790 /* We may set "last_open_dir" to "cf_name", and if we change
1791 "last_open_dir" later, we free the old value, so we have to
1792 set "cf_name" to something that's been allocated. */
1793 cf_name = g_strdup(optarg);
1795 case 'R': /* Read file filter */
1798 case 's': /* Set the snapshot (capture) length */
1800 capture_opts.has_snaplen = TRUE;
1801 capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
1803 capture_option_specified = TRUE;
1807 case 'S': /* "Sync" mode: used for following file ala tail -f */
1809 capture_opts.sync_mode = TRUE;
1811 capture_option_specified = TRUE;
1815 case 't': /* Time stamp type */
1816 if (strcmp(optarg, "r") == 0)
1817 timestamp_type = RELATIVE;
1818 else if (strcmp(optarg, "a") == 0)
1819 timestamp_type = ABSOLUTE;
1820 else if (strcmp(optarg, "ad") == 0)
1821 timestamp_type = ABSOLUTE_WITH_DATE;
1822 else if (strcmp(optarg, "d") == 0)
1823 timestamp_type = DELTA;
1825 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1827 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1828 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1832 case 'T': /* Tree view pane height */
1833 tv_size = get_positive_int(optarg, "tree view pane height");
1835 case 'v': /* Show version and exit */
1838 if (console_was_created)
1843 case 'w': /* Write to capture file xxx */
1845 save_file = g_strdup(optarg);
1847 capture_option_specified = TRUE;
1852 /* This is a hidden option supporting Sync mode, so we don't set
1853 * the error flags for the user in the non-libpcap case.
1855 case 'W': /* Write to capture file FD xxx */
1856 cfile.save_file_fd = atoi(optarg);
1860 for(tli=tap_list;tli;tli=tli->next){
1861 if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
1862 tap_opt = g_strdup(optarg);
1867 fprintf(stderr,"ethereal: invalid -z argument.\n");
1868 fprintf(stderr," -z argument must be one of :\n");
1869 for(tli=tap_list;tli;tli=tli->next){
1870 fprintf(stderr," %s\n",tli->cmd);
1878 /* Hidden option supporting Sync mode */
1879 case 'Z': /* Write to pipe FD XXX */
1880 /* associate stdout with pipe */
1882 if (dup2(i, 1) < 0) {
1883 fprintf(stderr, "Unable to dup pipe handle\n");
1887 #endif /* HAVE_LIBPCAP */
1891 case '?': /* Bad flag - print usage message */
1899 if (cf_name != NULL) {
1901 * Input file name specified with "-r" *and* specified as a regular
1902 * command-line argument.
1907 * Input file name not specified with "-r", and a command-line argument
1908 * was specified; treat it as the input file name.
1910 * Yes, this is different from tethereal, where non-flag command-line
1911 * arguments are a filter, but this works better on GUI desktops
1912 * where a command can be specified to be run to open a particular
1913 * file - yes, you could have "-r" as the last part of the command,
1914 * but that's a bit ugly.
1916 cf_name = g_strdup(argv[0]);
1924 * Extra command line arguments were specified; complain.
1926 fprintf(stderr, "Invalid argument: %s\n", argv[0]);
1935 if (capture_opts.ringbuffer_on) {
1936 /* Ring buffer works only under certain conditions:
1937 a) ring buffer does not work with temporary files;
1938 b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
1939 sync_mode takes precedence;
1940 c) it makes no sense to enable the ring buffer if the maximum
1941 file size is set to "infinite". */
1942 if (save_file == NULL) {
1943 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
1944 capture_opts.ringbuffer_on = FALSE;
1946 if (capture_opts.sync_mode) {
1947 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
1948 capture_opts.ringbuffer_on = FALSE;
1950 if (!capture_opts.has_autostop_filesize) {
1951 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
1952 capture_opts.ringbuffer_on = FALSE;
1958 /* Load wpcap if possible */
1961 /* Start windows sockets */
1962 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1965 /* Notify all registered modules that have had any of their preferences
1966 changed either from one of the preferences file or from the command
1967 line that their preferences have changed. */
1970 #ifndef HAVE_LIBPCAP
1971 if (capture_option_specified)
1972 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1975 if (start_capture) {
1976 /* We're supposed to do a live capture; did the user specify an interface
1978 if (cfile.iface == NULL) {
1979 /* No - is a default specified in the preferences file? */
1980 if (prefs->capture_device != NULL) {
1982 cfile.iface = g_strdup(prefs->capture_device);
1984 /* No - pick the first one from the list of interfaces. */
1985 if_list = get_interface_list(&err, err_str);
1986 if (if_list == NULL) {
1989 case CANT_GET_INTERFACE_LIST:
1990 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1994 case NO_INTERFACES_FOUND:
1995 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2000 cfile.iface = g_strdup(if_list->data); /* first interface */
2001 free_interface_list(if_list);
2005 if (capture_child) {
2006 if (cfile.save_file_fd == -1) {
2007 /* XXX - send this to the standard output as something our parent
2008 should put in an error message box? */
2009 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2015 /* Build the column format array */
2016 col_setup(&cfile.cinfo, prefs->num_cols);
2017 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2018 cfile.cinfo.col_fmt[i] = get_column_format(i);
2019 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2020 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2022 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2023 cfile.cinfo.col_data[i] = NULL;
2024 if (cfile.cinfo.col_fmt[i] == COL_INFO)
2025 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2027 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2028 cfile.cinfo.col_fence[i] = 0;
2029 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2030 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2034 if (capture_opts.has_snaplen) {
2035 if (capture_opts.snaplen < 1)
2036 capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
2037 else if (capture_opts.snaplen < MIN_PACKET_SIZE)
2038 capture_opts.snaplen = MIN_PACKET_SIZE;
2041 /* Check the value range of the ringbuffer_num_files parameter */
2042 if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
2043 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
2044 else if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
2045 capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
2048 rc_file = get_persconffile_path(RC_FILE, FALSE);
2049 gtk_rc_parse(rc_file);
2051 /* Try to load the regular and boldface fixed-width fonts */
2052 #if GTK_MAJOR_VERSION < 2
2053 bold_font_name = boldify(prefs->gui_font_name);
2054 m_r_font = gdk_font_load(prefs->gui_font_name);
2055 m_b_font = gdk_font_load(bold_font_name);
2057 m_r_font = pango_font_description_from_string(prefs->gui_font_name);
2058 m_b_font = pango_font_description_copy(m_r_font);
2059 pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2061 if (m_r_font == NULL || m_b_font == NULL) {
2062 /* XXX - pop this up as a dialog box? no */
2063 if (m_r_font == NULL) {
2067 #if GTK_MAJOR_VERSION < 2
2068 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2070 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to Monospace 9\n",
2072 prefs->gui_font_name);
2074 #if GTK_MAJOR_VERSION < 2
2075 gdk_font_unref(m_r_font);
2077 pango_font_description_free(m_r_font);
2080 if (m_b_font == NULL) {
2084 #if GTK_MAJOR_VERSION < 2
2085 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2088 fprintf(stderr, "ethereal: Warning: bold font %s not found - defaulting"
2089 " to Monospace 9\n", prefs->gui_font_name);
2092 #if GTK_MAJOR_VERSION < 2
2093 gdk_font_unref(m_b_font);
2095 pango_font_description_free(m_b_font);
2098 #if GTK_MAJOR_VERSION < 2
2099 g_free(bold_font_name);
2100 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
2101 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
2103 if ((m_r_font = pango_font_description_from_string("Monospace 9")) == NULL)
2105 fprintf(stderr, "ethereal: Error: font Monospace 9 not found\n");
2109 #if GTK_MAJOR_VERSION < 2
2110 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
2111 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
2113 if ((m_b_font = pango_font_description_copy(m_r_font)) == NULL) {
2114 fprintf(stderr, "ethereal: Error: font Monospace 9 bold not found\n");
2118 g_free(prefs->gui_font_name);
2119 #if GTK_MAJOR_VERSION < 2
2120 prefs->gui_font_name = g_strdup("6x13");
2122 pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2123 prefs->gui_font_name = g_strdup("Monospace 9");
2127 /* Call this for the side-effects that set_fonts() produces */
2128 set_fonts(m_r_font, m_b_font);
2132 /* Is this a "child" ethereal, which is only supposed to pop up a
2133 capture box to let us stop the capture, and run a capture
2134 to a file that our parent will read? */
2135 if (!capture_child) {
2137 /* No. Pop up the main window, register menus for taps (which we
2138 must do after creating the main window, so that we can add
2139 menu items to the main menu), and read in a capture file if
2141 create_main_window(pl_size, tv_size, bv_size, prefs);
2142 register_all_tap_menus();
2143 set_menus_for_capture_file(FALSE);
2145 /* open tap windows after creating the main window to avoid GTK warnings */
2146 if (tap_opt && tli) {
2147 (*tli->func)(tap_opt);
2154 /* If we were given the name of a capture file, read it in now;
2155 we defer it until now, so that, if we can't open it, and pop
2156 up an alert box, the alert box is more likely to come up on
2157 top of the main window - but before the preference-file-error
2158 alert box, so, if we get one of those, it's more likely to come
2161 if (rfilter != NULL) {
2162 if (!dfilter_compile(rfilter, &rfcode)) {
2163 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
2164 rfilter_parse_failed = TRUE;
2167 if (!rfilter_parse_failed) {
2168 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
2169 /* "open_cap_file()" succeeded, so it closed the previous
2170 capture file, and thus destroyed any previous read filter
2171 attached to "cf". */
2172 cfile.rfcode = rfcode;
2173 switch (read_cap_file(&cfile, &err)) {
2177 /* Just because we got an error, that doesn't mean we were unable
2178 to read any of the file; we handle what we could get from the
2187 /* Save the name of the containing directory specified in the
2188 path name, if any; we can write over cf_name, which is a
2189 good thing, given that "get_dirname()" does write over its
2191 s = get_dirname(cf_name);
2192 set_last_open_dir(s);
2197 dfilter_free(rfcode);
2198 cfile.rfcode = NULL;
2206 /* If the global preferences file exists but we failed to open it,
2207 pop up an alert box; we defer that until now, so that the alert
2208 box is more likely to come up on top of the main window. */
2209 if (gpf_path != NULL) {
2210 simple_dialog(ESD_TYPE_WARN, NULL,
2211 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
2212 strerror(gpf_open_errno));
2215 /* If the user's preferences file exists but we failed to open it,
2216 pop up an alert box; we defer that until now, so that the alert
2217 box is more likely to come up on top of the main window. */
2218 if (pf_path != NULL) {
2219 simple_dialog(ESD_TYPE_WARN, NULL,
2220 "Could not open your preferences file\n\"%s\": %s.", pf_path,
2221 strerror(pf_open_errno));
2226 /* If the user's capture filter file exists but we failed to open it,
2227 pop up an alert box; we defer that until now, so that the alert
2228 box is more likely to come up on top of the main window. */
2229 if (cf_path != NULL) {
2230 simple_dialog(ESD_TYPE_WARN, NULL,
2231 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2232 strerror(cf_open_errno));
2236 /* If the user's display filter file exists but we failed to open it,
2237 pop up an alert box; we defer that until now, so that the alert
2238 box is more likely to come up on top of the main window. */
2239 if (df_path != NULL) {
2240 simple_dialog(ESD_TYPE_WARN, NULL,
2241 "Could not open your display filter file\n\"%s\": %s.", df_path,
2242 strerror(df_open_errno));
2247 if (capture_child) {
2248 /* This is the child process for a sync mode or fork mode capture,
2249 so just do the low-level work of a capture - don't create
2250 a temporary file and fork off *another* child process (so don't
2251 call "do_capture()"). */
2253 /* XXX - hand these stats to the parent process */
2254 capture(&stats_known, &stats);
2256 /* The capture is done; there's nothing more for us to do. */
2259 if (start_capture) {
2260 /* "-k" was specified; start a capture. */
2261 do_capture(save_file);
2262 if (save_file != NULL) {
2263 /* Save the directory name for future file dialogs. */
2264 s = get_dirname(save_file); /* Overwrites save_file */
2265 set_last_open_dir(s);
2271 set_menus_for_capture_in_progress(FALSE);
2275 set_menus_for_capture_in_progress(FALSE);
2280 /* Try to save our geometry. GTK+ provides two routines to get a
2281 window's position relative to the X root window. If I understand the
2282 documentation correctly, gdk_window_get_deskrelative_origin applies
2283 mainly to Enlightenment and gdk_window_get_root_origin applies for
2286 The code below tries both routines, and picks the one that returns
2287 the upper-left-most coordinates.
2291 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
2292 http://www.gtk.org/faq/#AEN600 */
2294 /* Re-read our saved preferences. */
2295 /* XXX - Move all of this into a separate function? */
2296 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
2298 if (pf_path == NULL) {
2299 if (prefs->gui_geometry_save_position) {
2300 if (top_level->window != NULL) {
2301 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
2302 if (gdk_window_get_deskrelative_origin(top_level->window,
2303 &desk_x, &desk_y)) {
2304 if (desk_x <= root_x && desk_y <= root_y) {
2310 if (prefs->gui_geometry_main_x != root_x) {
2311 prefs->gui_geometry_main_x = root_x;
2312 prefs_write_needed = TRUE;
2314 if (prefs->gui_geometry_main_y != root_y) {
2315 prefs->gui_geometry_main_y = root_y;
2316 prefs_write_needed = TRUE;
2320 if (prefs->gui_geometry_save_size) {
2321 if (top_level->window != NULL) {
2322 /* XXX - Is this the "approved" method? */
2323 gdk_window_get_size(top_level->window, &top_width, &top_height);
2325 if (prefs->gui_geometry_main_width != top_width) {
2326 prefs->gui_geometry_main_width = top_width;
2327 prefs_write_needed = TRUE;
2329 if (prefs->gui_geometry_main_height != top_height) {
2330 prefs->gui_geometry_main_height = top_height;
2331 prefs_write_needed = TRUE;
2335 if (prefs_write_needed) {
2336 write_prefs(&pf_path);
2339 /* Ignore errors silently */
2347 /* Shutdown windows sockets */
2350 /* For some unknown reason, the "atexit()" call in "create_console()"
2351 doesn't arrange that "destroy_console()" be called when we exit,
2352 so we call it here if a console was created. */
2353 if (console_was_created)
2359 /* This isn't reached, but we need it to keep GCC from complaining
2360 that "main()" returns without returning a value - it knows that
2361 "exit()" never returns, but it doesn't know that "gtk_exit()"
2362 doesn't, as GTK+ doesn't declare it with the attribute
2364 return 0; /* not reached */
2369 /* We build this as a GUI subsystem application on Win32, so
2370 "WinMain()", not "main()", gets called.
2372 Hack shamelessly stolen from the Win32 port of the GIMP. */
2374 #define _stdcall __attribute__((stdcall))
2378 WinMain (struct HINSTANCE__ *hInstance,
2379 struct HINSTANCE__ *hPrevInstance,
2383 has_no_console = TRUE;
2384 return main (__argc, __argv);
2388 * If this application has no console window to which its standard output
2389 * would go, create one.
2392 create_console(void)
2394 if (has_no_console) {
2395 /* We have no console to which to print the version string, so
2396 create one and make it the standard input, output, and error. */
2397 if (!AllocConsole())
2398 return; /* couldn't create console */
2399 freopen("CONIN$", "r", stdin);
2400 freopen("CONOUT$", "w", stdout);
2401 freopen("CONOUT$", "w", stderr);
2403 /* Well, we have a console now. */
2404 has_no_console = FALSE;
2405 console_was_created = TRUE;
2407 /* Now register "destroy_console()" as a routine to be called just
2408 before the application exits, so that we can destroy the console
2409 after the user has typed a key (so that the console doesn't just
2410 disappear out from under them, giving the user no chance to see
2411 the message(s) we put in there). */
2412 atexit(destroy_console);
2417 destroy_console(void)
2419 printf("\n\nPress any key to exit\n");
2424 /* This routine should not be necessary, at least as I read the GLib
2425 source code, as it looks as if GLib is, on Win32, *supposed* to
2426 create a console window into which to display its output.
2428 That doesn't happen, however. I suspect there's something completely
2429 broken about that code in GLib-for-Win32, and that it may be related
2430 to the breakage that forces us to just call "printf()" on the message
2431 rather than passing the message on to "g_log_default_handler()"
2432 (which is the routine that does the aforementioned non-functional
2433 console window creation). */
2435 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2436 const char *message, gpointer user_data)
2439 if (console_was_created) {
2440 /* For some unknown reason, the above doesn't appear to actually cause
2441 anything to be sent to the standard output, so we'll just splat the
2442 message out directly, just to make sure it gets out. */
2443 printf("%s\n", message);
2445 g_log_default_handler(log_domain, log_level, message, user_data);
2449 #if GTK_MAJOR_VERSION < 2
2450 /* Given a font name, construct the name of the next heavier version of
2453 #define XLFD_WEIGHT 3 /* index of the "weight" field */
2455 /* Map from a given weight to the appropriate weight for the "bold"
2457 XXX - the XLFD says these strings shouldn't be used for font matching;
2458 can we get the weight, as a number, from GDK, and ask GDK to find us
2459 a font just like the given font, but with the appropriate higher
2461 static const struct {
2465 { "ultralight", "light" },
2466 { "extralight", "semilight" },
2467 { "light", "medium" },
2468 { "semilight", "semibold" },
2469 { "medium", "bold" },
2470 { "normal", "bold" },
2471 { "semibold", "extrabold" },
2472 { "bold", "ultrabold" }
2474 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
2477 boldify(const char *font_name)
2479 char *bold_font_name;
2480 gchar **xlfd_tokens;
2483 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
2484 if (font_name[0] == '-') {
2485 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
2488 * Make sure we *have* a weight (this might not be a valid
2491 for (i = 0; i < XLFD_WEIGHT+1; i++) {
2492 if (xlfd_tokens[i] == NULL) {
2494 * We don't, so treat this as a non-XLFD
2500 for (i = 0; i < N_WEIGHTS; i++) {
2501 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
2502 weight_map[i].light) == 0) {
2503 g_free(xlfd_tokens[XLFD_WEIGHT]);
2504 xlfd_tokens[XLFD_WEIGHT] =
2505 g_strdup(weight_map[i].heavier);
2509 bold_font_name = g_strjoinv("-", xlfd_tokens);
2510 g_strfreev(xlfd_tokens);
2511 return bold_font_name;
2516 * This isn't an XLFD font name; just append "bold" to the name
2519 bold_font_name = g_strconcat(font_name, "bold", NULL);
2520 return bold_font_name;
2525 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2527 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
2528 *stat_hbox, *column_lb,
2529 *filter_bt, *filter_cm, *filter_te,
2532 GList *filter_list = NULL;
2533 GtkAccelGroup *accel;
2534 GtkStyle *win_style;
2535 GdkBitmap *ascend_bm, *descend_bm;
2536 GdkPixmap *ascend_pm, *descend_pm;
2537 column_arrows *col_arrows;
2539 /* Display filter construct dialog has an Apply button, and "OK" not
2540 only sets our text widget, it activates it (i.e., it causes us to
2541 filter the capture). */
2542 static construct_args_t args = {
2543 "Ethereal: Display Filter",
2549 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2550 gtk_widget_set_name(top_level, "main window");
2551 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
2553 SIGNAL_CONNECT(top_level, "realize", window_icon_realize_cb, NULL);
2554 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
2555 if (prefs->gui_geometry_save_position) {
2556 gtk_widget_set_uposition(GTK_WIDGET(top_level),
2557 prefs->gui_geometry_main_x,
2558 prefs->gui_geometry_main_y);
2560 if (prefs->gui_geometry_save_size) {
2561 WIDGET_SET_SIZE(top_level, prefs->gui_geometry_main_width,
2562 prefs->gui_geometry_main_height);
2564 WIDGET_SET_SIZE(top_level, DEF_WIDTH, -1);
2566 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2568 /* Container for menu bar, paned windows and progress/info box */
2569 main_vbox = gtk_vbox_new(FALSE, 1);
2570 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2571 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2572 gtk_widget_show(main_vbox);
2575 get_main_menu(&menubar, &accel);
2576 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2577 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2578 gtk_widget_show(menubar);
2580 /* Panes for the packet list, tree, and byte view */
2581 u_pane = gtk_vpaned_new();
2582 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
2583 l_pane = gtk_vpaned_new();
2584 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
2585 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
2586 gtk_widget_show(l_pane);
2587 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
2588 gtk_widget_show(u_pane);
2591 pkt_scrollw = scrolled_window_new(NULL, NULL);
2592 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
2593 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2594 gtk_widget_show(pkt_scrollw);
2595 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
2597 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
2598 /* Column titles are filled in below */
2599 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
2601 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
2602 cfile.cinfo.num_cols);
2604 set_plist_sel_browse(prefs->gui_plist_sel_browse);
2605 set_plist_font(m_r_font);
2606 gtk_widget_set_name(packet_list, "packet list");
2607 SIGNAL_CONNECT(packet_list, "click-column", packet_list_click_column_cb,
2609 SIGNAL_CONNECT(packet_list, "select-row", packet_list_select_cb, NULL);
2610 SIGNAL_CONNECT(packet_list, "unselect-row", packet_list_unselect_cb, NULL);
2611 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2612 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
2613 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
2615 /* Right-justify the packet number column. */
2616 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
2617 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
2620 WIDGET_SET_SIZE(packet_list, -1, pl_size);
2621 SIGNAL_CONNECT(packet_list, "button_press_event", popup_menu_handler,
2622 OBJECT_GET_DATA(popup_menu_object, PM_PACKET_LIST_KEY));
2623 SIGNAL_CONNECT(packet_list, "button_press_event",
2624 packet_list_button_pressed_cb, NULL);
2625 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
2626 gtk_widget_show(packet_list);
2629 #if GTK_MAJOR_VERSION < 2
2630 item_style = gtk_style_new();
2631 gdk_font_unref(item_style->font);
2632 item_style->font = m_r_font;
2634 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view);
2635 #if GTK_MAJOR_VERSION < 2
2636 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
2637 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
2640 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
2641 "changed", tree_view_selection_changed_cb, NULL);
2643 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
2644 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
2645 gtk_widget_show(tree_view);
2648 byte_nb_ptr = create_byte_view(bv_size, l_pane);
2650 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
2651 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
2653 /* Filter/info box */
2654 stat_hbox = gtk_hbox_new(FALSE, 1);
2655 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
2656 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2657 gtk_widget_show(stat_hbox);
2659 filter_bt = gtk_button_new_with_label("Filter:");
2660 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
2661 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
2662 gtk_widget_show(filter_bt);
2664 filter_cm = gtk_combo_new();
2665 filter_list = g_list_append (filter_list, "");
2666 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
2667 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
2668 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
2669 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
2670 filter_te = GTK_COMBO(filter_cm)->entry;
2671 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
2672 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
2673 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
2674 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
2675 gtk_widget_show(filter_cm);
2677 #if GTK_MAJOR_VERSION < 2
2678 filter_reset = gtk_button_new_with_label("Reset");
2680 filter_reset = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
2682 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
2683 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
2684 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
2685 gtk_widget_show(filter_reset);
2687 #if GTK_MAJOR_VERSION < 2
2688 filter_apply = gtk_button_new_with_label("Apply");
2690 filter_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
2692 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
2693 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
2694 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_apply, FALSE, TRUE, 1);
2695 gtk_widget_show(filter_apply);
2697 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
2698 * of any widget that ends up calling a callback which needs
2699 * that text entry pointer */
2700 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
2701 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
2702 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
2703 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
2705 set_menu_object_data("/Display/Match/Selected", E_DFILTER_TE_KEY,
2707 set_menu_object_data("/Display/Match/Not Selected", E_DFILTER_TE_KEY,
2709 set_menu_object_data("/Display/Match/And Selected", E_DFILTER_TE_KEY,
2711 set_menu_object_data("/Display/Match/Or Selected", E_DFILTER_TE_KEY,
2713 set_menu_object_data("/Display/Match/And Not Selected", E_DFILTER_TE_KEY,
2715 set_menu_object_data("/Display/Match/Or Not Selected", E_DFILTER_TE_KEY,
2717 set_menu_object_data("/Display/Prepare/Selected", E_DFILTER_TE_KEY,
2719 set_menu_object_data("/Display/Prepare/Not Selected", E_DFILTER_TE_KEY,
2721 set_menu_object_data("/Display/Prepare/And Selected", E_DFILTER_TE_KEY,
2723 set_menu_object_data("/Display/Prepare/Or Selected", E_DFILTER_TE_KEY,
2725 set_menu_object_data("/Display/Prepare/And Not Selected", E_DFILTER_TE_KEY,
2727 set_menu_object_data("/Display/Prepare/Or Not Selected", E_DFILTER_TE_KEY,
2729 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
2730 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
2732 info_bar = gtk_statusbar_new();
2733 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2734 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2735 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2736 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2737 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2738 gtk_widget_show(info_bar);
2740 gtk_widget_show(top_level);
2742 /* Fill in column titles. This must be done after the top level window
2744 win_style = gtk_widget_get_style(top_level);
2745 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
2746 &win_style->bg[GTK_STATE_NORMAL],
2747 (gchar **)clist_ascend_xpm);
2748 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
2749 &win_style->bg[GTK_STATE_NORMAL],
2750 (gchar **)clist_descend_xpm);
2751 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2752 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
2753 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
2754 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
2755 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
2756 GTK_SHRINK, GTK_SHRINK, 0, 0);
2757 gtk_widget_show(column_lb);
2758 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
2759 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
2760 col_arrows[i].ascend_pm,
2761 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
2763 gtk_widget_show(col_arrows[i].ascend_pm);
2765 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
2766 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
2767 col_arrows[i].descend_pm,
2768 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
2769 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i,
2770 col_arrows[i].table);
2771 gtk_widget_show(col_arrows[i].table);
2773 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
2778 set_last_open_dir(char *dirname)
2782 if (last_open_dir) {
2783 g_free(last_open_dir);
2787 len = strlen(dirname);
2788 if (dirname[len-1] == G_DIR_SEPARATOR) {
2789 last_open_dir = g_strconcat(dirname, NULL);
2792 last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
2797 last_open_dir = NULL;