3 * $Id: main.c,v 1.240 2002/03/05 12:03:26 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.
31 * - Check for end of packet in dissect_* routines.
33 * - Multiple window support
34 * - Add cut/copy/paste
35 * - Create header parsing routines
36 * - Make byte view selections more fancy?
57 #ifdef HAVE_SYS_TYPES_H
58 #include <sys/types.h>
61 #ifdef HAVE_SYS_STAT_H
66 #include <io.h> /* open/close on win32 */
73 #ifdef HAVE_NETINET_IN_H
74 #include <netinet/in.h>
84 #include <zlib.h> /* to get the libz version number */
87 #ifdef NEED_SNPRINTF_H
88 # include "snprintf.h"
91 #if defined(HAVE_UCD_SNMP_SNMP_H)
92 #ifdef HAVE_UCD_SNMP_VERSION_H
93 #include <ucd-snmp/version.h>
94 #endif /* HAVE_UCD_SNMP_VERSION_H */
95 #elif defined(HAVE_SNMP_SNMP_H)
96 #ifdef HAVE_SNMP_VERSION_H
97 #include <snmp/version.h>
98 #endif /* HAVE_SNMP_VERSION_H */
101 #ifdef NEED_STRERROR_H
102 #include "strerror.h"
109 #ifdef WIN32 /* Needed for console I/O */
114 #include <epan/epan.h>
115 #include <epan/filesystem.h>
116 #include <epan/epan_dissect.h>
119 #include <epan/timestamp.h>
120 #include <epan/packet.h>
129 #include "color_utils.h"
130 #include "filter_prefs.h"
131 #include "file_dlg.h"
134 #include <epan/resolv.h>
136 #include "pcap-util.h"
138 #include "statusbar.h"
139 #include "simple_dialog.h"
140 #include "proto_draw.h"
141 #include <epan/dfilter/dfilter.h>
143 #include "packet_win.h"
144 #include "gtkglobals.h"
145 #include <epan/plugins.h>
147 #include <epan/strutil.h>
148 #include "register.h"
149 #include "ringbuffer.h"
151 #include "image/clist_ascend.xpm"
152 #include "image/clist_descend.xpm"
155 #include "capture-wpcap.h"
158 typedef struct column_arrows {
160 GtkWidget *ascend_pm;
161 GtkWidget *descend_pm;
165 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
166 *tv_scrollw, *pkt_scrollw;
167 static GtkWidget *info_bar;
168 GdkFont *m_r_font, *m_b_font;
169 guint m_font_height, m_font_width;
170 static guint main_ctx, file_ctx, help_ctx;
171 static GString *comp_info_str;
172 gchar *ethereal_path = NULL;
173 gchar *last_open_dir = NULL;
174 gint root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
176 ts_type timestamp_type = RELATIVE;
178 GtkStyle *item_style;
180 /* Specifies the field currently selected in the GUI protocol tree */
181 field_info *finfo_selected = NULL;
184 static gboolean has_no_console; /* TRUE if app has no console */
185 static gboolean console_was_created; /* TRUE if console was created */
186 static void create_console(void);
187 static void destroy_console(void);
188 static void console_log_handler(const char *log_domain,
189 GLogLevelFlags log_level, const char *message, gpointer user_data);
192 static void create_main_window(gint, gint, gint, e_prefs*);
194 /* About Ethereal window */
196 about_ethereal( GtkWidget *w _U_, gpointer data _U_ ) {
197 simple_dialog(ESD_TYPE_INFO, NULL,
198 "Ethereal - Network Protocol Analyzer\n"
199 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
202 "Check the man page for complete documentation and\n"
203 "for the list of contributors.\n"
205 "\nSee http://www.ethereal.com/ for more information.",
210 set_fonts(GdkFont *regular, GdkFont *bold)
212 /* Yes, assert. The code that loads the font should check
213 * for NULL and provide its own error message. */
214 g_assert(m_r_font && m_b_font);
218 m_font_height = m_r_font->ascent + m_r_font->descent;
219 m_font_width = gdk_string_width(m_r_font, "0");
223 /* Match selected byte pattern */
225 match_selected_cb_do(gpointer data, int action, gchar *text)
228 GtkWidget *filter_te;
233 filter_te = gtk_object_get_data(GTK_OBJECT(data), E_DFILTER_TE_KEY);
236 ptr = gtk_editable_get_chars(GTK_EDITABLE(filter_te),0,-1);
238 switch (action&MATCH_SELECTED_MASK) {
240 case MATCH_SELECTED_REPLACE:
241 ptr = g_strdup(text);
244 case MATCH_SELECTED_AND:
245 if ((!ptr) || (0 == strlen(ptr)))
246 ptr = g_strdup(text);
248 ptr = g_strconcat("(", ptr, ") && (", text, ")", NULL);
251 case MATCH_SELECTED_OR:
252 if ((!ptr) || (0 == strlen(ptr)))
253 ptr = g_strdup(text);
255 ptr = g_strconcat("(", ptr, ") || (", text, ")", NULL);
258 case MATCH_SELECTED_NOT:
259 ptr = g_strconcat("!(", text, ")", NULL);
262 case MATCH_SELECTED_AND_NOT:
263 if ((!ptr) || (0 == strlen(ptr)))
264 ptr = g_strconcat("!(", text, ")", NULL);
266 ptr = g_strconcat("(", ptr, ") && !(", text, ")", NULL);
269 case MATCH_SELECTED_OR_NOT:
270 if ((!ptr) || (0 == strlen(ptr)))
271 ptr = g_strconcat("!(", text, ")", NULL);
273 ptr = g_strconcat("(", ptr, ") || !(", text, ")", NULL);
280 /* create a new one and set the display filter entry accordingly */
281 gtk_entry_set_text(GTK_ENTRY(filter_te), ptr);
283 /* Run the display filter so it goes in effect. */
284 if (action&MATCH_SELECTED_APPLY_NOW)
285 filter_packets(&cfile, ptr);
287 /* Don't g_free(ptr) here. filter_packets() will do it the next time
293 match_selected_cb_replace(GtkWidget *w, gpointer data)
296 match_selected_cb_do((data ? data : w),
297 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
298 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
302 match_selected_cb_and(GtkWidget *w, gpointer data)
305 match_selected_cb_do((data ? data : w),
306 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
307 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
311 match_selected_cb_or(GtkWidget *w, gpointer data)
314 match_selected_cb_do((data ? data : w),
315 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
316 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
320 match_selected_cb_not(GtkWidget *w, gpointer data)
323 match_selected_cb_do((data ? data : w),
324 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
325 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
329 match_selected_cb_and_not(GtkWidget *w, gpointer data)
332 match_selected_cb_do((data ? data : w),
333 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
334 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
338 match_selected_cb_or_not(GtkWidget *w, gpointer data)
341 match_selected_cb_do((data ? data : w),
342 MATCH_SELECTED_OR_NOT,
343 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
347 prepare_selected_cb_replace(GtkWidget *w, gpointer data)
350 match_selected_cb_do((data ? data : w),
351 MATCH_SELECTED_REPLACE,
352 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
356 prepare_selected_cb_and(GtkWidget *w, gpointer data)
359 match_selected_cb_do((data ? data : w),
361 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
365 prepare_selected_cb_or(GtkWidget *w, gpointer data)
368 match_selected_cb_do((data ? data : w),
370 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
374 prepare_selected_cb_not(GtkWidget *w, gpointer data)
377 match_selected_cb_do((data ? data : w),
379 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
383 prepare_selected_cb_and_not(GtkWidget *w, gpointer data)
386 match_selected_cb_do((data ? data : w),
387 MATCH_SELECTED_AND_NOT,
388 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
392 prepare_selected_cb_or_not(GtkWidget *w, gpointer data)
395 match_selected_cb_do((data ? data : w),
396 MATCH_SELECTED_OR_NOT,
397 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
401 get_text_from_packet_list(gpointer data)
403 gint row = (gint)gtk_object_get_data(GTK_OBJECT(data), E_MPACKET_LIST_ROW_KEY);
404 gint column = (gint)gtk_object_get_data(GTK_OBJECT(data), E_MPACKET_LIST_COL_KEY);
405 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
412 /* XXX - do something with "err" */
413 wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
414 cfile.pd, fdata->cap_len, &err);
416 edt = epan_dissect_new(FALSE, FALSE);
417 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
419 epan_dissect_fill_in_columns(edt);
421 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
422 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
423 len = strlen(cfile.cinfo.col_expr[column]) +
424 strlen(cfile.cinfo.col_expr_val[column]) + 5;
425 buf = g_malloc0(len);
426 snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
427 cfile.cinfo.col_expr_val[column]);
430 epan_dissect_free(edt);
437 match_selected_cb_replace2(GtkWidget *w _U_, gpointer data)
439 match_selected_cb_do(data,
440 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
441 get_text_from_packet_list(data));
445 match_selected_cb_and2(GtkWidget *w _U_, gpointer data)
447 match_selected_cb_do(data,
448 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
449 get_text_from_packet_list(data));
453 match_selected_cb_or2(GtkWidget *w _U_, gpointer data)
455 match_selected_cb_do(data,
456 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
457 get_text_from_packet_list(data));
461 match_selected_cb_not2(GtkWidget *w _U_, gpointer data)
463 match_selected_cb_do(data,
464 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
465 get_text_from_packet_list(data));
469 match_selected_cb_and_not2(GtkWidget *w _U_, gpointer data)
471 match_selected_cb_do(data,
472 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
473 get_text_from_packet_list(data));
477 match_selected_cb_or_not2(GtkWidget *w _U_, gpointer data)
479 match_selected_cb_do(data,
480 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
481 get_text_from_packet_list(data));
485 prepare_selected_cb_replace2(GtkWidget *w _U_, gpointer data)
487 match_selected_cb_do(data,
488 MATCH_SELECTED_REPLACE,
489 get_text_from_packet_list(data));
493 prepare_selected_cb_and2(GtkWidget *w _U_, gpointer data)
495 match_selected_cb_do(data,
497 get_text_from_packet_list(data));
501 prepare_selected_cb_or2(GtkWidget *w _U_, gpointer data)
503 match_selected_cb_do(data,
505 get_text_from_packet_list(data));
509 prepare_selected_cb_not2(GtkWidget *w _U_, gpointer data)
511 match_selected_cb_do(data,
513 get_text_from_packet_list(data));
517 prepare_selected_cb_and_not2(GtkWidget *w _U_, gpointer data)
519 match_selected_cb_do(data,
520 MATCH_SELECTED_AND_NOT,
521 get_text_from_packet_list(data));
525 prepare_selected_cb_or_not2(GtkWidget *w _U_, gpointer data)
527 match_selected_cb_do(data,
528 MATCH_SELECTED_OR_NOT,
529 get_text_from_packet_list(data));
532 /* Run the current display filter on the current packet set, and
535 filter_activate_cb(GtkWidget *w, gpointer data)
537 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
538 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
539 GList *li, *nl = NULL;
540 gboolean add_filter = TRUE;
544 s = gtk_entry_get_text(GTK_ENTRY(data));
546 /* GtkCombos don't let us get at their list contents easily, so we maintain
547 our own filter list, and feed it to gtk_combo_set_popdown_strings when
548 a new filter is added. */
549 if (filter_packets(&cfile, g_strdup(s))) {
550 li = g_list_first(filter_list);
552 if (li->data && strcmp(s, li->data) == 0)
558 filter_list = g_list_append(filter_list, g_strdup(s));
559 li = g_list_first(filter_list);
561 nl = g_list_append(nl, strdup(li->data));
564 gtk_combo_set_popdown_strings(filter_cm, nl);
565 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
570 /* redisplay with no display filter */
572 filter_reset_cb(GtkWidget *w, gpointer data _U_)
574 GtkWidget *filter_te = NULL;
576 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
577 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
579 filter_packets(&cfile, NULL);
582 /* GTKClist compare routine, overrides default to allow numeric comparison */
584 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
586 /* Get row text strings */
587 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
588 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
590 /* Attempt to convert to numbers */
591 double num1 = atof(text1);
592 double num2 = atof(text2);
594 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
596 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
597 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
598 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
599 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
600 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
601 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
602 (col_fmt == COL_PACKET_LENGTH)) {
604 /* Compare numeric column */
608 else if (num1 > num2)
616 /* Compare text column */
618 return (text1 != NULL);
623 return strcmp(text1, text2);
627 /* What to do when a column is clicked */
629 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
631 column_arrows *col_arrows = (column_arrows *) data;
634 gtk_clist_freeze(clist);
636 for (i = 0; i < cfile.cinfo.num_cols; i++) {
637 gtk_widget_hide(col_arrows[i].ascend_pm);
638 gtk_widget_hide(col_arrows[i].descend_pm);
641 if (column == clist->sort_column) {
642 if (clist->sort_type == GTK_SORT_ASCENDING) {
643 clist->sort_type = GTK_SORT_DESCENDING;
644 gtk_widget_show(col_arrows[column].descend_pm);
646 clist->sort_type = GTK_SORT_ASCENDING;
647 gtk_widget_show(col_arrows[column].ascend_pm);
651 clist->sort_type = GTK_SORT_ASCENDING;
652 gtk_widget_show(col_arrows[column].ascend_pm);
653 gtk_clist_set_sort_column(clist, column);
655 gtk_clist_thaw(clist);
657 gtk_clist_sort(clist);
662 set_frame_mark(gboolean set, frame_data *frame, gint row) {
668 mark_frame(&cfile, frame);
669 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
670 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
672 unmark_frame(&cfile, frame);
676 file_set_save_marked_sensitive();
677 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
678 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
682 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_) {
684 GdkEventButton *event_button = (GdkEventButton *)event;
687 if (w == NULL || event == NULL)
690 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
691 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
693 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
694 set_frame_mark(!fdata->flags.marked, fdata, row);
698 void mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
699 if (cfile.current_frame) {
700 /* XXX hum, should better have a "cfile->current_row" here ... */
701 set_frame_mark(!cfile.current_frame->flags.marked,
703 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
704 cfile.current_frame));
708 static void mark_all_frames(gboolean set) {
710 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
713 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
717 void update_marked_frames(void) {
719 if (cfile.plist == NULL) return;
720 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
721 if (fdata->flags.marked)
724 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
729 void mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
730 mark_all_frames(TRUE);
733 void unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
734 mark_all_frames(FALSE);
737 /* What to do when a list item is selected/unselected */
739 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
741 /* Remove the hex display tabbed pages */
742 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
743 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
745 select_packet(&cfile, row);
750 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
752 unselect_packet(&cfile);
757 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_, gpointer user_data _U_)
760 gchar *help_str = NULL;
761 gboolean has_blurb = FALSE;
762 guint length = 0, byte_len;
763 GtkWidget *byte_view;
764 const guint8 *byte_data;
767 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
770 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
772 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
773 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
774 g_assert(byte_data != NULL);
776 finfo_selected = finfo;
777 set_menus_for_selected_tree_row(TRUE);
780 if (finfo->hfinfo->blurb != NULL &&
781 finfo->hfinfo->blurb[0] != '\0') {
783 length = strlen(finfo->hfinfo->blurb);
785 length = strlen(finfo->hfinfo->name);
787 statusbar_pop_field_msg(); /* get rid of current help msg */
789 length += strlen(finfo->hfinfo->abbrev) + 10;
790 help_str = g_malloc(sizeof(gchar) * length);
791 sprintf(help_str, "%s (%s)",
792 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
793 finfo->hfinfo->abbrev);
794 statusbar_push_field_msg(help_str);
798 * Don't show anything if the field name is zero-length;
799 * the pseudo-field for "proto_tree_add_text()" is such
800 * a field, and we don't want "Text (text)" showing up
801 * on the status line if you've selected such a field.
803 * XXX - there are zero-length fields for which we *do*
804 * want to show the field name.
806 * XXX - perhaps the name and abbrev field should be null
807 * pointers rather than null strings for that pseudo-field,
808 * but we'd have to add checks for null pointers in some
809 * places if we did that.
811 * Or perhaps protocol tree items added with
812 * "proto_tree_add_text()" should have -1 as the field index,
813 * with no pseudo-field being used, but that might also
814 * require special checks for -1 to be added.
816 statusbar_push_field_msg("");
820 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
825 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_, gpointer user_data _U_)
827 GtkWidget *byte_view;
832 * Which byte view is displaying the current protocol tree
835 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
836 if (byte_view == NULL)
839 data = get_byte_view_data_and_length(byte_view, &len);
844 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
848 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
850 collapse_all_tree(cfile.edt->tree, tree_view);
853 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
855 expand_all_tree(cfile.edt->tree, tree_view);
858 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
859 if (cfile.edt->tree) {
860 guint32 tmp = g_resolv_flags;
861 g_resolv_flags = RESOLV_ALL;
862 proto_tree_draw(cfile.edt->tree, tree_view);
863 g_resolv_flags = tmp;
867 /* Set the selection mode of the packet list window. */
869 set_plist_sel_browse(gboolean val)
874 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
876 if (val == old_val) {
878 * The mode isn't changing, so don't do anything.
879 * In particular, don't gratuitiously unselect the
882 * XXX - why do we have to unselect the current packet
883 * ourselves? The documentation for the GtkCList at
885 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
887 * says "Note that setting the widget's selection mode to
888 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
889 * cause all the items in the GtkCList to become deselected."
895 unselect_packet(&cfile);
897 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
898 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
900 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
903 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
907 /* Set the font of the packet list window. */
909 set_plist_font(GdkFont *font)
914 style = gtk_style_new();
915 gdk_font_unref(style->font);
919 gtk_widget_set_style(packet_list, style);
921 /* Compute static column sizes to use during a "-S" capture, so that
922 the columns don't resize during a live capture. */
923 for (i = 0; i < cfile.cinfo.num_cols; i++) {
924 cfile.cinfo.col_width[i] = gdk_string_width(font,
925 get_column_longest_string(get_column_format(i)));
930 * Push a message referring to file access onto the statusbar.
933 statusbar_push_file_msg(gchar *msg)
935 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
939 * Pop a message referring to file access off the statusbar.
942 statusbar_pop_file_msg(void)
944 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
948 * XXX - do we need multiple statusbar contexts?
952 * Push a message referring to the currently-selected field onto the statusbar.
955 statusbar_push_field_msg(gchar *msg)
957 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
961 * Pop a message referring to the currently-selected field off the statusbar.
964 statusbar_pop_field_msg(void)
966 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
972 /* XXX - should we check whether the capture file is an
973 unsaved temporary file for a live capture and, if so,
974 pop up a "do you want to exit without saving the capture
975 file?" dialog, and then just return, leaving said dialog
976 box to forcibly quit if the user clicks "OK"?
978 If so, note that this should be done in a subroutine that
979 returns TRUE if we do so, and FALSE otherwise, and if it
980 returns TRUE we should return TRUE without nuking anything.
982 Note that, if we do that, we might also want to check if
983 an "Update list of packets in real time" capture is in
984 progress and, if so, ask whether they want to terminate
985 the capture and discard it, and return TRUE, before nuking
986 any child capture, if they say they don't want to do so. */
989 /* Nuke any child capture in progress. */
990 kill_capture_child();
993 /* Are we in the middle of reading a capture? */
994 if (cfile.state == FILE_READ_IN_PROGRESS) {
995 /* Yes, so we can't just close the file and quit, as
996 that may yank the rug out from under the read in
997 progress; instead, just set the state to
998 "FILE_READ_ABORTED" and return - the code doing the read
999 will check for that and, if it sees that, will clean
1001 cfile.state = FILE_READ_ABORTED;
1003 /* Say that the window should *not* be deleted;
1004 that'll be done by the code that cleans up. */
1007 /* Close any capture file we have open; on some OSes, you
1008 can't unlink a temporary capture file if you have it
1010 "close_cap_file()" will unlink it after closing it if
1011 it's a temporary file.
1013 We do this here, rather than after the main loop returns,
1014 as, after the main loop returns, the main window may have
1015 been destroyed (if this is called due to a "destroy"
1016 even on the main window rather than due to the user
1017 selecting a menu item), and there may be a crash
1018 or other problem when "close_cap_file()" tries to
1019 clean up stuff in the main window.
1021 XXX - is there a better place to put this?
1022 Or should we have a routine that *just* closes the
1023 capture file, and doesn't do anything with the UI,
1024 which we'd call here, and another routine that
1025 calls that routine and also cleans up the UI, which
1026 we'd call elsewhere? */
1027 close_cap_file(&cfile);
1029 /* Exit by leaving the main loop, so that any quit functions
1030 we registered get called. */
1033 /* Say that the window should be deleted. */
1039 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1041 gint desk_x, desk_y;
1043 /* Try to grab our geometry */
1044 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1045 if (gdk_window_get_deskrelative_origin(top_level->window,
1046 &desk_x, &desk_y)) {
1047 if (desk_x <= root_x && desk_y <= root_y) {
1053 /* XXX - Is this the "approved" method? */
1054 gdk_window_get_size(top_level->window, &top_width, &top_height);
1056 /* "do_quit()" indicates whether the main window should be deleted. */
1061 file_quit_cmd_cb (GtkWidget *widget _U_, gpointer data _U_)
1069 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
1070 comp_info_str->str);
1072 fprintf(stderr, "%s [ -vh ] [ -klpQS ] [ -a <capture autostop condition> ] ...\n",
1074 fprintf(stderr, "\t[ -b <number of ringbuffer files> ] [ -B <byte view height> ]\n");
1075 fprintf(stderr, "\t[ -c <count> ] [ -f <capture filter> ] [ -i <interface> ]\n");
1076 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -N <resolving> ]\n");
1077 fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1078 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1079 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1080 fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n");
1082 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1084 fprintf(stderr, "\t[ -n ] [ -N <resolving> ]\n");
1085 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
1086 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
1087 fprintf(stderr, "\t[ -T <tree view height> ] [ <infile> ]\n");
1098 printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
1102 get_positive_int(const char *string, const char *name)
1107 number = strtol(string, &p, 10);
1108 if (p == string || *p != '\0') {
1109 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1114 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1119 fprintf(stderr, "ethereal: The specified %s \"%s\" is zero\n",
1123 if (number > INT_MAX) {
1124 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1125 name, string, INT_MAX);
1133 * Given a string of the form "<autostop criterion>:<value>", as might appear
1134 * as an argument to a "-a" option, parse it and set the criterion in
1135 * question. Return an indication of whether it succeeded or failed
1139 set_autostop_criterion(const char *autostoparg)
1143 colonp = strchr(autostoparg, ':');
1151 * Skip over any white space (there probably won't be any, but
1152 * as we allow it in the preferences file, we might as well
1159 * Put the colon back, so if our caller uses, in an
1160 * error message, the string they passed us, the message
1166 if (strcmp(autostoparg,"duration") == 0) {
1167 capture_opts.has_autostop_duration = TRUE;
1168 capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1169 } else if (strcmp(autostoparg,"filesize") == 0) {
1170 capture_opts.has_autostop_filesize = TRUE;
1171 capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1175 *colonp = ':'; /* put the colon back */
1180 /* And now our feature presentation... [ fade to music ] */
1182 main(int argc, char *argv[])
1190 extern char *optarg;
1191 gboolean arg_error = FALSE;
1193 #ifdef HAVE_PCAP_VERSION
1194 extern char pcap_version[];
1195 #endif /* HAVE_PCAP_VERSION */
1196 #endif /* HAVE_LIBPCAP */
1202 char *gpf_path, *cf_path, *df_path;
1203 const char *pf_path;
1204 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
1207 gboolean start_capture = FALSE;
1208 gchar *save_file = NULL;
1210 gchar err_str[PCAP_ERRBUF_SIZE];
1211 gboolean stats_known;
1212 struct pcap_stat stats;
1214 gboolean capture_option_specified = FALSE;
1216 gint pl_size = 280, tv_size = 95, bv_size = 75;
1217 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1218 dfilter_t *rfcode = NULL;
1219 gboolean rfilter_parse_failed = FALSE;
1222 char *bold_font_name;
1223 gint desk_x, desk_y;
1224 gboolean prefs_write_needed = FALSE;
1227 ethereal_path = argv[0];
1230 /* Arrange that if we have no console window, and a GLib message logging
1231 routine is called to log a message, we pop up a console window.
1233 We do that by inserting our own handler for all messages logged
1234 to the default domain; that handler pops up a console if necessary,
1235 and then calls the default handler. */
1236 g_log_set_handler(NULL,
1238 G_LOG_LEVEL_CRITICAL|
1239 G_LOG_LEVEL_WARNING|
1240 G_LOG_LEVEL_MESSAGE|
1243 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1244 console_log_handler, NULL);
1248 command_name = get_basename(ethereal_path);
1249 /* Set "capture_child" to indicate whether this is going to be a child
1250 process for a "-S" capture. */
1251 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1254 /* Register all dissectors; we must do this before checking for the
1255 "-G" flag, as the "-G" flag dumps a list of fields registered
1256 by the dissectors, and we must do it before we read the preferences,
1257 in case any dissectors register preferences. */
1258 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
1260 /* Now register the preferences for any non-dissector modules.
1261 We must do that before we read the preferences as well. */
1262 prefs_register_modules();
1264 /* If invoked with the "-G" flag, we dump out a glossary of
1265 display filter symbols.
1267 We must do this before calling "gtk_init()", because "gtk_init()"
1268 tries to open an X display, and we don't want to have to do any X
1269 stuff just to do a build.
1271 Given that we call "gtk_init()" before doing the regular argument
1272 list processing, so that it can handle X and GTK+ arguments and
1273 remove them from the list at which we look, this means we must do
1274 this before doing the regular argument list processing, as well.
1278 you must give the "-G" flag as the first flag on the command line;
1280 you must give it as "-G", nothing more, nothing less;
1282 any arguments after the "-G" flag will not be used. */
1283 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1284 proto_registrar_dump();
1288 /* Set the current locale according to the program environment.
1289 * We haven't localized anything, but some GTK widgets are localized
1290 * (the file selection dialogue, for example).
1291 * This also sets the C-language locale to the native environment. */
1294 /* Let GTK get its args */
1295 gtk_init (&argc, &argv);
1297 /* Read the preference files. */
1298 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1301 capture_opts.has_snaplen = FALSE;
1302 capture_opts.snaplen = MIN_PACKET_SIZE;
1303 capture_opts.has_autostop_count = FALSE;
1304 capture_opts.autostop_count = 1;
1305 capture_opts.has_autostop_duration = FALSE;
1306 capture_opts.autostop_duration = 1;
1307 capture_opts.has_autostop_filesize = FALSE;
1308 capture_opts.autostop_filesize = 1;
1309 capture_opts.ringbuffer_on = FALSE;
1310 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1312 /* If this is a capture child process, it should pay no attention
1313 to the "prefs.capture_prom_mode" setting in the preferences file;
1314 it should do what the parent process tells it to do, and if
1315 the parent process wants it not to run in promiscuous mode, it'll
1316 tell it so with a "-p" flag.
1318 Otherwise, set promiscuous mode from the preferences setting. */
1320 capture_opts.promisc_mode = TRUE;
1322 capture_opts.promisc_mode = prefs->capture_prom_mode;
1324 /* Set "Update list of packets in real time" mode from the preferences
1326 capture_opts.sync_mode = prefs->capture_real_time;
1328 /* And do the same for "Automatic scrolling in live capture" mode. */
1329 auto_scroll_live = prefs->capture_auto_scroll;
1332 /* Set the name resolution code's flags from the preferences. */
1333 g_resolv_flags = prefs->name_resolve;
1335 /* Read the capture filter file. */
1336 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1338 /* Read the display filter file. */
1339 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1341 /* Initialize the capture file struct */
1343 cfile.plist_end = NULL;
1345 cfile.filename = NULL;
1346 cfile.user_saved = FALSE;
1347 cfile.is_tempfile = FALSE;
1348 cfile.rfcode = NULL;
1349 cfile.dfilter = NULL;
1350 cfile.dfcode = NULL;
1352 cfile.cfilter = g_strdup(EMPTY_FILTER);
1355 cfile.save_file = NULL;
1356 cfile.save_file_fd = -1;
1357 cfile.has_snap = FALSE;
1358 cfile.snap = WTAP_MAX_PACKET_SIZE;
1360 col_init(&cfile.cinfo, prefs->num_cols);
1362 /* Assemble the compile-time options */
1363 comp_info_str = g_string_new("");
1365 g_string_append(comp_info_str, "with ");
1366 g_string_sprintfa(comp_info_str,
1367 #ifdef GTK_MAJOR_VERSION
1368 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1371 "GTK+ (version unknown)");
1374 g_string_append(comp_info_str, ", with ");
1375 g_string_sprintfa(comp_info_str,
1376 #ifdef GLIB_MAJOR_VERSION
1377 "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
1378 GLIB_MICRO_VERSION);
1380 "GLib (version unknown)");
1384 g_string_append(comp_info_str, ", with libpcap ");
1385 #ifdef HAVE_PCAP_VERSION
1386 g_string_append(comp_info_str, pcap_version);
1387 #else /* HAVE_PCAP_VERSION */
1388 g_string_append(comp_info_str, "(version unknown)");
1389 #endif /* HAVE_PCAP_VERSION */
1390 #else /* HAVE_LIBPCAP */
1391 g_string_append(comp_info_str, ", without libpcap");
1392 #endif /* HAVE_LIBPCAP */
1395 g_string_append(comp_info_str, ", with libz ");
1397 g_string_append(comp_info_str, ZLIB_VERSION);
1398 #else /* ZLIB_VERSION */
1399 g_string_append(comp_info_str, "(version unknown)");
1400 #endif /* ZLIB_VERSION */
1401 #else /* HAVE_LIBZ */
1402 g_string_append(comp_info_str, ", without libz");
1403 #endif /* HAVE_LIBZ */
1405 /* Oh, this is pretty */
1406 #if defined(HAVE_UCD_SNMP_SNMP_H)
1407 g_string_append(comp_info_str, ", with UCD SNMP ");
1408 #ifdef HAVE_UCD_SNMP_VERSION_H
1409 g_string_append(comp_info_str, VersionInfo);
1410 #else /* HAVE_UCD_SNMP_VERSION_H */
1411 g_string_append(comp_info_str, "(version unknown)");
1412 #endif /* HAVE_UCD_SNMP_VERSION_H */
1413 #elif defined(HAVE_SNMP_SNMP_H)
1414 g_string_append(comp_info_str, ", with CMU SNMP ");
1415 #ifdef HAVE_SNMP_VERSION_H
1416 g_string_append(comp_info_str, snmp_Version());
1417 #else /* HAVE_SNMP_VERSION_H */
1418 g_string_append(comp_info_str, "(version unknown)");
1419 #endif /* HAVE_SNMP_VERSION_H */
1421 g_string_append(comp_info_str, ", without SNMP");
1424 /* Now get our args */
1425 while ((opt = getopt(argc, argv, "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:W:vZ:")) != -1) {
1427 case 'a': /* autostop criteria */
1429 if (set_autostop_criterion(optarg) == FALSE) {
1430 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1434 capture_option_specified = TRUE;
1438 case 'b': /* Ringbuffer option */
1440 capture_opts.ringbuffer_on = TRUE;
1441 capture_opts.ringbuffer_num_files =
1442 get_positive_int(optarg, "number of ring buffer files");
1444 capture_option_specified = TRUE;
1448 case 'B': /* Byte view pane height */
1449 bv_size = get_positive_int(optarg, "byte view pane height");
1451 case 'c': /* Capture xxx packets */
1453 capture_opts.has_autostop_count = TRUE;
1454 capture_opts.autostop_count = get_positive_int(optarg, "packet count");
1456 capture_option_specified = TRUE;
1463 g_free(cfile.cfilter);
1464 cfile.cfilter = g_strdup(optarg);
1466 capture_option_specified = TRUE;
1470 case 'h': /* Print help and exit */
1474 case 'i': /* Use interface xxx */
1476 cfile.iface = g_strdup(optarg);
1478 capture_option_specified = TRUE;
1482 case 'k': /* Start capture immediately */
1484 start_capture = TRUE;
1486 capture_option_specified = TRUE;
1490 case 'l': /* Automatic scrolling in live capture mode */
1492 auto_scroll_live = TRUE;
1494 capture_option_specified = TRUE;
1498 case 'm': /* Fixed-width font for the display */
1499 if (prefs->gui_font_name != NULL)
1500 g_free(prefs->gui_font_name);
1501 prefs->gui_font_name = g_strdup(optarg);
1503 case 'n': /* No name resolution */
1504 g_resolv_flags = RESOLV_NONE;
1506 case 'N': /* Select what types of addresses/port #s to resolve */
1507 if (g_resolv_flags == RESOLV_ALL)
1508 g_resolv_flags = RESOLV_NONE;
1509 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1510 if (badopt != '\0') {
1511 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1516 case 'o': /* Override preference from command line */
1517 switch (prefs_set_pref(optarg)) {
1519 case PREFS_SET_SYNTAX_ERR:
1520 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1524 case PREFS_SET_NO_SUCH_PREF:
1525 case PREFS_SET_OBSOLETE:
1526 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1532 case 'p': /* Don't capture in promiscuous mode */
1534 capture_opts.promisc_mode = FALSE;
1536 capture_option_specified = TRUE;
1540 case 'P': /* Packet list pane height */
1541 pl_size = get_positive_int(optarg, "packet list pane height");
1543 case 'Q': /* Quit after capture (just capture to file) */
1546 start_capture = TRUE; /*** -Q implies -k !! ***/
1548 capture_option_specified = TRUE;
1552 case 'r': /* Read capture file xxx */
1553 /* We may set "last_open_dir" to "cf_name", and if we change
1554 "last_open_dir" later, we free the old value, so we have to
1555 set "cf_name" to something that's been allocated. */
1556 cf_name = g_strdup(optarg);
1558 case 'R': /* Read file filter */
1561 case 's': /* Set the snapshot (capture) length */
1563 capture_opts.has_snaplen = TRUE;
1564 capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
1566 capture_option_specified = TRUE;
1570 case 'S': /* "Sync" mode: used for following file ala tail -f */
1572 capture_opts.sync_mode = TRUE;
1574 capture_option_specified = TRUE;
1578 case 't': /* Time stamp type */
1579 if (strcmp(optarg, "r") == 0)
1580 timestamp_type = RELATIVE;
1581 else if (strcmp(optarg, "a") == 0)
1582 timestamp_type = ABSOLUTE;
1583 else if (strcmp(optarg, "ad") == 0)
1584 timestamp_type = ABSOLUTE_WITH_DATE;
1585 else if (strcmp(optarg, "d") == 0)
1586 timestamp_type = DELTA;
1588 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1590 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1591 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1595 case 'T': /* Tree view pane height */
1596 tv_size = get_positive_int(optarg, "tree view pane height");
1598 case 'v': /* Show version and exit */
1601 if (console_was_created)
1606 case 'w': /* Write to capture file xxx */
1608 save_file = g_strdup(optarg);
1610 capture_option_specified = TRUE;
1614 case 'W': /* Write to capture file FD xxx */
1616 cfile.save_file_fd = atoi(optarg);
1618 capture_option_specified = TRUE;
1624 case 'Z': /* Write to pipe FD XXX */
1626 /* associate stdout with pipe */
1628 if (dup2(i, 1) < 0) {
1629 fprintf(stderr, "Unable to dup pipe handle\n");
1633 capture_option_specified = TRUE;
1635 #endif /* HAVE_LIBPCAP */
1640 case '?': /* Bad flag - print usage message */
1648 if (cf_name != NULL) {
1650 * Input file name specified with "-r" *and* specified as a regular
1651 * command-line argument.
1656 * Input file name not specified with "-r", and a command-line argument
1657 * was specified; treat it as the input file name.
1659 * Yes, this is different from tethereal, where non-flag command-line
1660 * arguments are a filter, but this works better on GUI desktops
1661 * where a command can be specified to be run to open a particular
1662 * file - yes, you could have "-r" as the last part of the command,
1663 * but that's a bit ugly.
1665 cf_name = g_strdup(argv[0]);
1673 * Extra command line arguments were specified; complain.
1679 if (capture_opts.ringbuffer_on) {
1680 /* Ring buffer works only under certain conditions:
1681 a) ring buffer does not work with temporary files;
1682 b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
1683 sync_mode takes precedence;
1684 c) it makes no sense to enable the ring buffer if the maximum
1685 file size is set to "infinite". */
1686 if (cfile.save_file == NULL) {
1687 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
1688 capture_opts.ringbuffer_on = FALSE;
1690 if (capture_opts.sync_mode) {
1691 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
1692 capture_opts.ringbuffer_on = FALSE;
1694 if (!capture_opts.has_autostop_filesize) {
1695 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
1696 capture_opts.ringbuffer_on = FALSE;
1702 /* Load wpcap if possible */
1705 /* Start windows sockets */
1706 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1709 /* Notify all registered modules that have had any of their preferences
1710 changed either from one of the preferences file or from the command
1711 line that its preferences have changed. */
1714 #ifndef HAVE_LIBPCAP
1715 if (capture_option_specified)
1716 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1721 if (start_capture) {
1722 /* We're supposed to do a live capture; did the user specify an interface
1724 if (cfile.iface == NULL) {
1725 /* No - pick the first one from the list of interfaces. */
1726 if_list = get_interface_list(&err, err_str);
1727 if (if_list == NULL) {
1730 case CANT_GET_INTERFACE_LIST:
1731 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1735 case NO_INTERFACES_FOUND:
1736 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1741 cfile.iface = g_strdup(if_list->data); /* first interface */
1742 free_interface_list(if_list);
1745 if (capture_child) {
1746 if (cfile.save_file_fd == -1) {
1747 /* XXX - send this to the standard output as something our parent
1748 should put in an error message box? */
1749 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1755 /* Build the column format array */
1756 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1757 cfile.cinfo.col_fmt[i] = get_column_format(i);
1758 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1759 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1761 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1762 cfile.cinfo.col_data[i] = NULL;
1763 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1764 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1766 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1767 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1768 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1772 if (capture_opts.has_snaplen) {
1773 if (capture_opts.snaplen < 1)
1774 capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
1775 else if (capture_opts.snaplen < MIN_PACKET_SIZE)
1776 capture_opts.snaplen = MIN_PACKET_SIZE;
1779 /* Check the value range of the ringbuffer_num_files parameter */
1780 if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
1781 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1782 else if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
1783 capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
1786 rc_file = get_persconffile_path(RC_FILE, FALSE);
1787 gtk_rc_parse(rc_file);
1789 /* Try to load the regular and boldface fixed-width fonts */
1790 bold_font_name = boldify(prefs->gui_font_name);
1791 m_r_font = gdk_font_load(prefs->gui_font_name);
1792 m_b_font = gdk_font_load(bold_font_name);
1793 if (m_r_font == NULL || m_b_font == NULL) {
1794 /* XXX - pop this up as a dialog box? no */
1795 if (m_r_font == NULL) {
1799 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1800 prefs->gui_font_name);
1802 gdk_font_unref(m_r_font);
1804 if (m_b_font == NULL) {
1808 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1811 gdk_font_unref(m_b_font);
1813 g_free(bold_font_name);
1814 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1815 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1818 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1819 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1822 g_free(prefs->gui_font_name);
1823 prefs->gui_font_name = g_strdup("6x13");
1826 /* Call this for the side-effects that set_fonts() produces */
1827 set_fonts(m_r_font, m_b_font);
1831 /* Is this a "child" ethereal, which is only supposed to pop up a
1832 capture box to let us stop the capture, and run a capture
1833 to a file that our parent will read? */
1834 if (!capture_child) {
1836 /* No. Pop up the main window, and read in a capture file if
1839 create_main_window(pl_size, tv_size, bv_size, prefs);
1840 set_menus_for_capture_file(FALSE);
1842 cfile.colors = colfilter_new();
1844 /* If we were given the name of a capture file, read it in now;
1845 we defer it until now, so that, if we can't open it, and pop
1846 up an alert box, the alert box is more likely to come up on
1847 top of the main window - but before the preference-file-error
1848 alert box, so, if we get one of those, it's more likely to come
1851 if (rfilter != NULL) {
1852 if (!dfilter_compile(rfilter, &rfcode)) {
1853 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1854 rfilter_parse_failed = TRUE;
1857 if (!rfilter_parse_failed) {
1858 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1859 /* "open_cap_file()" succeeded, so it closed the previous
1860 capture file, and thus destroyed any previous read filter
1861 attached to "cf". */
1862 cfile.rfcode = rfcode;
1863 switch (read_cap_file(&cfile, &err)) {
1867 /* Just because we got an error, that doesn't mean we were unable
1868 to read any of the file; we handle what we could get from the
1877 /* Save the name of the containing directory specified in the
1878 path name, if any; we can write over cf_name, which is a
1879 good thing, given that "get_dirname()" does write over its
1881 s = get_dirname(cf_name);
1882 set_last_open_dir(s);
1885 dfilter_free(rfcode);
1886 cfile.rfcode = NULL;
1894 /* If the global preferences file exists but we failed to open it,
1895 pop up an alert box; we defer that until now, so that the alert
1896 box is more likely to come up on top of the main window. */
1897 if (gpf_path != NULL) {
1898 simple_dialog(ESD_TYPE_WARN, NULL,
1899 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1900 strerror(gpf_open_errno));
1903 /* If the user's preferences file exists but we failed to open it,
1904 pop up an alert box; we defer that until now, so that the alert
1905 box is more likely to come up on top of the main window. */
1906 if (pf_path != NULL) {
1907 simple_dialog(ESD_TYPE_WARN, NULL,
1908 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1909 strerror(pf_open_errno));
1912 /* If the user's capture filter file exists but we failed to open it,
1913 pop up an alert box; we defer that until now, so that the alert
1914 box is more likely to come up on top of the main window. */
1915 if (cf_path != NULL) {
1916 simple_dialog(ESD_TYPE_WARN, NULL,
1917 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1918 strerror(cf_open_errno));
1922 /* If the user's display filter file exists but we failed to open it,
1923 pop up an alert box; we defer that until now, so that the alert
1924 box is more likely to come up on top of the main window. */
1925 if (df_path != NULL) {
1926 simple_dialog(ESD_TYPE_WARN, NULL,
1927 "Could not open your display filter file\n\"%s\": %s.", df_path,
1928 strerror(df_open_errno));
1933 if (capture_child) {
1934 /* This is the child process for a sync mode or fork mode capture,
1935 so just do the low-level work of a capture - don't create
1936 a temporary file and fork off *another* child process (so don't
1937 call "do_capture()"). */
1939 /* XXX - hand these stats to the parent process */
1940 capture(&stats_known, &stats);
1942 /* The capture is done; there's nothing more for us to do. */
1945 if (start_capture) {
1946 /* "-k" was specified; start a capture. */
1947 do_capture(save_file);
1950 set_menus_for_capture_in_progress(FALSE);
1954 set_menus_for_capture_in_progress(FALSE);
1959 /* Try to save our geometry. GTK+ provides two routines to get a
1960 window's position relative to the X root window. If I understand the
1961 documentation correctly, gdk_window_get_deskrelative_origin applies
1962 mainly to Enlightenment and gdk_window_get_root_origin applies for
1965 The code below tries both routines, and picks the one that returns
1966 the upper-left-most coordinates.
1970 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
1971 http://www.gtk.org/faq/#AEN600 */
1973 /* Re-read our saved preferences. */
1974 /* XXX - Move all of this into a separate function? */
1975 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1977 if (pf_path == NULL) {
1978 if (prefs->gui_geometry_save_position) {
1979 if (top_level->window != NULL) {
1980 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1981 if (gdk_window_get_deskrelative_origin(top_level->window,
1982 &desk_x, &desk_y)) {
1983 if (desk_x <= root_x && desk_y <= root_y) {
1989 if (prefs->gui_geometry_main_x != root_x) {
1990 prefs->gui_geometry_main_x = root_x;
1991 prefs_write_needed = TRUE;
1993 if (prefs->gui_geometry_main_y != root_y) {
1994 prefs->gui_geometry_main_y = root_y;
1995 prefs_write_needed = TRUE;
1999 if (prefs->gui_geometry_save_size) {
2000 if (top_level->window != NULL) {
2001 /* XXX - Is this the "approved" method? */
2002 gdk_window_get_size(top_level->window, &top_width, &top_height);
2004 if (prefs->gui_geometry_main_width != top_width) {
2005 prefs->gui_geometry_main_width = top_width;
2006 prefs_write_needed = TRUE;
2008 if (prefs->gui_geometry_main_height != top_height) {
2009 prefs->gui_geometry_main_height = top_height;
2010 prefs_write_needed = TRUE;
2014 if (prefs_write_needed) {
2015 write_prefs(&pf_path);
2023 /* Shutdown windows sockets */
2026 /* For some unknown reason, the "atexit()" call in "create_console()"
2027 doesn't arrange that "destroy_console()" be called when we exit,
2028 so we call it here if a console was created. */
2029 if (console_was_created)
2035 /* This isn't reached, but we need it to keep GCC from complaining
2036 that "main()" returns without returning a value - it knows that
2037 "exit()" never returns, but it doesn't know that "gtk_exit()"
2038 doesn't, as GTK+ doesn't declare it with the attribute
2040 return 0; /* not reached */
2045 /* We build this as a GUI subsystem application on Win32, so
2046 "WinMain()", not "main()", gets called.
2048 Hack shamelessly stolen from the Win32 port of the GIMP. */
2050 #define _stdcall __attribute__((stdcall))
2054 WinMain (struct HINSTANCE__ *hInstance,
2055 struct HINSTANCE__ *hPrevInstance,
2059 has_no_console = TRUE;
2060 return main (__argc, __argv);
2064 * If this application has no console window to which its standard output
2065 * would go, create one.
2068 create_console(void)
2070 if (has_no_console) {
2071 /* We have no console to which to print the version string, so
2072 create one and make it the standard input, output, and error. */
2073 if (!AllocConsole())
2074 return; /* couldn't create console */
2075 freopen("CONIN$", "r", stdin);
2076 freopen("CONOUT$", "w", stdout);
2077 freopen("CONOUT$", "w", stderr);
2079 /* Well, we have a console now. */
2080 has_no_console = FALSE;
2081 console_was_created = TRUE;
2083 /* Now register "destroy_console()" as a routine to be called just
2084 before the application exits, so that we can destroy the console
2085 after the user has typed a key (so that the console doesn't just
2086 disappear out from under them, giving the user no chance to see
2087 the message(s) we put in there). */
2088 atexit(destroy_console);
2093 destroy_console(void)
2095 printf("\n\nPress any key to exit\n");
2100 /* This routine should not be necessary, at least as I read the GLib
2101 source code, as it looks as if GLib is, on Win32, *supposed* to
2102 create a console window into which to display its output.
2104 That doesn't happen, however. I suspect there's something completely
2105 broken about that code in GLib-for-Win32, and that it may be related
2106 to the breakage that forces us to just call "printf()" on the message
2107 rather than passing the message on to "g_log_default_handler()"
2108 (which is the routine that does the aforementioned non-functional
2109 console window creation). */
2111 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2112 const char *message, gpointer user_data)
2115 if (console_was_created) {
2116 /* For some unknown reason, the above doesn't appear to actually cause
2117 anything to be sent to the standard output, so we'll just splat the
2118 message out directly, just to make sure it gets out. */
2119 printf("%s\n", message);
2121 g_log_default_handler(log_domain, log_level, message, user_data);
2125 /* Given a font name, construct the name of the next heavier version of
2128 #define XLFD_WEIGHT 3 /* index of the "weight" field */
2130 /* Map from a given weight to the appropriate weight for the "bold"
2132 XXX - the XLFD says these strings shouldn't be used for font matching;
2133 can we get the weight, as a number, from GDK, and ask GDK to find us
2134 a font just like the given font, but with the appropriate higher
2136 static const struct {
2140 { "ultralight", "light" },
2141 { "extralight", "semilight" },
2142 { "light", "medium" },
2143 { "semilight", "semibold" },
2144 { "medium", "bold" },
2145 { "normal", "bold" },
2146 { "semibold", "extrabold" },
2147 { "bold", "ultrabold" }
2149 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
2152 boldify(const char *font_name)
2154 char *bold_font_name;
2155 gchar **xlfd_tokens;
2158 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
2159 if (font_name[0] == '-') {
2160 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
2161 for (i = 0; i < N_WEIGHTS; i++) {
2162 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
2163 weight_map[i].light) == 0) {
2164 g_free(xlfd_tokens[XLFD_WEIGHT]);
2165 xlfd_tokens[XLFD_WEIGHT] =
2166 g_strdup(weight_map[i].heavier);
2170 bold_font_name = g_strjoinv("-", xlfd_tokens);
2171 g_strfreev(xlfd_tokens);
2173 /* Append "bold" to the name of the font. */
2174 bold_font_name = g_strconcat(font_name, "bold", NULL);
2176 return bold_font_name;
2181 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2183 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
2184 *stat_hbox, *column_lb,
2185 *filter_bt, *filter_cm, *filter_te,
2188 GList *filter_list = NULL;
2189 GtkAccelGroup *accel;
2190 GtkStyle *win_style;
2191 GdkBitmap *ascend_bm, *descend_bm;
2192 GdkPixmap *ascend_pm, *descend_pm;
2193 column_arrows *col_arrows;
2195 /* Display filter construct dialog has an Apply button, and "OK" not
2196 only sets our text widget, it activates it (i.e., it causes us to
2197 filter the capture). */
2198 static construct_args_t args = {
2199 "Ethereal: Display Filter",
2205 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2206 gtk_widget_set_name(top_level, "main window");
2207 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
2208 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
2209 gtk_signal_connect (GTK_OBJECT (top_level), "realize",
2210 GTK_SIGNAL_FUNC (window_icon_realize_cb), NULL);
2211 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
2212 if (prefs->gui_geometry_save_position) {
2213 gtk_widget_set_uposition(GTK_WIDGET(top_level),
2214 prefs->gui_geometry_main_x, prefs->gui_geometry_main_y);
2216 if (prefs->gui_geometry_save_size) {
2217 gtk_widget_set_usize(GTK_WIDGET(top_level),
2218 prefs->gui_geometry_main_width, prefs->gui_geometry_main_height);
2220 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
2222 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2224 /* Container for menu bar, paned windows and progress/info box */
2225 main_vbox = gtk_vbox_new(FALSE, 1);
2226 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2227 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2228 gtk_widget_show(main_vbox);
2231 get_main_menu(&menubar, &accel);
2232 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2233 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2234 gtk_widget_show(menubar);
2236 /* Panes for the packet list, tree, and byte view */
2237 u_pane = gtk_vpaned_new();
2238 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
2239 l_pane = gtk_vpaned_new();
2240 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
2241 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
2242 gtk_widget_show(l_pane);
2243 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
2244 gtk_widget_show(u_pane);
2247 pkt_scrollw = scrolled_window_new(NULL, NULL);
2248 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
2249 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2250 gtk_widget_show(pkt_scrollw);
2251 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
2253 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
2254 /* Column titles are filled in below */
2255 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
2257 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * cfile.cinfo.num_cols);
2259 set_plist_sel_browse(prefs->gui_plist_sel_browse);
2260 set_plist_font(m_r_font);
2261 gtk_widget_set_name(packet_list, "packet list");
2262 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
2263 GTK_SIGNAL_FUNC(packet_list_click_column_cb), col_arrows);
2264 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
2265 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
2266 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
2267 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
2268 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2269 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
2270 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
2272 /* Right-justify the packet number column. */
2273 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
2274 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
2277 gtk_widget_set_usize(packet_list, -1, pl_size);
2278 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
2279 GTK_SIGNAL_FUNC(popup_menu_handler),
2280 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
2281 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
2282 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
2283 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
2284 gtk_widget_show(packet_list);
2287 item_style = gtk_style_new();
2288 gdk_font_unref(item_style->font);
2289 item_style->font = m_r_font;
2290 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
2291 prefs->gui_scrollbar_on_right);
2292 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
2293 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
2294 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
2295 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
2296 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
2297 GTK_SIGNAL_FUNC(popup_menu_handler),
2298 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
2299 gtk_widget_show(tree_view);
2302 byte_nb_ptr = create_byte_view(bv_size, l_pane, prefs->gui_scrollbar_on_right);
2304 gtk_signal_connect(GTK_OBJECT(byte_nb_ptr), "button_press_event",
2305 GTK_SIGNAL_FUNC(popup_menu_handler),
2306 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
2308 /* Filter/info box */
2309 stat_hbox = gtk_hbox_new(FALSE, 1);
2310 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
2311 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2312 gtk_widget_show(stat_hbox);
2314 filter_bt = gtk_button_new_with_label("Filter:");
2315 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
2316 GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
2317 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
2318 gtk_widget_show(filter_bt);
2320 filter_cm = gtk_combo_new();
2321 filter_list = g_list_append (filter_list, "");
2322 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
2323 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
2324 filter_te = GTK_COMBO(filter_cm)->entry;
2325 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
2326 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
2327 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
2328 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
2329 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
2330 GTK_SIGNAL_FUNC(filter_activate_cb), filter_te);
2331 gtk_widget_show(filter_cm);
2333 filter_reset = gtk_button_new_with_label("Reset");
2334 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
2335 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
2336 GTK_SIGNAL_FUNC(filter_reset_cb), NULL);
2337 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
2338 gtk_widget_show(filter_reset);
2340 filter_apply = gtk_button_new_with_label("Apply");
2341 gtk_object_set_data(GTK_OBJECT(filter_apply), E_DFILTER_CM_KEY, filter_cm);
2342 gtk_object_set_data(GTK_OBJECT(filter_apply), E_DFILTER_FL_KEY, filter_list);
2343 gtk_signal_connect(GTK_OBJECT(filter_apply), "clicked",
2344 GTK_SIGNAL_FUNC(filter_activate_cb), filter_te);
2345 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_apply, FALSE, TRUE, 1);
2346 gtk_widget_show(filter_apply);
2348 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
2349 * of any widget that ends up calling a callback which needs
2350 * that text entry pointer */
2351 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
2352 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
2353 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
2354 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
2355 set_menu_object_data("/Display/Match/Selected", E_DFILTER_TE_KEY, filter_te);
2356 set_menu_object_data("/Display/Match/Not Selected", E_DFILTER_TE_KEY, filter_te);
2357 set_menu_object_data("/Display/Match/And Selected", E_DFILTER_TE_KEY, filter_te);
2358 set_menu_object_data("/Display/Match/Or Selected", E_DFILTER_TE_KEY, filter_te);
2359 set_menu_object_data("/Display/Match/And Not Selected", E_DFILTER_TE_KEY, filter_te);
2360 set_menu_object_data("/Display/Match/Or Not Selected", E_DFILTER_TE_KEY, filter_te);
2361 set_menu_object_data("/Display/Prepare/Selected", E_DFILTER_TE_KEY, filter_te);
2362 set_menu_object_data("/Display/Prepare/Not Selected", E_DFILTER_TE_KEY, filter_te);
2363 set_menu_object_data("/Display/Prepare/And Selected", E_DFILTER_TE_KEY, filter_te);
2364 set_menu_object_data("/Display/Prepare/Or Selected", E_DFILTER_TE_KEY, filter_te);
2365 set_menu_object_data("/Display/Prepare/And Not Selected", E_DFILTER_TE_KEY, filter_te);
2366 set_menu_object_data("/Display/Prepare/Or Not Selected", E_DFILTER_TE_KEY, filter_te);
2367 gtk_object_set_data(GTK_OBJECT(popup_menu_object), E_DFILTER_TE_KEY, filter_te);
2368 gtk_object_set_data(GTK_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, packet_list);
2370 info_bar = gtk_statusbar_new();
2371 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2372 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2373 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2374 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2375 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2376 gtk_widget_show(info_bar);
2378 gtk_widget_show(top_level);
2380 /* Fill in column titles. This must be done after the top level window
2382 win_style = gtk_widget_get_style(top_level);
2383 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
2384 &win_style->bg[GTK_STATE_NORMAL], (gchar **)clist_ascend_xpm);
2385 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
2386 &win_style->bg[GTK_STATE_NORMAL], (gchar **)clist_descend_xpm);
2387 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2388 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
2389 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
2390 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
2391 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
2392 GTK_SHRINK, GTK_SHRINK, 0, 0);
2393 gtk_widget_show(column_lb);
2394 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
2395 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm,
2396 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
2398 gtk_widget_show(col_arrows[i].ascend_pm);
2400 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
2401 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm,
2402 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
2403 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i, col_arrows[i].table);
2404 gtk_widget_show(col_arrows[i].table);
2406 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
2411 set_last_open_dir(char *dirname)
2415 if (last_open_dir) {
2416 g_free(last_open_dir);
2420 len = strlen(dirname);
2421 if (dirname[len-1] != G_DIR_SEPARATOR) {
2422 last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
2427 last_open_dir = NULL;