3 * $Id: main.c,v 1.284 2003/03/02 22:31:24 guy 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 */
60 #include <zlib.h> /* to get the libz version number */
63 #ifdef NEED_SNPRINTF_H
64 # include "snprintf.h"
70 #include <net-snmp/version.h>
71 #endif /* HAVE_NET_SNMP */
74 #include <ucd-snmp/version.h>
75 #endif /* HAVE_UCD_SNMP */
77 #endif /* HAVE_SOME_SNMP */
79 #ifdef NEED_STRERROR_H
87 #ifdef WIN32 /* Needed for console I/O */
92 #include <epan/epan.h>
93 #include <epan/filesystem.h>
94 #include <epan/epan_dissect.h>
97 #include <epan/timestamp.h>
98 #include <epan/packet.h>
107 #include "color_filters.h"
108 #include "color_utils.h"
109 #include "filter_prefs.h"
110 #include "file_dlg.h"
113 #include <epan/resolv.h>
115 #include "pcap-util.h"
117 #include "statusbar.h"
118 #include "simple_dialog.h"
119 #include "proto_draw.h"
120 #include <epan/dfilter/dfilter.h>
122 #include "packet_win.h"
123 #include "gtkglobals.h"
124 #include <epan/plugins.h>
126 #include <epan/strutil.h>
127 #include "register.h"
128 #include "ringbuffer.h"
130 #include "image/clist_ascend.xpm"
131 #include "image/clist_descend.xpm"
133 #include "compat_macros.h"
136 #include "capture-wpcap.h"
139 typedef struct column_arrows {
141 GtkWidget *ascend_pm;
142 GtkWidget *descend_pm;
146 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
147 *tv_scrollw, *pkt_scrollw;
148 static GtkWidget *info_bar;
149 #if GTK_MAJOR_VERSION < 2
150 GdkFont *m_r_font, *m_b_font;
151 guint m_font_height, m_font_width;
153 PangoFontDescription *m_r_font, *m_b_font;
155 static guint main_ctx, file_ctx, help_ctx;
156 static GString *comp_info_str;
157 gchar *ethereal_path = NULL;
158 gchar *last_open_dir = NULL;
159 gint root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
161 ts_type timestamp_type = RELATIVE;
163 #if GTK_MAJOR_VERSION < 2
164 GtkStyle *item_style;
167 /* Specifies the field currently selected in the GUI protocol tree */
168 field_info *finfo_selected = NULL;
171 static gboolean has_no_console; /* TRUE if app has no console */
172 static gboolean console_was_created; /* TRUE if console was created */
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);
179 static void create_main_window(gint, gint, gint, e_prefs*);
181 #define E_DFILTER_CM_KEY "display_filter_combo"
182 #define E_DFILTER_FL_KEY "display_filter_list"
184 /* About Ethereal window */
186 about_ethereal( GtkWidget *w _U_, gpointer data _U_ ) {
187 simple_dialog(ESD_TYPE_INFO, NULL,
188 "Ethereal - Network Protocol Analyzer\n"
189 "Version " VERSION " (C) 1998-2002 Gerald Combs <gerald@ethereal.com>\n"
192 "Check the man page for complete documentation and\n"
193 "for the list of contributors.\n"
195 "\nSee http://www.ethereal.com/ for more information.",
199 #if GTK_MAJOR_VERSION < 2
201 set_fonts(GdkFont *regular, GdkFont *bold)
204 set_fonts(PangoFontDescription *regular, PangoFontDescription *bold)
207 /* Yes, assert. The code that loads the font should check
208 * for NULL and provide its own error message. */
209 g_assert(m_r_font && m_b_font);
213 #if GTK_MAJOR_VERSION < 2
214 m_font_height = m_r_font->ascent + m_r_font->descent;
215 m_font_width = gdk_string_width(m_r_font, "0");
220 * Go to frame specified by currently selected protocol tree item.
223 goto_framenum_cb(GtkWidget *w _U_, gpointer data _U_)
225 if (finfo_selected) {
226 header_field_info *hfinfo;
229 hfinfo = finfo_selected->hfinfo;
231 if (hfinfo->type == FT_FRAMENUM) {
232 framenum = fvalue_get_integer(finfo_selected->value);
234 goto_frame(&cfile, framenum);
239 /* Match selected byte pattern */
241 match_selected_cb_do(gpointer data, int action, gchar *text)
243 GtkWidget *filter_te;
244 char *cur_filter, *new_filter;
249 filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
252 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
254 switch (action&MATCH_SELECTED_MASK) {
256 case MATCH_SELECTED_REPLACE:
257 new_filter = g_strdup(text);
260 case MATCH_SELECTED_AND:
261 if ((!cur_filter) || (0 == strlen(cur_filter)))
262 new_filter = g_strdup(text);
264 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
267 case MATCH_SELECTED_OR:
268 if ((!cur_filter) || (0 == strlen(cur_filter)))
269 new_filter = g_strdup(text);
271 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
274 case MATCH_SELECTED_NOT:
275 new_filter = g_strconcat("!(", text, ")", NULL);
278 case MATCH_SELECTED_AND_NOT:
279 if ((!cur_filter) || (0 == strlen(cur_filter)))
280 new_filter = g_strconcat("!(", text, ")", NULL);
282 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
285 case MATCH_SELECTED_OR_NOT:
286 if ((!cur_filter) || (0 == strlen(cur_filter)))
287 new_filter = g_strconcat("!(", text, ")", NULL);
289 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
293 g_assert_not_reached();
298 /* Free up the copy we got of the old filter text. */
301 /* create a new one and set the display filter entry accordingly */
302 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
304 /* Run the display filter so it goes in effect. */
305 if (action&MATCH_SELECTED_APPLY_NOW)
306 filter_packets(&cfile, new_filter);
308 /* Free up the new filter text. */
311 /* Free up the generated text we were handed. */
316 match_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
319 match_selected_cb_do((data ? data : w),
320 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
321 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
325 match_selected_cb_and_ptree(GtkWidget *w, gpointer data)
328 match_selected_cb_do((data ? data : w),
329 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
330 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
334 match_selected_cb_or_ptree(GtkWidget *w, gpointer data)
337 match_selected_cb_do((data ? data : w),
338 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
339 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
343 match_selected_cb_not_ptree(GtkWidget *w, gpointer data)
346 match_selected_cb_do((data ? data : w),
347 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
348 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
352 match_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
355 match_selected_cb_do((data ? data : w),
356 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
357 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
361 match_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
364 match_selected_cb_do((data ? data : w),
365 MATCH_SELECTED_OR_NOT,
366 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
370 prepare_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
373 match_selected_cb_do((data ? data : w),
374 MATCH_SELECTED_REPLACE,
375 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
379 prepare_selected_cb_and_ptree(GtkWidget *w, gpointer data)
382 match_selected_cb_do((data ? data : w),
384 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
388 prepare_selected_cb_or_ptree(GtkWidget *w, gpointer data)
391 match_selected_cb_do((data ? data : w),
393 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
397 prepare_selected_cb_not_ptree(GtkWidget *w, gpointer data)
400 match_selected_cb_do((data ? data : w),
402 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
406 prepare_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
409 match_selected_cb_do((data ? data : w),
410 MATCH_SELECTED_AND_NOT,
411 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
415 prepare_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
418 match_selected_cb_do((data ? data : w),
419 MATCH_SELECTED_OR_NOT,
420 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
424 get_text_from_packet_list(gpointer data)
426 gint row = (gint)OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY);
427 gint column = (gint)OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY);
428 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
435 /* XXX - do something with "err" */
436 wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
437 cfile.pd, fdata->cap_len, &err);
439 edt = epan_dissect_new(FALSE, FALSE);
440 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
442 epan_dissect_fill_in_columns(edt);
444 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
445 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
446 len = strlen(cfile.cinfo.col_expr[column]) +
447 strlen(cfile.cinfo.col_expr_val[column]) + 5;
448 buf = g_malloc0(len);
449 snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
450 cfile.cinfo.col_expr_val[column]);
453 epan_dissect_free(edt);
460 match_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
462 match_selected_cb_do(data,
463 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
464 get_text_from_packet_list(data));
468 match_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
470 match_selected_cb_do(data,
471 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
472 get_text_from_packet_list(data));
476 match_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
478 match_selected_cb_do(data,
479 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
480 get_text_from_packet_list(data));
484 match_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
486 match_selected_cb_do(data,
487 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
488 get_text_from_packet_list(data));
492 match_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
494 match_selected_cb_do(data,
495 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
496 get_text_from_packet_list(data));
500 match_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
502 match_selected_cb_do(data,
503 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
504 get_text_from_packet_list(data));
508 prepare_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
510 match_selected_cb_do(data,
511 MATCH_SELECTED_REPLACE,
512 get_text_from_packet_list(data));
516 prepare_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
518 match_selected_cb_do(data,
520 get_text_from_packet_list(data));
524 prepare_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
526 match_selected_cb_do(data,
528 get_text_from_packet_list(data));
532 prepare_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
534 match_selected_cb_do(data,
536 get_text_from_packet_list(data));
540 prepare_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
542 match_selected_cb_do(data,
543 MATCH_SELECTED_AND_NOT,
544 get_text_from_packet_list(data));
548 prepare_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
550 match_selected_cb_do(data,
551 MATCH_SELECTED_OR_NOT,
552 get_text_from_packet_list(data));
555 /* Run the current display filter on the current packet set, and
558 filter_activate_cb(GtkWidget *w, gpointer data)
560 GtkCombo *filter_cm = OBJECT_GET_DATA(w, E_DFILTER_CM_KEY);
561 GList *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
563 gboolean add_filter = TRUE;
564 gboolean free_filter = TRUE;
568 s = g_strdup(gtk_entry_get_text(GTK_ENTRY(data)));
570 /* GtkCombos don't let us get at their list contents easily, so we maintain
571 our own filter list, and feed it to gtk_combo_set_popdown_strings when
572 a new filter is added. */
573 if (filter_packets(&cfile, s)) {
574 li = g_list_first(filter_list);
576 if (li->data && strcmp(s, li->data) == 0)
583 filter_list = g_list_append(filter_list, s);
584 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
585 gtk_combo_set_popdown_strings(filter_cm, filter_list);
586 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
593 /* redisplay with no display filter */
595 filter_reset_cb(GtkWidget *w, gpointer data _U_)
597 GtkWidget *filter_te = NULL;
599 if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
600 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
602 filter_packets(&cfile, NULL);
605 /* GTKClist compare routine, overrides default to allow numeric comparison */
607 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
609 /* Get row text strings */
610 char *text1 = GTK_CELL_TEXT (((const GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
611 char *text2 = GTK_CELL_TEXT (((const GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
613 /* Attempt to convert to numbers */
614 double num1 = atof(text1);
615 double num2 = atof(text2);
617 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
619 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
620 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
621 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
622 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
623 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
624 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
625 (col_fmt == COL_PACKET_LENGTH)) {
627 /* Compare numeric column */
631 else if (num1 > num2)
639 /* Compare text column */
641 return (text1 != NULL);
646 return strcmp(text1, text2);
650 /* What to do when a column is clicked */
652 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
654 column_arrows *col_arrows = (column_arrows *) data;
657 gtk_clist_freeze(clist);
659 for (i = 0; i < cfile.cinfo.num_cols; i++) {
660 gtk_widget_hide(col_arrows[i].ascend_pm);
661 gtk_widget_hide(col_arrows[i].descend_pm);
664 if (column == clist->sort_column) {
665 if (clist->sort_type == GTK_SORT_ASCENDING) {
666 clist->sort_type = GTK_SORT_DESCENDING;
667 gtk_widget_show(col_arrows[column].descend_pm);
669 clist->sort_type = GTK_SORT_ASCENDING;
670 gtk_widget_show(col_arrows[column].ascend_pm);
674 clist->sort_type = GTK_SORT_ASCENDING;
675 gtk_widget_show(col_arrows[column].ascend_pm);
676 gtk_clist_set_sort_column(clist, column);
678 gtk_clist_thaw(clist);
680 gtk_clist_sort(clist);
685 set_frame_mark(gboolean set, frame_data *frame, gint row) {
691 mark_frame(&cfile, frame);
692 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
693 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
694 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
695 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
697 unmark_frame(&cfile, frame);
698 gtk_clist_set_background(GTK_CLIST(packet_list), row, NULL);
699 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, NULL);
701 file_set_save_marked_sensitive();
704 #if GTK_MAJOR_VERSION < 2
706 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
708 GdkEventButton *event_button = (GdkEventButton *)event;
711 if (w == NULL || event == NULL)
714 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
715 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
716 event_button->y, &row, &column)) {
717 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w),
719 set_frame_mark(!fdata->flags.marked, fdata, row);
724 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
726 GdkEventButton *event_button = (GdkEventButton *)event;
729 if (w == NULL || event == NULL)
732 if (event->type == GDK_BUTTON_PRESS &&
733 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
734 event_button->y, &row, &column)) {
735 if (event_button->button == 2)
737 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w), row);
738 set_frame_mark(!fdata->flags.marked, fdata, row);
741 else if (event_button->button == 1) {
742 gtk_clist_select_row(GTK_CLIST(w), row, column);
750 void mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
751 if (cfile.current_frame) {
752 /* XXX hum, should better have a "cfile->current_row" here ... */
753 set_frame_mark(!cfile.current_frame->flags.marked,
755 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
756 cfile.current_frame));
760 static void mark_all_frames(gboolean set) {
762 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
765 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
769 void update_marked_frames(void) {
771 if (cfile.plist == NULL) return;
772 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
773 if (fdata->flags.marked)
776 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
781 void mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
782 mark_all_frames(TRUE);
785 void unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
786 mark_all_frames(FALSE);
789 /* What to do when a list item is selected/unselected */
791 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
793 /* Remove the hex display tabbed pages */
794 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
795 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
797 select_packet(&cfile, row);
802 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
804 unselect_packet(&cfile);
808 #if GTK_MAJOR_VERSION < 2
810 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
811 gpointer user_data _U_)
814 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
818 gchar *help_str = NULL;
819 gchar len_str[2+10+1+5+1]; /* ", {N} bytes\0",
821 gboolean has_blurb = FALSE;
822 guint length = 0, byte_len;
823 GtkWidget *byte_view;
824 const guint8 *byte_data;
825 #if GTK_MAJOR_VERSION >= 2
830 #if GTK_MAJOR_VERSION >= 2
831 /* if nothing is selected */
832 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
835 * Which byte view is displaying the current protocol tree
838 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
839 if (byte_view == NULL)
842 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
843 if (byte_data == NULL)
847 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
848 cfile.current_frame, NULL, byte_len);
851 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
854 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
858 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
860 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
861 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
862 g_assert(byte_data != NULL);
864 finfo_selected = finfo;
865 set_menus_for_selected_tree_row(TRUE);
868 if (finfo->hfinfo->blurb != NULL &&
869 finfo->hfinfo->blurb[0] != '\0') {
871 length = strlen(finfo->hfinfo->blurb);
873 length = strlen(finfo->hfinfo->name);
875 if (finfo->length == 0) {
877 } else if (finfo->length == 1) {
878 strcpy (len_str, ", 1 byte");
880 snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
882 statusbar_pop_field_msg(); /* get rid of current help msg */
884 length += strlen(finfo->hfinfo->abbrev) + strlen(len_str) + 10;
885 help_str = g_malloc(sizeof(gchar) * length);
886 sprintf(help_str, "%s (%s)%s",
887 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
888 finfo->hfinfo->abbrev, len_str);
889 statusbar_push_field_msg(help_str);
893 * Don't show anything if the field name is zero-length;
894 * the pseudo-field for "proto_tree_add_text()" is such
895 * a field, and we don't want "Text (text)" showing up
896 * on the status line if you've selected such a field.
898 * XXX - there are zero-length fields for which we *do*
899 * want to show the field name.
901 * XXX - perhaps the name and abbrev field should be null
902 * pointers rather than null strings for that pseudo-field,
903 * but we'd have to add checks for null pointers in some
904 * places if we did that.
906 * Or perhaps protocol tree items added with
907 * "proto_tree_add_text()" should have -1 as the field index,
908 * with no pseudo-field being used, but that might also
909 * require special checks for -1 to be added.
911 statusbar_push_field_msg("");
915 #if GTK_MAJOR_VERSION < 2
916 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
919 packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
924 #if GTK_MAJOR_VERSION < 2
926 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
927 gpointer user_data _U_)
929 GtkWidget *byte_view;
934 * Which byte view is displaying the current protocol tree
937 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
938 if (byte_view == NULL)
941 data = get_byte_view_data_and_length(byte_view, &len);
946 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
951 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
953 collapse_all_tree(cfile.edt->tree, tree_view);
956 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
958 expand_all_tree(cfile.edt->tree, tree_view);
961 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
962 if (cfile.edt->tree) {
963 guint32 tmp = g_resolv_flags;
964 g_resolv_flags = RESOLV_ALL;
965 proto_tree_draw(cfile.edt->tree, tree_view);
966 g_resolv_flags = tmp;
970 /* Set the selection mode of the packet list window. */
972 set_plist_sel_browse(gboolean val)
977 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
979 if (val == old_val) {
981 * The mode isn't changing, so don't do anything.
982 * In particular, don't gratuitiously unselect the
985 * XXX - why do we have to unselect the current packet
986 * ourselves? The documentation for the GtkCList at
988 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
990 * says "Note that setting the widget's selection mode to
991 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
992 * cause all the items in the GtkCList to become deselected."
998 unselect_packet(&cfile);
1000 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
1001 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
1003 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
1006 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
1010 /* Set the font of the packet list window. */
1011 #if GTK_MAJOR_VERSION < 2
1013 set_plist_font(GdkFont *font)
1016 set_plist_font(PangoFontDescription *font)
1020 #if GTK_MAJOR_VERSION < 2
1023 style = gtk_style_new();
1024 gdk_font_unref(style->font);
1028 gtk_widget_set_style(packet_list, style);
1030 PangoLayout *layout;
1032 gtk_widget_modify_font(packet_list, font);
1035 /* Compute static column sizes to use during a "-S" capture, so that
1036 the columns don't resize during a live capture. */
1037 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1038 #if GTK_MAJOR_VERSION < 2
1039 cfile.cinfo.col_width[i] = gdk_string_width(font,
1040 get_column_longest_string(get_column_format(i)));
1042 layout = gtk_widget_create_pango_layout(packet_list,
1043 get_column_longest_string(get_column_format(i)));
1044 pango_layout_get_pixel_size(layout, &cfile.cinfo.col_width[i],
1046 g_object_unref(G_OBJECT(layout));
1052 * Push a message referring to file access onto the statusbar.
1055 statusbar_push_file_msg(gchar *msg)
1057 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
1061 * Pop a message referring to file access off the statusbar.
1064 statusbar_pop_file_msg(void)
1066 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1070 * XXX - do we need multiple statusbar contexts?
1074 * Push a message referring to the currently-selected field onto the statusbar.
1077 statusbar_push_field_msg(gchar *msg)
1079 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
1083 * Pop a message referring to the currently-selected field off the statusbar.
1086 statusbar_pop_field_msg(void)
1088 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
1094 /* XXX - should we check whether the capture file is an
1095 unsaved temporary file for a live capture and, if so,
1096 pop up a "do you want to exit without saving the capture
1097 file?" dialog, and then just return, leaving said dialog
1098 box to forcibly quit if the user clicks "OK"?
1100 If so, note that this should be done in a subroutine that
1101 returns TRUE if we do so, and FALSE otherwise, and if it
1102 returns TRUE we should return TRUE without nuking anything.
1104 Note that, if we do that, we might also want to check if
1105 an "Update list of packets in real time" capture is in
1106 progress and, if so, ask whether they want to terminate
1107 the capture and discard it, and return TRUE, before nuking
1108 any child capture, if they say they don't want to do so. */
1111 /* Nuke any child capture in progress. */
1112 kill_capture_child();
1115 /* Are we in the middle of reading a capture? */
1116 if (cfile.state == FILE_READ_IN_PROGRESS) {
1117 /* Yes, so we can't just close the file and quit, as
1118 that may yank the rug out from under the read in
1119 progress; instead, just set the state to
1120 "FILE_READ_ABORTED" and return - the code doing the read
1121 will check for that and, if it sees that, will clean
1123 cfile.state = FILE_READ_ABORTED;
1125 /* Say that the window should *not* be deleted;
1126 that'll be done by the code that cleans up. */
1129 /* Close any capture file we have open; on some OSes, you
1130 can't unlink a temporary capture file if you have it
1132 "close_cap_file()" will unlink it after closing it if
1133 it's a temporary file.
1135 We do this here, rather than after the main loop returns,
1136 as, after the main loop returns, the main window may have
1137 been destroyed (if this is called due to a "destroy"
1138 even on the main window rather than due to the user
1139 selecting a menu item), and there may be a crash
1140 or other problem when "close_cap_file()" tries to
1141 clean up stuff in the main window.
1143 XXX - is there a better place to put this?
1144 Or should we have a routine that *just* closes the
1145 capture file, and doesn't do anything with the UI,
1146 which we'd call here, and another routine that
1147 calls that routine and also cleans up the UI, which
1148 we'd call elsewhere? */
1149 close_cap_file(&cfile);
1151 /* Exit by leaving the main loop, so that any quit functions
1152 we registered get called. */
1155 /* Say that the window should be deleted. */
1161 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1163 gint desk_x, desk_y;
1165 /* Try to grab our geometry */
1166 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1167 if (gdk_window_get_deskrelative_origin(top_level->window,
1168 &desk_x, &desk_y)) {
1169 if (desk_x <= root_x && desk_y <= root_y) {
1175 /* XXX - Is this the "approved" method? */
1176 gdk_window_get_size(top_level->window, &top_width, &top_height);
1178 /* "do_quit()" indicates whether the main window should be deleted. */
1183 file_quit_cmd_cb (GtkWidget *widget _U_, gpointer data _U_)
1189 print_usage(gboolean print_ver) {
1192 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
1193 comp_info_str->str);
1196 fprintf(stderr, "\n%s [ -vh ] [ -klpQS ] [ -a <capture autostop condition> ] ...\n",
1198 fprintf(stderr, "\t[ -b <number of ringbuffer files> ] [ -B <byte view height> ]\n");
1199 fprintf(stderr, "\t[ -c <count> ] [ -f <capture filter> ] [ -i <interface> ]\n");
1200 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -N <resolving> ]\n");
1201 fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1202 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1203 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1204 fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n");
1206 fprintf(stderr, "\n%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1208 fprintf(stderr, "\t[ -n ] [ -N <resolving> ]\n");
1209 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
1210 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
1211 fprintf(stderr, "\t[ -T <tree view height> ] [ <infile> ]\n");
1222 printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
1226 get_positive_int(const char *string, const char *name)
1231 number = strtol(string, &p, 10);
1232 if (p == string || *p != '\0') {
1233 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1238 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1243 fprintf(stderr, "ethereal: The specified %s \"%s\" is zero\n",
1247 if (number > INT_MAX) {
1248 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1249 name, string, INT_MAX);
1257 * Given a string of the form "<autostop criterion>:<value>", as might appear
1258 * as an argument to a "-a" option, parse it and set the criterion in
1259 * question. Return an indication of whether it succeeded or failed
1263 set_autostop_criterion(const char *autostoparg)
1267 colonp = strchr(autostoparg, ':');
1275 * Skip over any white space (there probably won't be any, but
1276 * as we allow it in the preferences file, we might as well
1283 * Put the colon back, so if our caller uses, in an
1284 * error message, the string they passed us, the message
1290 if (strcmp(autostoparg,"duration") == 0) {
1291 capture_opts.has_autostop_duration = TRUE;
1292 capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1293 } else if (strcmp(autostoparg,"filesize") == 0) {
1294 capture_opts.has_autostop_filesize = TRUE;
1295 capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1299 *colonp = ':'; /* put the colon back */
1304 #if defined WIN32 || GTK_MAJOR_VERSION < 2
1306 Once every 3 seconds we get a callback here which we use to update
1307 the tap extensions. Since Gtk1 is single threaded we dont have to
1308 worry about any locking or critical regions.
1311 update_cb(gpointer data _U_)
1313 draw_tap_listeners(FALSE);
1318 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1319 use threads all updte_thread_mutex can be dropped and protect/unprotect
1320 would just be empty functions.
1322 This allows gtk2-rpcstat.c and friends to be copied unmodified to
1323 gtk1-ethereal and it will just work.
1325 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1327 update_thread(gpointer data _U_)
1331 g_get_current_time(&tv1);
1332 g_static_mutex_lock(&update_thread_mutex);
1333 gdk_threads_enter();
1334 draw_tap_listeners(FALSE);
1335 gdk_threads_leave();
1336 g_static_mutex_unlock(&update_thread_mutex);
1338 g_get_current_time(&tv2);
1339 if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1340 (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1341 g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1342 (tv2.tv_sec * 1000000 + tv2.tv_usec));
1349 protect_thread_critical_region(void)
1351 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2
1352 g_static_mutex_lock(&update_thread_mutex);
1356 unprotect_thread_critical_region(void)
1358 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2
1359 g_static_mutex_unlock(&update_thread_mutex);
1363 /* structure to keep track of what tap listeners have been registered.
1365 typedef struct _ethereal_tap_list {
1366 struct _ethereal_tap_list *next;
1368 void (*func)(char *arg);
1369 } ethereal_tap_list;
1370 static ethereal_tap_list *tap_list=NULL;
1373 register_ethereal_tap(char *cmd, void (*func)(char *arg), char *dummy _U_, void (*dummy2)(void) _U_)
1375 ethereal_tap_list *newtl;
1377 newtl=malloc(sizeof(ethereal_tap_list));
1378 newtl->next=tap_list;
1385 /* And now our feature presentation... [ fade to music ] */
1387 main(int argc, char *argv[])
1395 extern char *optarg;
1396 gboolean arg_error = FALSE;
1398 #ifdef HAVE_PCAP_VERSION
1399 extern char pcap_version[];
1400 #endif /* HAVE_PCAP_VERSION */
1401 #endif /* HAVE_LIBPCAP */
1407 char *gpf_path, *cf_path, *df_path;
1409 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
1412 gboolean start_capture = FALSE;
1413 gchar *save_file = NULL;
1415 gchar err_str[PCAP_ERRBUF_SIZE];
1416 gboolean stats_known;
1417 struct pcap_stat stats;
1419 gboolean capture_option_specified = FALSE;
1421 gint pl_size = 280, tv_size = 95, bv_size = 75;
1422 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1423 dfilter_t *rfcode = NULL;
1424 gboolean rfilter_parse_failed = FALSE;
1427 #if GTK_MAJOR_VERSION < 2
1428 char *bold_font_name;
1430 gint desk_x, desk_y;
1431 gboolean prefs_write_needed = FALSE;
1432 ethereal_tap_list *tli = NULL;
1433 gchar *tap_opt = NULL;
1435 #define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vz:"
1439 #define OPTSTRING_CHILD "W:Z:"
1441 #define OPTSTRING_CHILD "W:"
1444 #define OPTSTRING_CHILD ""
1445 #endif /* HAVE_LIBPCAP */
1447 char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1450 ethereal_path = argv[0];
1453 /* Arrange that if we have no console window, and a GLib message logging
1454 routine is called to log a message, we pop up a console window.
1456 We do that by inserting our own handler for all messages logged
1457 to the default domain; that handler pops up a console if necessary,
1458 and then calls the default handler. */
1459 g_log_set_handler(NULL,
1461 G_LOG_LEVEL_CRITICAL|
1462 G_LOG_LEVEL_WARNING|
1463 G_LOG_LEVEL_MESSAGE|
1466 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1467 console_log_handler, NULL);
1471 command_name = get_basename(ethereal_path);
1472 /* Set "capture_child" to indicate whether this is going to be a child
1473 process for a "-S" capture. */
1474 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1476 strcat(optstring, OPTSTRING_CHILD);
1479 /* Register all dissectors; we must do this before checking for the
1480 "-G" flag, as the "-G" flag dumps information registered by the
1481 dissectors, and we must do it before we read the preferences, in
1482 case any dissectors register preferences. */
1483 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
1484 register_all_tap_listeners();
1486 /* Now register the preferences for any non-dissector modules.
1487 We must do that before we read the preferences as well. */
1488 prefs_register_modules();
1490 /* If invoked with the "-G" flag, we dump out information based on
1491 the argument to the "-G" flag; if no argument is specified,
1492 for backwards compatibility we dump out a glossary of display
1495 We must do this before calling "gtk_init()", because "gtk_init()"
1496 tries to open an X display, and we don't want to have to do any X
1497 stuff just to do a build.
1499 Given that we call "gtk_init()" before doing the regular argument
1500 list processing, so that it can handle X and GTK+ arguments and
1501 remove them from the list at which we look, this means we must do
1502 this before doing the regular argument list processing, as well.
1506 you must give the "-G" flag as the first flag on the command line;
1508 you must give it as "-G", nothing more, nothing less;
1510 the first argument after the "-G" flag, if present, will be used
1511 to specify the information to dump;
1513 arguments after that will not be used. */
1514 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1516 proto_registrar_dump_fields();
1518 if (strcmp(argv[2], "fields") == 0)
1519 proto_registrar_dump_fields();
1520 else if (strcmp(argv[2], "protocols") == 0)
1521 proto_registrar_dump_protocols();
1523 fprintf(stderr, "tethereal: Invalid \"%s\" option for -G flag\n",
1531 /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1532 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined G_THREADS_ENABLED
1535 g_thread_init(NULL);
1537 ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1538 g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1540 #else /* WIN32 || GTK1.2 || !G_THREADS_ENABLED */
1541 /* this is to keep tap extensions updating once every 3 seconds */
1542 gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1543 #endif /* !WIN32 && GTK2 && G_THREADS_ENABLED */
1545 /* Set the current locale according to the program environment.
1546 * We haven't localized anything, but some GTK widgets are localized
1547 * (the file selection dialogue, for example).
1548 * This also sets the C-language locale to the native environment. */
1551 /* Let GTK get its args */
1552 gtk_init (&argc, &argv);
1554 /* Read the preference files. */
1555 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1558 capture_opts.has_snaplen = FALSE;
1559 capture_opts.snaplen = MIN_PACKET_SIZE;
1560 capture_opts.has_autostop_count = FALSE;
1561 capture_opts.autostop_count = 1;
1562 capture_opts.has_autostop_duration = FALSE;
1563 capture_opts.autostop_duration = 1;
1564 capture_opts.has_autostop_filesize = FALSE;
1565 capture_opts.autostop_filesize = 1;
1566 capture_opts.ringbuffer_on = FALSE;
1567 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1569 /* If this is a capture child process, it should pay no attention
1570 to the "prefs.capture_prom_mode" setting in the preferences file;
1571 it should do what the parent process tells it to do, and if
1572 the parent process wants it not to run in promiscuous mode, it'll
1573 tell it so with a "-p" flag.
1575 Otherwise, set promiscuous mode from the preferences setting. */
1577 capture_opts.promisc_mode = TRUE;
1579 capture_opts.promisc_mode = prefs->capture_prom_mode;
1581 /* Set "Update list of packets in real time" mode from the preferences
1583 capture_opts.sync_mode = prefs->capture_real_time;
1585 /* And do the same for "Automatic scrolling in live capture" mode. */
1586 auto_scroll_live = prefs->capture_auto_scroll;
1589 /* Set the name resolution code's flags from the preferences. */
1590 g_resolv_flags = prefs->name_resolve;
1592 /* Read the capture filter file. */
1593 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1595 /* Read the display filter file. */
1596 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1598 init_cap_file(&cfile);
1600 /* Assemble the compile-time options */
1601 comp_info_str = g_string_new("");
1603 g_string_append(comp_info_str, "with ");
1604 g_string_sprintfa(comp_info_str,
1605 #ifdef GTK_MAJOR_VERSION
1606 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1609 "GTK+ (version unknown)");
1612 g_string_append(comp_info_str, ", with ");
1613 g_string_sprintfa(comp_info_str,
1614 #ifdef GLIB_MAJOR_VERSION
1615 "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
1616 GLIB_MICRO_VERSION);
1618 "GLib (version unknown)");
1622 g_string_append(comp_info_str, ", with libpcap ");
1623 #ifdef HAVE_PCAP_VERSION
1624 g_string_append(comp_info_str, pcap_version);
1625 #else /* HAVE_PCAP_VERSION */
1626 g_string_append(comp_info_str, "(version unknown)");
1627 #endif /* HAVE_PCAP_VERSION */
1628 #else /* HAVE_LIBPCAP */
1629 g_string_append(comp_info_str, ", without libpcap");
1630 #endif /* HAVE_LIBPCAP */
1633 g_string_append(comp_info_str, ", with libz ");
1635 g_string_append(comp_info_str, ZLIB_VERSION);
1636 #else /* ZLIB_VERSION */
1637 g_string_append(comp_info_str, "(version unknown)");
1638 #endif /* ZLIB_VERSION */
1639 #else /* HAVE_LIBZ */
1640 g_string_append(comp_info_str, ", without libz");
1641 #endif /* HAVE_LIBZ */
1643 /* Oh, this is pretty. */
1644 /* Oh, ha. you think that was pretty. Try this:! --Wes */
1645 #ifdef HAVE_SOME_SNMP
1647 #ifdef HAVE_UCD_SNMP
1648 g_string_append(comp_info_str, ", with UCD-SNMP ");
1649 g_string_append(comp_info_str, VersionInfo);
1650 #endif /* HAVE_UCD_SNMP */
1652 #ifdef HAVE_NET_SNMP
1653 g_string_append(comp_info_str, ", with Net-SNMP ");
1654 g_string_append(comp_info_str, netsnmp_get_version());
1655 #endif /* HAVE_NET_SNMP */
1657 #else /* no SNMP library */
1658 g_string_append(comp_info_str, ", without UCD-SNMP or Net-SNMP");
1659 #endif /* HAVE_SOME_SNMP */
1661 /* Now get our args */
1662 while ((opt = getopt(argc, argv, optstring)) != -1) {
1664 case 'a': /* autostop criteria */
1666 if (set_autostop_criterion(optarg) == FALSE) {
1667 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1671 capture_option_specified = TRUE;
1675 case 'b': /* Ringbuffer option */
1677 capture_opts.ringbuffer_on = TRUE;
1678 capture_opts.ringbuffer_num_files =
1679 get_positive_int(optarg, "number of ring buffer files");
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_init(&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_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2029 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2033 if (capture_opts.has_snaplen) {
2034 if (capture_opts.snaplen < 1)
2035 capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
2036 else if (capture_opts.snaplen < MIN_PACKET_SIZE)
2037 capture_opts.snaplen = MIN_PACKET_SIZE;
2040 /* Check the value range of the ringbuffer_num_files parameter */
2041 if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
2042 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
2043 else if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
2044 capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
2047 rc_file = get_persconffile_path(RC_FILE, FALSE);
2048 gtk_rc_parse(rc_file);
2050 /* Try to load the regular and boldface fixed-width fonts */
2051 #if GTK_MAJOR_VERSION < 2
2052 bold_font_name = boldify(prefs->gui_font_name);
2053 m_r_font = gdk_font_load(prefs->gui_font_name);
2054 m_b_font = gdk_font_load(bold_font_name);
2056 m_r_font = pango_font_description_from_string(prefs->gui_font_name);
2057 m_b_font = pango_font_description_copy(m_r_font);
2058 pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2060 if (m_r_font == NULL || m_b_font == NULL) {
2061 /* XXX - pop this up as a dialog box? no */
2062 if (m_r_font == NULL) {
2066 #if GTK_MAJOR_VERSION < 2
2067 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2069 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to Monospace 9\n",
2071 prefs->gui_font_name);
2073 #if GTK_MAJOR_VERSION < 2
2074 gdk_font_unref(m_r_font);
2076 pango_font_description_free(m_r_font);
2079 if (m_b_font == NULL) {
2083 #if GTK_MAJOR_VERSION < 2
2084 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2087 fprintf(stderr, "ethereal: Warning: bold font %s not found - defaulting"
2088 " to Monospace 9\n", prefs->gui_font_name);
2091 #if GTK_MAJOR_VERSION < 2
2092 gdk_font_unref(m_b_font);
2094 pango_font_description_free(m_b_font);
2097 #if GTK_MAJOR_VERSION < 2
2098 g_free(bold_font_name);
2099 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
2100 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
2102 if ((m_r_font = pango_font_description_from_string("Monospace 9")) == NULL)
2104 fprintf(stderr, "ethereal: Error: font Monospace 9 not found\n");
2108 #if GTK_MAJOR_VERSION < 2
2109 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
2110 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
2112 if ((m_b_font = pango_font_description_copy(m_r_font)) == NULL) {
2113 fprintf(stderr, "ethereal: Error: font Monospace 9 bold not found\n");
2117 g_free(prefs->gui_font_name);
2118 #if GTK_MAJOR_VERSION < 2
2119 prefs->gui_font_name = g_strdup("6x13");
2121 pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2122 prefs->gui_font_name = g_strdup("Monospace 9");
2126 /* Call this for the side-effects that set_fonts() produces */
2127 set_fonts(m_r_font, m_b_font);
2131 /* Is this a "child" ethereal, which is only supposed to pop up a
2132 capture box to let us stop the capture, and run a capture
2133 to a file that our parent will read? */
2134 if (!capture_child) {
2136 /* No. Pop up the main window, and read in a capture file if
2139 create_main_window(pl_size, tv_size, bv_size, prefs);
2140 set_menus_for_capture_file(FALSE);
2142 /* open tap windows after creating the main window to avoid GTK warnings */
2143 if (tap_opt && tli) {
2144 (*tli->func)(tap_opt);
2151 /* If we were given the name of a capture file, read it in now;
2152 we defer it until now, so that, if we can't open it, and pop
2153 up an alert box, the alert box is more likely to come up on
2154 top of the main window - but before the preference-file-error
2155 alert box, so, if we get one of those, it's more likely to come
2158 if (rfilter != NULL) {
2159 if (!dfilter_compile(rfilter, &rfcode)) {
2160 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
2161 rfilter_parse_failed = TRUE;
2164 if (!rfilter_parse_failed) {
2165 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
2166 /* "open_cap_file()" succeeded, so it closed the previous
2167 capture file, and thus destroyed any previous read filter
2168 attached to "cf". */
2169 cfile.rfcode = rfcode;
2170 switch (read_cap_file(&cfile, &err)) {
2174 /* Just because we got an error, that doesn't mean we were unable
2175 to read any of the file; we handle what we could get from the
2184 /* Save the name of the containing directory specified in the
2185 path name, if any; we can write over cf_name, which is a
2186 good thing, given that "get_dirname()" does write over its
2188 s = get_dirname(cf_name);
2189 set_last_open_dir(s);
2194 dfilter_free(rfcode);
2195 cfile.rfcode = NULL;
2203 /* If the global preferences file exists but we failed to open it,
2204 pop up an alert box; we defer that until now, so that the alert
2205 box is more likely to come up on top of the main window. */
2206 if (gpf_path != NULL) {
2207 simple_dialog(ESD_TYPE_WARN, NULL,
2208 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
2209 strerror(gpf_open_errno));
2212 /* If the user's preferences file exists but we failed to open it,
2213 pop up an alert box; we defer that until now, so that the alert
2214 box is more likely to come up on top of the main window. */
2215 if (pf_path != NULL) {
2216 simple_dialog(ESD_TYPE_WARN, NULL,
2217 "Could not open your preferences file\n\"%s\": %s.", pf_path,
2218 strerror(pf_open_errno));
2223 /* If the user's capture filter file exists but we failed to open it,
2224 pop up an alert box; we defer that until now, so that the alert
2225 box is more likely to come up on top of the main window. */
2226 if (cf_path != NULL) {
2227 simple_dialog(ESD_TYPE_WARN, NULL,
2228 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2229 strerror(cf_open_errno));
2233 /* If the user's display filter file exists but we failed to open it,
2234 pop up an alert box; we defer that until now, so that the alert
2235 box is more likely to come up on top of the main window. */
2236 if (df_path != NULL) {
2237 simple_dialog(ESD_TYPE_WARN, NULL,
2238 "Could not open your display filter file\n\"%s\": %s.", df_path,
2239 strerror(df_open_errno));
2244 if (capture_child) {
2245 /* This is the child process for a sync mode or fork mode capture,
2246 so just do the low-level work of a capture - don't create
2247 a temporary file and fork off *another* child process (so don't
2248 call "do_capture()"). */
2250 /* XXX - hand these stats to the parent process */
2251 capture(&stats_known, &stats);
2253 /* The capture is done; there's nothing more for us to do. */
2256 if (start_capture) {
2257 /* "-k" was specified; start a capture. */
2258 do_capture(save_file);
2259 if (save_file != NULL) {
2260 /* Save the directory name for future file dialogs. */
2261 s = get_dirname(save_file); /* Overwrites save_file */
2262 set_last_open_dir(s);
2268 set_menus_for_capture_in_progress(FALSE);
2272 set_menus_for_capture_in_progress(FALSE);
2277 /* Try to save our geometry. GTK+ provides two routines to get a
2278 window's position relative to the X root window. If I understand the
2279 documentation correctly, gdk_window_get_deskrelative_origin applies
2280 mainly to Enlightenment and gdk_window_get_root_origin applies for
2283 The code below tries both routines, and picks the one that returns
2284 the upper-left-most coordinates.
2288 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
2289 http://www.gtk.org/faq/#AEN600 */
2291 /* Re-read our saved preferences. */
2292 /* XXX - Move all of this into a separate function? */
2293 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
2295 if (pf_path == NULL) {
2296 if (prefs->gui_geometry_save_position) {
2297 if (top_level->window != NULL) {
2298 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
2299 if (gdk_window_get_deskrelative_origin(top_level->window,
2300 &desk_x, &desk_y)) {
2301 if (desk_x <= root_x && desk_y <= root_y) {
2307 if (prefs->gui_geometry_main_x != root_x) {
2308 prefs->gui_geometry_main_x = root_x;
2309 prefs_write_needed = TRUE;
2311 if (prefs->gui_geometry_main_y != root_y) {
2312 prefs->gui_geometry_main_y = root_y;
2313 prefs_write_needed = TRUE;
2317 if (prefs->gui_geometry_save_size) {
2318 if (top_level->window != NULL) {
2319 /* XXX - Is this the "approved" method? */
2320 gdk_window_get_size(top_level->window, &top_width, &top_height);
2322 if (prefs->gui_geometry_main_width != top_width) {
2323 prefs->gui_geometry_main_width = top_width;
2324 prefs_write_needed = TRUE;
2326 if (prefs->gui_geometry_main_height != top_height) {
2327 prefs->gui_geometry_main_height = top_height;
2328 prefs_write_needed = TRUE;
2332 if (prefs_write_needed) {
2333 write_prefs(&pf_path);
2336 /* Ignore errors silently */
2344 /* Shutdown windows sockets */
2347 /* For some unknown reason, the "atexit()" call in "create_console()"
2348 doesn't arrange that "destroy_console()" be called when we exit,
2349 so we call it here if a console was created. */
2350 if (console_was_created)
2356 /* This isn't reached, but we need it to keep GCC from complaining
2357 that "main()" returns without returning a value - it knows that
2358 "exit()" never returns, but it doesn't know that "gtk_exit()"
2359 doesn't, as GTK+ doesn't declare it with the attribute
2361 return 0; /* not reached */
2366 /* We build this as a GUI subsystem application on Win32, so
2367 "WinMain()", not "main()", gets called.
2369 Hack shamelessly stolen from the Win32 port of the GIMP. */
2371 #define _stdcall __attribute__((stdcall))
2375 WinMain (struct HINSTANCE__ *hInstance,
2376 struct HINSTANCE__ *hPrevInstance,
2380 has_no_console = TRUE;
2381 return main (__argc, __argv);
2385 * If this application has no console window to which its standard output
2386 * would go, create one.
2389 create_console(void)
2391 if (has_no_console) {
2392 /* We have no console to which to print the version string, so
2393 create one and make it the standard input, output, and error. */
2394 if (!AllocConsole())
2395 return; /* couldn't create console */
2396 freopen("CONIN$", "r", stdin);
2397 freopen("CONOUT$", "w", stdout);
2398 freopen("CONOUT$", "w", stderr);
2400 /* Well, we have a console now. */
2401 has_no_console = FALSE;
2402 console_was_created = TRUE;
2404 /* Now register "destroy_console()" as a routine to be called just
2405 before the application exits, so that we can destroy the console
2406 after the user has typed a key (so that the console doesn't just
2407 disappear out from under them, giving the user no chance to see
2408 the message(s) we put in there). */
2409 atexit(destroy_console);
2414 destroy_console(void)
2416 printf("\n\nPress any key to exit\n");
2421 /* This routine should not be necessary, at least as I read the GLib
2422 source code, as it looks as if GLib is, on Win32, *supposed* to
2423 create a console window into which to display its output.
2425 That doesn't happen, however. I suspect there's something completely
2426 broken about that code in GLib-for-Win32, and that it may be related
2427 to the breakage that forces us to just call "printf()" on the message
2428 rather than passing the message on to "g_log_default_handler()"
2429 (which is the routine that does the aforementioned non-functional
2430 console window creation). */
2432 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2433 const char *message, gpointer user_data)
2436 if (console_was_created) {
2437 /* For some unknown reason, the above doesn't appear to actually cause
2438 anything to be sent to the standard output, so we'll just splat the
2439 message out directly, just to make sure it gets out. */
2440 printf("%s\n", message);
2442 g_log_default_handler(log_domain, log_level, message, user_data);
2446 #if GTK_MAJOR_VERSION < 2
2447 /* Given a font name, construct the name of the next heavier version of
2450 #define XLFD_WEIGHT 3 /* index of the "weight" field */
2452 /* Map from a given weight to the appropriate weight for the "bold"
2454 XXX - the XLFD says these strings shouldn't be used for font matching;
2455 can we get the weight, as a number, from GDK, and ask GDK to find us
2456 a font just like the given font, but with the appropriate higher
2458 static const struct {
2462 { "ultralight", "light" },
2463 { "extralight", "semilight" },
2464 { "light", "medium" },
2465 { "semilight", "semibold" },
2466 { "medium", "bold" },
2467 { "normal", "bold" },
2468 { "semibold", "extrabold" },
2469 { "bold", "ultrabold" }
2471 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
2474 boldify(const char *font_name)
2476 char *bold_font_name;
2477 gchar **xlfd_tokens;
2480 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
2481 if (font_name[0] == '-') {
2482 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
2485 * Make sure we *have* a weight (this might not be a valid
2488 for (i = 0; i < XLFD_WEIGHT+1; i++) {
2489 if (xlfd_tokens[i] == NULL) {
2491 * We don't, so treat this as a non-XLFD
2497 for (i = 0; i < N_WEIGHTS; i++) {
2498 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
2499 weight_map[i].light) == 0) {
2500 g_free(xlfd_tokens[XLFD_WEIGHT]);
2501 xlfd_tokens[XLFD_WEIGHT] =
2502 g_strdup(weight_map[i].heavier);
2506 bold_font_name = g_strjoinv("-", xlfd_tokens);
2507 g_strfreev(xlfd_tokens);
2508 return bold_font_name;
2513 * This isn't an XLFD font name; just append "bold" to the name
2516 bold_font_name = g_strconcat(font_name, "bold", NULL);
2517 return bold_font_name;
2522 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2524 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
2525 *stat_hbox, *column_lb,
2526 *filter_bt, *filter_cm, *filter_te,
2529 GList *filter_list = NULL;
2530 GtkAccelGroup *accel;
2531 GtkStyle *win_style;
2532 GdkBitmap *ascend_bm, *descend_bm;
2533 GdkPixmap *ascend_pm, *descend_pm;
2534 column_arrows *col_arrows;
2536 /* Display filter construct dialog has an Apply button, and "OK" not
2537 only sets our text widget, it activates it (i.e., it causes us to
2538 filter the capture). */
2539 static construct_args_t args = {
2540 "Ethereal: Display Filter",
2546 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2547 gtk_widget_set_name(top_level, "main window");
2548 SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
2550 SIGNAL_CONNECT(top_level, "realize", window_icon_realize_cb, NULL);
2551 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
2552 if (prefs->gui_geometry_save_position) {
2553 gtk_widget_set_uposition(GTK_WIDGET(top_level),
2554 prefs->gui_geometry_main_x,
2555 prefs->gui_geometry_main_y);
2557 if (prefs->gui_geometry_save_size) {
2558 WIDGET_SET_SIZE(top_level, prefs->gui_geometry_main_width,
2559 prefs->gui_geometry_main_height);
2561 WIDGET_SET_SIZE(top_level, DEF_WIDTH, -1);
2563 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2565 /* Container for menu bar, paned windows and progress/info box */
2566 main_vbox = gtk_vbox_new(FALSE, 1);
2567 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2568 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2569 gtk_widget_show(main_vbox);
2572 get_main_menu(&menubar, &accel);
2573 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2574 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2575 gtk_widget_show(menubar);
2577 /* Panes for the packet list, tree, and byte view */
2578 u_pane = gtk_vpaned_new();
2579 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
2580 l_pane = gtk_vpaned_new();
2581 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
2582 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
2583 gtk_widget_show(l_pane);
2584 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
2585 gtk_widget_show(u_pane);
2588 pkt_scrollw = scrolled_window_new(NULL, NULL);
2589 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
2590 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2591 gtk_widget_show(pkt_scrollw);
2592 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
2594 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
2595 /* Column titles are filled in below */
2596 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
2598 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
2599 cfile.cinfo.num_cols);
2601 set_plist_sel_browse(prefs->gui_plist_sel_browse);
2602 set_plist_font(m_r_font);
2603 gtk_widget_set_name(packet_list, "packet list");
2604 SIGNAL_CONNECT(packet_list, "click-column", packet_list_click_column_cb,
2606 SIGNAL_CONNECT(packet_list, "select-row", packet_list_select_cb, NULL);
2607 SIGNAL_CONNECT(packet_list, "unselect-row", packet_list_unselect_cb, NULL);
2608 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2609 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
2610 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
2612 /* Right-justify the packet number column. */
2613 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
2614 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
2617 WIDGET_SET_SIZE(packet_list, -1, pl_size);
2618 SIGNAL_CONNECT(packet_list, "button_press_event", popup_menu_handler,
2619 OBJECT_GET_DATA(popup_menu_object, PM_PACKET_LIST_KEY));
2620 SIGNAL_CONNECT(packet_list, "button_press_event",
2621 packet_list_button_pressed_cb, NULL);
2622 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
2623 gtk_widget_show(packet_list);
2626 #if GTK_MAJOR_VERSION < 2
2627 item_style = gtk_style_new();
2628 gdk_font_unref(item_style->font);
2629 item_style->font = m_r_font;
2631 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view);
2632 #if GTK_MAJOR_VERSION < 2
2633 SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
2634 SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
2637 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
2638 "changed", tree_view_selection_changed_cb, NULL);
2640 SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
2641 OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
2642 gtk_widget_show(tree_view);
2645 byte_nb_ptr = create_byte_view(bv_size, l_pane);
2647 SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
2648 OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
2650 /* Filter/info box */
2651 stat_hbox = gtk_hbox_new(FALSE, 1);
2652 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
2653 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2654 gtk_widget_show(stat_hbox);
2656 filter_bt = gtk_button_new_with_label("Filter:");
2657 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
2658 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
2659 gtk_widget_show(filter_bt);
2661 filter_cm = gtk_combo_new();
2662 filter_list = g_list_append (filter_list, "");
2663 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
2664 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
2665 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
2666 OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
2667 filter_te = GTK_COMBO(filter_cm)->entry;
2668 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
2669 OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
2670 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
2671 SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
2672 gtk_widget_show(filter_cm);
2674 #if GTK_MAJOR_VERSION < 2
2675 filter_reset = gtk_button_new_with_label("Reset");
2677 filter_reset = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
2679 OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
2680 SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
2681 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
2682 gtk_widget_show(filter_reset);
2684 #if GTK_MAJOR_VERSION < 2
2685 filter_apply = gtk_button_new_with_label("Apply");
2687 filter_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
2689 OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
2690 SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
2691 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_apply, FALSE, TRUE, 1);
2692 gtk_widget_show(filter_apply);
2694 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
2695 * of any widget that ends up calling a callback which needs
2696 * that text entry pointer */
2697 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
2698 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
2699 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
2700 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
2702 set_menu_object_data("/Display/Match/Selected", E_DFILTER_TE_KEY,
2704 set_menu_object_data("/Display/Match/Not Selected", E_DFILTER_TE_KEY,
2706 set_menu_object_data("/Display/Match/And Selected", E_DFILTER_TE_KEY,
2708 set_menu_object_data("/Display/Match/Or Selected", E_DFILTER_TE_KEY,
2710 set_menu_object_data("/Display/Match/And Not Selected", E_DFILTER_TE_KEY,
2712 set_menu_object_data("/Display/Match/Or Not Selected", E_DFILTER_TE_KEY,
2714 set_menu_object_data("/Display/Prepare/Selected", E_DFILTER_TE_KEY,
2716 set_menu_object_data("/Display/Prepare/Not Selected", E_DFILTER_TE_KEY,
2718 set_menu_object_data("/Display/Prepare/And Selected", E_DFILTER_TE_KEY,
2720 set_menu_object_data("/Display/Prepare/Or Selected", E_DFILTER_TE_KEY,
2722 set_menu_object_data("/Display/Prepare/And Not Selected", E_DFILTER_TE_KEY,
2724 set_menu_object_data("/Display/Prepare/Or Not Selected", E_DFILTER_TE_KEY,
2726 OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
2727 OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
2729 info_bar = gtk_statusbar_new();
2730 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2731 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2732 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2733 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2734 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2735 gtk_widget_show(info_bar);
2737 gtk_widget_show(top_level);
2739 /* Fill in column titles. This must be done after the top level window
2741 win_style = gtk_widget_get_style(top_level);
2742 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
2743 &win_style->bg[GTK_STATE_NORMAL],
2744 (gchar **)clist_ascend_xpm);
2745 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
2746 &win_style->bg[GTK_STATE_NORMAL],
2747 (gchar **)clist_descend_xpm);
2748 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2749 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
2750 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
2751 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
2752 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
2753 GTK_SHRINK, GTK_SHRINK, 0, 0);
2754 gtk_widget_show(column_lb);
2755 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
2756 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
2757 col_arrows[i].ascend_pm,
2758 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
2760 gtk_widget_show(col_arrows[i].ascend_pm);
2762 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
2763 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
2764 col_arrows[i].descend_pm,
2765 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
2766 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i,
2767 col_arrows[i].table);
2768 gtk_widget_show(col_arrows[i].table);
2770 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
2775 set_last_open_dir(char *dirname)
2779 if (last_open_dir) {
2780 g_free(last_open_dir);
2784 len = strlen(dirname);
2785 if (dirname[len-1] == G_DIR_SEPARATOR) {
2786 last_open_dir = g_strconcat(dirname, NULL);
2789 last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
2794 last_open_dir = NULL;