3 * $Id: main.c,v 1.249 2002/05/14 18:27:28 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?
55 #ifdef HAVE_SYS_TYPES_H
56 #include <sys/types.h>
59 #ifdef HAVE_SYS_STAT_H
64 #include <io.h> /* open/close on win32 */
71 #ifdef HAVE_NETINET_IN_H
72 #include <netinet/in.h>
82 #include <zlib.h> /* to get the libz version number */
85 #ifdef NEED_SNPRINTF_H
86 # include "snprintf.h"
89 #ifdef HAVE_UCD_SNMP_VERSION_H
90 #include <ucd-snmp/version.h>
91 #endif /* HAVE_UCD_SNMP_VERSION_H */
93 #ifdef NEED_STRERROR_H
101 #ifdef WIN32 /* Needed for console I/O */
106 #include <epan/epan.h>
107 #include <epan/filesystem.h>
108 #include <epan/epan_dissect.h>
111 #include <epan/timestamp.h>
112 #include <epan/packet.h>
121 #include "color_utils.h"
122 #include "filter_prefs.h"
123 #include "file_dlg.h"
126 #include <epan/resolv.h>
128 #include "pcap-util.h"
130 #include "statusbar.h"
131 #include "simple_dialog.h"
132 #include "proto_draw.h"
133 #include <epan/dfilter/dfilter.h>
135 #include "packet_win.h"
136 #include "gtkglobals.h"
137 #include <epan/plugins.h>
139 #include <epan/strutil.h>
140 #include "register.h"
141 #include "ringbuffer.h"
143 #include "image/clist_ascend.xpm"
144 #include "image/clist_descend.xpm"
147 #include "capture-wpcap.h"
150 typedef struct column_arrows {
152 GtkWidget *ascend_pm;
153 GtkWidget *descend_pm;
157 GtkWidget *top_level, *packet_list, *tree_view, *byte_nb_ptr,
158 *tv_scrollw, *pkt_scrollw;
159 static GtkWidget *info_bar;
160 GdkFont *m_r_font, *m_b_font;
161 guint m_font_height, m_font_width;
162 static guint main_ctx, file_ctx, help_ctx;
163 static GString *comp_info_str;
164 gchar *ethereal_path = NULL;
165 gchar *last_open_dir = NULL;
166 gint root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
168 ts_type timestamp_type = RELATIVE;
170 GtkStyle *item_style;
172 /* Specifies the field currently selected in the GUI protocol tree */
173 field_info *finfo_selected = NULL;
176 static gboolean has_no_console; /* TRUE if app has no console */
177 static gboolean console_was_created; /* TRUE if console was created */
178 static void create_console(void);
179 static void destroy_console(void);
180 static void console_log_handler(const char *log_domain,
181 GLogLevelFlags log_level, const char *message, gpointer user_data);
184 static void create_main_window(gint, gint, gint, e_prefs*);
186 #define E_DFILTER_CM_KEY "display_filter_combo"
187 #define E_DFILTER_FL_KEY "display_filter_list"
189 /* About Ethereal window */
191 about_ethereal( GtkWidget *w _U_, gpointer data _U_ ) {
192 simple_dialog(ESD_TYPE_INFO, NULL,
193 "Ethereal - Network Protocol Analyzer\n"
194 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@ethereal.com>\n"
197 "Check the man page for complete documentation and\n"
198 "for the list of contributors.\n"
200 "\nSee http://www.ethereal.com/ for more information.",
205 set_fonts(GdkFont *regular, GdkFont *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 m_font_height = m_r_font->ascent + m_r_font->descent;
214 m_font_width = gdk_string_width(m_r_font, "0");
218 /* Match selected byte pattern */
220 match_selected_cb_do(gpointer data, int action, gchar *text)
222 GtkWidget *filter_te;
223 char *cur_filter, *new_filter;
228 filter_te = gtk_object_get_data(GTK_OBJECT(data), E_DFILTER_TE_KEY);
231 cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
233 switch (action&MATCH_SELECTED_MASK) {
235 case MATCH_SELECTED_REPLACE:
236 new_filter = g_strdup(text);
239 case MATCH_SELECTED_AND:
240 if ((!cur_filter) || (0 == strlen(cur_filter)))
241 new_filter = g_strdup(text);
243 new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
246 case MATCH_SELECTED_OR:
247 if ((!cur_filter) || (0 == strlen(cur_filter)))
248 new_filter = g_strdup(text);
250 new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
253 case MATCH_SELECTED_NOT:
254 new_filter = g_strconcat("!(", text, ")", NULL);
257 case MATCH_SELECTED_AND_NOT:
258 if ((!cur_filter) || (0 == strlen(cur_filter)))
259 new_filter = g_strconcat("!(", text, ")", NULL);
261 new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
264 case MATCH_SELECTED_OR_NOT:
265 if ((!cur_filter) || (0 == strlen(cur_filter)))
266 new_filter = g_strconcat("!(", text, ")", NULL);
268 new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
272 g_assert_not_reached();
277 /* Free up the copy we got of the old filter text. */
280 /* create a new one and set the display filter entry accordingly */
281 gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
283 /* Run the display filter so it goes in effect. */
284 if (action&MATCH_SELECTED_APPLY_NOW)
285 filter_packets(&cfile, new_filter);
287 /* Free up the new filter text. */
290 /* Free up the generated text we were handed. */
295 match_selected_cb_replace(GtkWidget *w, gpointer data)
298 match_selected_cb_do((data ? data : w),
299 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
300 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
304 match_selected_cb_and(GtkWidget *w, gpointer data)
307 match_selected_cb_do((data ? data : w),
308 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
309 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
313 match_selected_cb_or(GtkWidget *w, gpointer data)
316 match_selected_cb_do((data ? data : w),
317 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
318 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
322 match_selected_cb_not(GtkWidget *w, gpointer data)
325 match_selected_cb_do((data ? data : w),
326 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
327 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
331 match_selected_cb_and_not(GtkWidget *w, gpointer data)
334 match_selected_cb_do((data ? data : w),
335 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
336 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
340 match_selected_cb_or_not(GtkWidget *w, gpointer data)
343 match_selected_cb_do((data ? data : w),
344 MATCH_SELECTED_OR_NOT,
345 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
349 prepare_selected_cb_replace(GtkWidget *w, gpointer data)
352 match_selected_cb_do((data ? data : w),
353 MATCH_SELECTED_REPLACE,
354 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
358 prepare_selected_cb_and(GtkWidget *w, gpointer data)
361 match_selected_cb_do((data ? data : w),
363 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
367 prepare_selected_cb_or(GtkWidget *w, gpointer data)
370 match_selected_cb_do((data ? data : w),
372 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
376 prepare_selected_cb_not(GtkWidget *w, gpointer data)
379 match_selected_cb_do((data ? data : w),
381 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
385 prepare_selected_cb_and_not(GtkWidget *w, gpointer data)
388 match_selected_cb_do((data ? data : w),
389 MATCH_SELECTED_AND_NOT,
390 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
394 prepare_selected_cb_or_not(GtkWidget *w, gpointer data)
397 match_selected_cb_do((data ? data : w),
398 MATCH_SELECTED_OR_NOT,
399 proto_alloc_dfilter_string(finfo_selected, cfile.pd));
403 get_text_from_packet_list(gpointer data)
405 gint row = (gint)gtk_object_get_data(GTK_OBJECT(data), E_MPACKET_LIST_ROW_KEY);
406 gint column = (gint)gtk_object_get_data(GTK_OBJECT(data), E_MPACKET_LIST_COL_KEY);
407 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
414 /* XXX - do something with "err" */
415 wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
416 cfile.pd, fdata->cap_len, &err);
418 edt = epan_dissect_new(FALSE, FALSE);
419 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
421 epan_dissect_fill_in_columns(edt);
423 if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
424 strlen(cfile.cinfo.col_expr_val[column]) != 0) {
425 len = strlen(cfile.cinfo.col_expr[column]) +
426 strlen(cfile.cinfo.col_expr_val[column]) + 5;
427 buf = g_malloc0(len);
428 snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
429 cfile.cinfo.col_expr_val[column]);
432 epan_dissect_free(edt);
439 match_selected_cb_replace2(GtkWidget *w _U_, gpointer data)
441 match_selected_cb_do(data,
442 MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
443 get_text_from_packet_list(data));
447 match_selected_cb_and2(GtkWidget *w _U_, gpointer data)
449 match_selected_cb_do(data,
450 MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
451 get_text_from_packet_list(data));
455 match_selected_cb_or2(GtkWidget *w _U_, gpointer data)
457 match_selected_cb_do(data,
458 MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
459 get_text_from_packet_list(data));
463 match_selected_cb_not2(GtkWidget *w _U_, gpointer data)
465 match_selected_cb_do(data,
466 MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
467 get_text_from_packet_list(data));
471 match_selected_cb_and_not2(GtkWidget *w _U_, gpointer data)
473 match_selected_cb_do(data,
474 MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
475 get_text_from_packet_list(data));
479 match_selected_cb_or_not2(GtkWidget *w _U_, gpointer data)
481 match_selected_cb_do(data,
482 MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
483 get_text_from_packet_list(data));
487 prepare_selected_cb_replace2(GtkWidget *w _U_, gpointer data)
489 match_selected_cb_do(data,
490 MATCH_SELECTED_REPLACE,
491 get_text_from_packet_list(data));
495 prepare_selected_cb_and2(GtkWidget *w _U_, gpointer data)
497 match_selected_cb_do(data,
499 get_text_from_packet_list(data));
503 prepare_selected_cb_or2(GtkWidget *w _U_, gpointer data)
505 match_selected_cb_do(data,
507 get_text_from_packet_list(data));
511 prepare_selected_cb_not2(GtkWidget *w _U_, gpointer data)
513 match_selected_cb_do(data,
515 get_text_from_packet_list(data));
519 prepare_selected_cb_and_not2(GtkWidget *w _U_, gpointer data)
521 match_selected_cb_do(data,
522 MATCH_SELECTED_AND_NOT,
523 get_text_from_packet_list(data));
527 prepare_selected_cb_or_not2(GtkWidget *w _U_, gpointer data)
529 match_selected_cb_do(data,
530 MATCH_SELECTED_OR_NOT,
531 get_text_from_packet_list(data));
534 /* Run the current display filter on the current packet set, and
537 filter_activate_cb(GtkWidget *w, gpointer data)
539 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
540 GList *filter_list = gtk_object_get_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY);
542 gboolean add_filter = TRUE;
543 gboolean free_filter = TRUE;
547 s = g_strdup(gtk_entry_get_text(GTK_ENTRY(data)));
549 /* GtkCombos don't let us get at their list contents easily, so we maintain
550 our own filter list, and feed it to gtk_combo_set_popdown_strings when
551 a new filter is added. */
552 if (filter_packets(&cfile, s)) {
553 li = g_list_first(filter_list);
555 if (li->data && strcmp(s, li->data) == 0)
562 filter_list = g_list_append(filter_list, s);
563 gtk_object_set_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY, filter_list);
564 gtk_combo_set_popdown_strings(filter_cm, filter_list);
565 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
572 /* redisplay with no display filter */
574 filter_reset_cb(GtkWidget *w, gpointer data _U_)
576 GtkWidget *filter_te = NULL;
578 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
579 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
581 filter_packets(&cfile, NULL);
584 /* GTKClist compare routine, overrides default to allow numeric comparison */
586 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
588 /* Get row text strings */
589 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
590 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
592 /* Attempt to convert to numbers */
593 double num1 = atof(text1);
594 double num2 = atof(text2);
596 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
598 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
599 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
600 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
601 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
602 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
603 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
604 (col_fmt == COL_PACKET_LENGTH)) {
606 /* Compare numeric column */
610 else if (num1 > num2)
618 /* Compare text column */
620 return (text1 != NULL);
625 return strcmp(text1, text2);
629 /* What to do when a column is clicked */
631 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
633 column_arrows *col_arrows = (column_arrows *) data;
636 gtk_clist_freeze(clist);
638 for (i = 0; i < cfile.cinfo.num_cols; i++) {
639 gtk_widget_hide(col_arrows[i].ascend_pm);
640 gtk_widget_hide(col_arrows[i].descend_pm);
643 if (column == clist->sort_column) {
644 if (clist->sort_type == GTK_SORT_ASCENDING) {
645 clist->sort_type = GTK_SORT_DESCENDING;
646 gtk_widget_show(col_arrows[column].descend_pm);
648 clist->sort_type = GTK_SORT_ASCENDING;
649 gtk_widget_show(col_arrows[column].ascend_pm);
653 clist->sort_type = GTK_SORT_ASCENDING;
654 gtk_widget_show(col_arrows[column].ascend_pm);
655 gtk_clist_set_sort_column(clist, column);
657 gtk_clist_thaw(clist);
659 gtk_clist_sort(clist);
664 set_frame_mark(gboolean set, frame_data *frame, gint row) {
670 mark_frame(&cfile, frame);
671 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
672 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
674 unmark_frame(&cfile, frame);
678 file_set_save_marked_sensitive();
679 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
680 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
684 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_) {
686 GdkEventButton *event_button = (GdkEventButton *)event;
689 if (w == NULL || event == NULL)
692 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
693 gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x, event_button->y,
695 frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
696 set_frame_mark(!fdata->flags.marked, fdata, row);
700 void mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
701 if (cfile.current_frame) {
702 /* XXX hum, should better have a "cfile->current_row" here ... */
703 set_frame_mark(!cfile.current_frame->flags.marked,
705 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
706 cfile.current_frame));
710 static void mark_all_frames(gboolean set) {
712 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
715 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
719 void update_marked_frames(void) {
721 if (cfile.plist == NULL) return;
722 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
723 if (fdata->flags.marked)
726 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
731 void mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
732 mark_all_frames(TRUE);
735 void unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
736 mark_all_frames(FALSE);
739 /* What to do when a list item is selected/unselected */
741 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
743 /* Remove the hex display tabbed pages */
744 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
745 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
747 select_packet(&cfile, row);
752 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
754 unselect_packet(&cfile);
759 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_, gpointer user_data _U_)
762 gchar *help_str = NULL;
763 gboolean has_blurb = FALSE;
764 guint length = 0, byte_len;
765 GtkWidget *byte_view;
766 const guint8 *byte_data;
769 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
772 set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
774 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
775 byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
776 g_assert(byte_data != NULL);
778 finfo_selected = finfo;
779 set_menus_for_selected_tree_row(TRUE);
782 if (finfo->hfinfo->blurb != NULL &&
783 finfo->hfinfo->blurb[0] != '\0') {
785 length = strlen(finfo->hfinfo->blurb);
787 length = strlen(finfo->hfinfo->name);
789 statusbar_pop_field_msg(); /* get rid of current help msg */
791 length += strlen(finfo->hfinfo->abbrev) + 10;
792 help_str = g_malloc(sizeof(gchar) * length);
793 sprintf(help_str, "%s (%s)",
794 (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
795 finfo->hfinfo->abbrev);
796 statusbar_push_field_msg(help_str);
800 * Don't show anything if the field name is zero-length;
801 * the pseudo-field for "proto_tree_add_text()" is such
802 * a field, and we don't want "Text (text)" showing up
803 * on the status line if you've selected such a field.
805 * XXX - there are zero-length fields for which we *do*
806 * want to show the field name.
808 * XXX - perhaps the name and abbrev field should be null
809 * pointers rather than null strings for that pseudo-field,
810 * but we'd have to add checks for null pointers in some
811 * places if we did that.
813 * Or perhaps protocol tree items added with
814 * "proto_tree_add_text()" should have -1 as the field index,
815 * with no pseudo-field being used, but that might also
816 * require special checks for -1 to be added.
818 statusbar_push_field_msg("");
822 packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
827 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_, gpointer user_data _U_)
829 GtkWidget *byte_view;
834 * Which byte view is displaying the current protocol tree
837 byte_view = get_notebook_bv_ptr(byte_nb_ptr);
838 if (byte_view == NULL)
841 data = get_byte_view_data_and_length(byte_view, &len);
846 packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
850 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
852 collapse_all_tree(cfile.edt->tree, tree_view);
855 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
857 expand_all_tree(cfile.edt->tree, tree_view);
860 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
861 if (cfile.edt->tree) {
862 guint32 tmp = g_resolv_flags;
863 g_resolv_flags = RESOLV_ALL;
864 proto_tree_draw(cfile.edt->tree, tree_view);
865 g_resolv_flags = tmp;
869 /* Set the selection mode of the packet list window. */
871 set_plist_sel_browse(gboolean val)
876 (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
878 if (val == old_val) {
880 * The mode isn't changing, so don't do anything.
881 * In particular, don't gratuitiously unselect the
884 * XXX - why do we have to unselect the current packet
885 * ourselves? The documentation for the GtkCList at
887 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
889 * says "Note that setting the widget's selection mode to
890 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
891 * cause all the items in the GtkCList to become deselected."
897 unselect_packet(&cfile);
899 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
900 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
902 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
905 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
909 /* Set the font of the packet list window. */
911 set_plist_font(GdkFont *font)
916 style = gtk_style_new();
917 gdk_font_unref(style->font);
921 gtk_widget_set_style(packet_list, style);
923 /* Compute static column sizes to use during a "-S" capture, so that
924 the columns don't resize during a live capture. */
925 for (i = 0; i < cfile.cinfo.num_cols; i++) {
926 cfile.cinfo.col_width[i] = gdk_string_width(font,
927 get_column_longest_string(get_column_format(i)));
932 * Push a message referring to file access onto the statusbar.
935 statusbar_push_file_msg(gchar *msg)
937 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
941 * Pop a message referring to file access off the statusbar.
944 statusbar_pop_file_msg(void)
946 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
950 * XXX - do we need multiple statusbar contexts?
954 * Push a message referring to the currently-selected field onto the statusbar.
957 statusbar_push_field_msg(gchar *msg)
959 gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
963 * Pop a message referring to the currently-selected field off the statusbar.
966 statusbar_pop_field_msg(void)
968 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
974 /* XXX - should we check whether the capture file is an
975 unsaved temporary file for a live capture and, if so,
976 pop up a "do you want to exit without saving the capture
977 file?" dialog, and then just return, leaving said dialog
978 box to forcibly quit if the user clicks "OK"?
980 If so, note that this should be done in a subroutine that
981 returns TRUE if we do so, and FALSE otherwise, and if it
982 returns TRUE we should return TRUE without nuking anything.
984 Note that, if we do that, we might also want to check if
985 an "Update list of packets in real time" capture is in
986 progress and, if so, ask whether they want to terminate
987 the capture and discard it, and return TRUE, before nuking
988 any child capture, if they say they don't want to do so. */
991 /* Nuke any child capture in progress. */
992 kill_capture_child();
995 /* Are we in the middle of reading a capture? */
996 if (cfile.state == FILE_READ_IN_PROGRESS) {
997 /* Yes, so we can't just close the file and quit, as
998 that may yank the rug out from under the read in
999 progress; instead, just set the state to
1000 "FILE_READ_ABORTED" and return - the code doing the read
1001 will check for that and, if it sees that, will clean
1003 cfile.state = FILE_READ_ABORTED;
1005 /* Say that the window should *not* be deleted;
1006 that'll be done by the code that cleans up. */
1009 /* Close any capture file we have open; on some OSes, you
1010 can't unlink a temporary capture file if you have it
1012 "close_cap_file()" will unlink it after closing it if
1013 it's a temporary file.
1015 We do this here, rather than after the main loop returns,
1016 as, after the main loop returns, the main window may have
1017 been destroyed (if this is called due to a "destroy"
1018 even on the main window rather than due to the user
1019 selecting a menu item), and there may be a crash
1020 or other problem when "close_cap_file()" tries to
1021 clean up stuff in the main window.
1023 XXX - is there a better place to put this?
1024 Or should we have a routine that *just* closes the
1025 capture file, and doesn't do anything with the UI,
1026 which we'd call here, and another routine that
1027 calls that routine and also cleans up the UI, which
1028 we'd call elsewhere? */
1029 close_cap_file(&cfile);
1031 /* Exit by leaving the main loop, so that any quit functions
1032 we registered get called. */
1035 /* Say that the window should be deleted. */
1041 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1043 gint desk_x, desk_y;
1045 /* Try to grab our geometry */
1046 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1047 if (gdk_window_get_deskrelative_origin(top_level->window,
1048 &desk_x, &desk_y)) {
1049 if (desk_x <= root_x && desk_y <= root_y) {
1055 /* XXX - Is this the "approved" method? */
1056 gdk_window_get_size(top_level->window, &top_width, &top_height);
1058 /* "do_quit()" indicates whether the main window should be deleted. */
1063 file_quit_cmd_cb (GtkWidget *widget _U_, gpointer data _U_)
1071 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
1072 comp_info_str->str);
1074 fprintf(stderr, "%s [ -vh ] [ -klpQS ] [ -a <capture autostop condition> ] ...\n",
1076 fprintf(stderr, "\t[ -b <number of ringbuffer files> ] [ -B <byte view height> ]\n");
1077 fprintf(stderr, "\t[ -c <count> ] [ -f <capture filter> ] [ -i <interface> ]\n");
1078 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -N <resolving> ]\n");
1079 fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1080 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1081 fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1082 fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n");
1084 fprintf(stderr, "%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1086 fprintf(stderr, "\t[ -n ] [ -N <resolving> ]\n");
1087 fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
1088 fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
1089 fprintf(stderr, "\t[ -T <tree view height> ] [ <infile> ]\n");
1100 printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
1104 get_positive_int(const char *string, const char *name)
1109 number = strtol(string, &p, 10);
1110 if (p == string || *p != '\0') {
1111 fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1116 fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1121 fprintf(stderr, "ethereal: The specified %s \"%s\" is zero\n",
1125 if (number > INT_MAX) {
1126 fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1127 name, string, INT_MAX);
1135 * Given a string of the form "<autostop criterion>:<value>", as might appear
1136 * as an argument to a "-a" option, parse it and set the criterion in
1137 * question. Return an indication of whether it succeeded or failed
1141 set_autostop_criterion(const char *autostoparg)
1145 colonp = strchr(autostoparg, ':');
1153 * Skip over any white space (there probably won't be any, but
1154 * as we allow it in the preferences file, we might as well
1161 * Put the colon back, so if our caller uses, in an
1162 * error message, the string they passed us, the message
1168 if (strcmp(autostoparg,"duration") == 0) {
1169 capture_opts.has_autostop_duration = TRUE;
1170 capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1171 } else if (strcmp(autostoparg,"filesize") == 0) {
1172 capture_opts.has_autostop_filesize = TRUE;
1173 capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1177 *colonp = ':'; /* put the colon back */
1182 /* And now our feature presentation... [ fade to music ] */
1184 main(int argc, char *argv[])
1192 extern char *optarg;
1193 gboolean arg_error = FALSE;
1195 #ifdef HAVE_PCAP_VERSION
1196 extern char pcap_version[];
1197 #endif /* HAVE_PCAP_VERSION */
1198 #endif /* HAVE_LIBPCAP */
1204 char *gpf_path, *cf_path, *df_path;
1205 const char *pf_path;
1206 int gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
1209 gboolean start_capture = FALSE;
1210 gchar *save_file = NULL;
1212 gchar err_str[PCAP_ERRBUF_SIZE];
1213 gboolean stats_known;
1214 struct pcap_stat stats;
1216 gboolean capture_option_specified = FALSE;
1218 gint pl_size = 280, tv_size = 95, bv_size = 75;
1219 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1220 dfilter_t *rfcode = NULL;
1221 gboolean rfilter_parse_failed = FALSE;
1224 char *bold_font_name;
1225 gint desk_x, desk_y;
1226 gboolean prefs_write_needed = FALSE;
1229 ethereal_path = argv[0];
1232 /* Arrange that if we have no console window, and a GLib message logging
1233 routine is called to log a message, we pop up a console window.
1235 We do that by inserting our own handler for all messages logged
1236 to the default domain; that handler pops up a console if necessary,
1237 and then calls the default handler. */
1238 g_log_set_handler(NULL,
1240 G_LOG_LEVEL_CRITICAL|
1241 G_LOG_LEVEL_WARNING|
1242 G_LOG_LEVEL_MESSAGE|
1245 G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1246 console_log_handler, NULL);
1250 command_name = get_basename(ethereal_path);
1251 /* Set "capture_child" to indicate whether this is going to be a child
1252 process for a "-S" capture. */
1253 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1256 /* Register all dissectors; we must do this before checking for the
1257 "-G" flag, as the "-G" flag dumps information registered by the
1258 dissectors, and we must do it before we read the preferences, in
1259 case any dissectors register preferences. */
1260 epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
1262 /* Now register the preferences for any non-dissector modules.
1263 We must do that before we read the preferences as well. */
1264 prefs_register_modules();
1266 /* If invoked with the "-G" flag, we dump out information based on
1267 the argument to the "-G" flag; if no argument is specified,
1268 for backwards compatibility we dump out a glossary of display
1271 We must do this before calling "gtk_init()", because "gtk_init()"
1272 tries to open an X display, and we don't want to have to do any X
1273 stuff just to do a build.
1275 Given that we call "gtk_init()" before doing the regular argument
1276 list processing, so that it can handle X and GTK+ arguments and
1277 remove them from the list at which we look, this means we must do
1278 this before doing the regular argument list processing, as well.
1282 you must give the "-G" flag as the first flag on the command line;
1284 you must give it as "-G", nothing more, nothing less;
1286 the first argument after the "-G" flag, if present, will be used
1287 to specify the information to dump;
1289 arguments after that will not be used. */
1290 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1292 proto_registrar_dump_fields();
1294 if (strcmp(argv[2], "fields") == 0)
1295 proto_registrar_dump_fields();
1296 else if (strcmp(argv[2], "protocols") == 0)
1297 proto_registrar_dump_protocols();
1299 fprintf(stderr, "tethereal: Invalid \"%s\" option for -G flag\n",
1307 /* Set the current locale according to the program environment.
1308 * We haven't localized anything, but some GTK widgets are localized
1309 * (the file selection dialogue, for example).
1310 * This also sets the C-language locale to the native environment. */
1313 /* Let GTK get its args */
1314 gtk_init (&argc, &argv);
1316 /* Read the preference files. */
1317 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1320 capture_opts.has_snaplen = FALSE;
1321 capture_opts.snaplen = MIN_PACKET_SIZE;
1322 capture_opts.has_autostop_count = FALSE;
1323 capture_opts.autostop_count = 1;
1324 capture_opts.has_autostop_duration = FALSE;
1325 capture_opts.autostop_duration = 1;
1326 capture_opts.has_autostop_filesize = FALSE;
1327 capture_opts.autostop_filesize = 1;
1328 capture_opts.ringbuffer_on = FALSE;
1329 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1331 /* If this is a capture child process, it should pay no attention
1332 to the "prefs.capture_prom_mode" setting in the preferences file;
1333 it should do what the parent process tells it to do, and if
1334 the parent process wants it not to run in promiscuous mode, it'll
1335 tell it so with a "-p" flag.
1337 Otherwise, set promiscuous mode from the preferences setting. */
1339 capture_opts.promisc_mode = TRUE;
1341 capture_opts.promisc_mode = prefs->capture_prom_mode;
1343 /* Set "Update list of packets in real time" mode from the preferences
1345 capture_opts.sync_mode = prefs->capture_real_time;
1347 /* And do the same for "Automatic scrolling in live capture" mode. */
1348 auto_scroll_live = prefs->capture_auto_scroll;
1351 /* Set the name resolution code's flags from the preferences. */
1352 g_resolv_flags = prefs->name_resolve;
1354 /* Read the capture filter file. */
1355 read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1357 /* Read the display filter file. */
1358 read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1360 /* Initialize the capture file struct */
1362 cfile.plist_end = NULL;
1364 cfile.filename = NULL;
1365 cfile.user_saved = FALSE;
1366 cfile.is_tempfile = FALSE;
1367 cfile.rfcode = NULL;
1368 cfile.dfilter = NULL;
1369 cfile.dfcode = NULL;
1371 cfile.cfilter = g_strdup(EMPTY_FILTER);
1374 cfile.save_file = NULL;
1375 cfile.save_file_fd = -1;
1376 cfile.has_snap = FALSE;
1377 cfile.snap = WTAP_MAX_PACKET_SIZE;
1379 col_init(&cfile.cinfo, prefs->num_cols);
1381 /* Assemble the compile-time options */
1382 comp_info_str = g_string_new("");
1384 g_string_append(comp_info_str, "with ");
1385 g_string_sprintfa(comp_info_str,
1386 #ifdef GTK_MAJOR_VERSION
1387 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1390 "GTK+ (version unknown)");
1393 g_string_append(comp_info_str, ", with ");
1394 g_string_sprintfa(comp_info_str,
1395 #ifdef GLIB_MAJOR_VERSION
1396 "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
1397 GLIB_MICRO_VERSION);
1399 "GLib (version unknown)");
1403 g_string_append(comp_info_str, ", with libpcap ");
1404 #ifdef HAVE_PCAP_VERSION
1405 g_string_append(comp_info_str, pcap_version);
1406 #else /* HAVE_PCAP_VERSION */
1407 g_string_append(comp_info_str, "(version unknown)");
1408 #endif /* HAVE_PCAP_VERSION */
1409 #else /* HAVE_LIBPCAP */
1410 g_string_append(comp_info_str, ", without libpcap");
1411 #endif /* HAVE_LIBPCAP */
1414 g_string_append(comp_info_str, ", with libz ");
1416 g_string_append(comp_info_str, ZLIB_VERSION);
1417 #else /* ZLIB_VERSION */
1418 g_string_append(comp_info_str, "(version unknown)");
1419 #endif /* ZLIB_VERSION */
1420 #else /* HAVE_LIBZ */
1421 g_string_append(comp_info_str, ", without libz");
1422 #endif /* HAVE_LIBZ */
1424 /* Oh, this is pretty */
1425 #ifdef HAVE_UCD_SNMP
1426 g_string_append(comp_info_str, ", with UCD SNMP ");
1427 #ifdef HAVE_UCD_SNMP_VERSION_H
1428 g_string_append(comp_info_str, VersionInfo);
1429 #else /* HAVE_UCD_SNMP_VERSION_H */
1430 g_string_append(comp_info_str, "(version unknown)");
1431 #endif /* HAVE_UCD_SNMP_VERSION_H */
1432 #else /* no SNMP library */
1433 g_string_append(comp_info_str, ", without UCD SNMP");
1436 /* Now get our args */
1437 while ((opt = getopt(argc, argv, "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:W:vZ:")) != -1) {
1439 case 'a': /* autostop criteria */
1441 if (set_autostop_criterion(optarg) == FALSE) {
1442 fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1446 capture_option_specified = TRUE;
1450 case 'b': /* Ringbuffer option */
1452 capture_opts.ringbuffer_on = TRUE;
1453 capture_opts.ringbuffer_num_files =
1454 get_positive_int(optarg, "number of ring buffer files");
1456 capture_option_specified = TRUE;
1460 case 'B': /* Byte view pane height */
1461 bv_size = get_positive_int(optarg, "byte view pane height");
1463 case 'c': /* Capture xxx packets */
1465 capture_opts.has_autostop_count = TRUE;
1466 capture_opts.autostop_count = get_positive_int(optarg, "packet count");
1468 capture_option_specified = TRUE;
1475 g_free(cfile.cfilter);
1476 cfile.cfilter = g_strdup(optarg);
1478 capture_option_specified = TRUE;
1482 case 'h': /* Print help and exit */
1486 case 'i': /* Use interface xxx */
1488 cfile.iface = g_strdup(optarg);
1490 capture_option_specified = TRUE;
1494 case 'k': /* Start capture immediately */
1496 start_capture = TRUE;
1498 capture_option_specified = TRUE;
1502 case 'l': /* Automatic scrolling in live capture mode */
1504 auto_scroll_live = TRUE;
1506 capture_option_specified = TRUE;
1510 case 'm': /* Fixed-width font for the display */
1511 if (prefs->gui_font_name != NULL)
1512 g_free(prefs->gui_font_name);
1513 prefs->gui_font_name = g_strdup(optarg);
1515 case 'n': /* No name resolution */
1516 g_resolv_flags = RESOLV_NONE;
1518 case 'N': /* Select what types of addresses/port #s to resolve */
1519 if (g_resolv_flags == RESOLV_ALL)
1520 g_resolv_flags = RESOLV_NONE;
1521 badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1522 if (badopt != '\0') {
1523 fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1528 case 'o': /* Override preference from command line */
1529 switch (prefs_set_pref(optarg)) {
1531 case PREFS_SET_SYNTAX_ERR:
1532 fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1536 case PREFS_SET_NO_SUCH_PREF:
1537 case PREFS_SET_OBSOLETE:
1538 fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1544 case 'p': /* Don't capture in promiscuous mode */
1546 capture_opts.promisc_mode = FALSE;
1548 capture_option_specified = TRUE;
1552 case 'P': /* Packet list pane height */
1553 pl_size = get_positive_int(optarg, "packet list pane height");
1555 case 'Q': /* Quit after capture (just capture to file) */
1558 start_capture = TRUE; /*** -Q implies -k !! ***/
1560 capture_option_specified = TRUE;
1564 case 'r': /* Read capture file xxx */
1565 /* We may set "last_open_dir" to "cf_name", and if we change
1566 "last_open_dir" later, we free the old value, so we have to
1567 set "cf_name" to something that's been allocated. */
1568 cf_name = g_strdup(optarg);
1570 case 'R': /* Read file filter */
1573 case 's': /* Set the snapshot (capture) length */
1575 capture_opts.has_snaplen = TRUE;
1576 capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
1578 capture_option_specified = TRUE;
1582 case 'S': /* "Sync" mode: used for following file ala tail -f */
1584 capture_opts.sync_mode = TRUE;
1586 capture_option_specified = TRUE;
1590 case 't': /* Time stamp type */
1591 if (strcmp(optarg, "r") == 0)
1592 timestamp_type = RELATIVE;
1593 else if (strcmp(optarg, "a") == 0)
1594 timestamp_type = ABSOLUTE;
1595 else if (strcmp(optarg, "ad") == 0)
1596 timestamp_type = ABSOLUTE_WITH_DATE;
1597 else if (strcmp(optarg, "d") == 0)
1598 timestamp_type = DELTA;
1600 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1602 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1603 fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1607 case 'T': /* Tree view pane height */
1608 tv_size = get_positive_int(optarg, "tree view pane height");
1610 case 'v': /* Show version and exit */
1613 if (console_was_created)
1618 case 'w': /* Write to capture file xxx */
1620 save_file = g_strdup(optarg);
1622 capture_option_specified = TRUE;
1626 case 'W': /* Write to capture file FD xxx */
1628 cfile.save_file_fd = atoi(optarg);
1630 capture_option_specified = TRUE;
1636 case 'Z': /* Write to pipe FD XXX */
1638 /* associate stdout with pipe */
1640 if (dup2(i, 1) < 0) {
1641 fprintf(stderr, "Unable to dup pipe handle\n");
1645 capture_option_specified = TRUE;
1647 #endif /* HAVE_LIBPCAP */
1652 case '?': /* Bad flag - print usage message */
1660 if (cf_name != NULL) {
1662 * Input file name specified with "-r" *and* specified as a regular
1663 * command-line argument.
1668 * Input file name not specified with "-r", and a command-line argument
1669 * was specified; treat it as the input file name.
1671 * Yes, this is different from tethereal, where non-flag command-line
1672 * arguments are a filter, but this works better on GUI desktops
1673 * where a command can be specified to be run to open a particular
1674 * file - yes, you could have "-r" as the last part of the command,
1675 * but that's a bit ugly.
1677 cf_name = g_strdup(argv[0]);
1685 * Extra command line arguments were specified; complain.
1691 if (capture_opts.ringbuffer_on) {
1692 /* Ring buffer works only under certain conditions:
1693 a) ring buffer does not work with temporary files;
1694 b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
1695 sync_mode takes precedence;
1696 c) it makes no sense to enable the ring buffer if the maximum
1697 file size is set to "infinite". */
1698 if (cfile.save_file == NULL) {
1699 fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
1700 capture_opts.ringbuffer_on = FALSE;
1702 if (capture_opts.sync_mode) {
1703 fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
1704 capture_opts.ringbuffer_on = FALSE;
1706 if (!capture_opts.has_autostop_filesize) {
1707 fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
1708 capture_opts.ringbuffer_on = FALSE;
1714 /* Load wpcap if possible */
1717 /* Start windows sockets */
1718 WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1721 /* Notify all registered modules that have had any of their preferences
1722 changed either from one of the preferences file or from the command
1723 line that its preferences have changed. */
1726 #ifndef HAVE_LIBPCAP
1727 if (capture_option_specified)
1728 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1733 if (start_capture) {
1734 /* We're supposed to do a live capture; did the user specify an interface
1736 if (cfile.iface == NULL) {
1737 /* No - pick the first one from the list of interfaces. */
1738 if_list = get_interface_list(&err, err_str);
1739 if (if_list == NULL) {
1742 case CANT_GET_INTERFACE_LIST:
1743 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1747 case NO_INTERFACES_FOUND:
1748 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1753 cfile.iface = g_strdup(if_list->data); /* first interface */
1754 free_interface_list(if_list);
1757 if (capture_child) {
1758 if (cfile.save_file_fd == -1) {
1759 /* XXX - send this to the standard output as something our parent
1760 should put in an error message box? */
1761 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1767 /* Build the column format array */
1768 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1769 cfile.cinfo.col_fmt[i] = get_column_format(i);
1770 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1771 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1773 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1774 cfile.cinfo.col_data[i] = NULL;
1775 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1776 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1778 cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1779 cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1780 cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1784 if (capture_opts.has_snaplen) {
1785 if (capture_opts.snaplen < 1)
1786 capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
1787 else if (capture_opts.snaplen < MIN_PACKET_SIZE)
1788 capture_opts.snaplen = MIN_PACKET_SIZE;
1791 /* Check the value range of the ringbuffer_num_files parameter */
1792 if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
1793 capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1794 else if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
1795 capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
1798 rc_file = get_persconffile_path(RC_FILE, FALSE);
1799 gtk_rc_parse(rc_file);
1801 /* Try to load the regular and boldface fixed-width fonts */
1802 bold_font_name = boldify(prefs->gui_font_name);
1803 m_r_font = gdk_font_load(prefs->gui_font_name);
1804 m_b_font = gdk_font_load(bold_font_name);
1805 if (m_r_font == NULL || m_b_font == NULL) {
1806 /* XXX - pop this up as a dialog box? no */
1807 if (m_r_font == NULL) {
1811 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1812 prefs->gui_font_name);
1814 gdk_font_unref(m_r_font);
1816 if (m_b_font == NULL) {
1820 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
1823 gdk_font_unref(m_b_font);
1825 g_free(bold_font_name);
1826 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
1827 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
1830 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
1831 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
1834 g_free(prefs->gui_font_name);
1835 prefs->gui_font_name = g_strdup("6x13");
1838 /* Call this for the side-effects that set_fonts() produces */
1839 set_fonts(m_r_font, m_b_font);
1843 /* Is this a "child" ethereal, which is only supposed to pop up a
1844 capture box to let us stop the capture, and run a capture
1845 to a file that our parent will read? */
1846 if (!capture_child) {
1848 /* No. Pop up the main window, and read in a capture file if
1851 create_main_window(pl_size, tv_size, bv_size, prefs);
1852 set_menus_for_capture_file(FALSE);
1854 cfile.colors = colfilter_new();
1856 /* If we were given the name of a capture file, read it in now;
1857 we defer it until now, so that, if we can't open it, and pop
1858 up an alert box, the alert box is more likely to come up on
1859 top of the main window - but before the preference-file-error
1860 alert box, so, if we get one of those, it's more likely to come
1863 if (rfilter != NULL) {
1864 if (!dfilter_compile(rfilter, &rfcode)) {
1865 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
1866 rfilter_parse_failed = TRUE;
1869 if (!rfilter_parse_failed) {
1870 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1871 /* "open_cap_file()" succeeded, so it closed the previous
1872 capture file, and thus destroyed any previous read filter
1873 attached to "cf". */
1874 cfile.rfcode = rfcode;
1875 switch (read_cap_file(&cfile, &err)) {
1879 /* Just because we got an error, that doesn't mean we were unable
1880 to read any of the file; we handle what we could get from the
1889 /* Save the name of the containing directory specified in the
1890 path name, if any; we can write over cf_name, which is a
1891 good thing, given that "get_dirname()" does write over its
1893 s = get_dirname(cf_name);
1894 set_last_open_dir(s);
1897 dfilter_free(rfcode);
1898 cfile.rfcode = NULL;
1906 /* If the global preferences file exists but we failed to open it,
1907 pop up an alert box; we defer that until now, so that the alert
1908 box is more likely to come up on top of the main window. */
1909 if (gpf_path != NULL) {
1910 simple_dialog(ESD_TYPE_WARN, NULL,
1911 "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1912 strerror(gpf_open_errno));
1915 /* If the user's preferences file exists but we failed to open it,
1916 pop up an alert box; we defer that until now, so that the alert
1917 box is more likely to come up on top of the main window. */
1918 if (pf_path != NULL) {
1919 simple_dialog(ESD_TYPE_WARN, NULL,
1920 "Could not open your preferences file\n\"%s\": %s.", pf_path,
1921 strerror(pf_open_errno));
1924 /* If the user's capture filter file exists but we failed to open it,
1925 pop up an alert box; we defer that until now, so that the alert
1926 box is more likely to come up on top of the main window. */
1927 if (cf_path != NULL) {
1928 simple_dialog(ESD_TYPE_WARN, NULL,
1929 "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1930 strerror(cf_open_errno));
1934 /* If the user's display filter file exists but we failed to open it,
1935 pop up an alert box; we defer that until now, so that the alert
1936 box is more likely to come up on top of the main window. */
1937 if (df_path != NULL) {
1938 simple_dialog(ESD_TYPE_WARN, NULL,
1939 "Could not open your display filter file\n\"%s\": %s.", df_path,
1940 strerror(df_open_errno));
1945 if (capture_child) {
1946 /* This is the child process for a sync mode or fork mode capture,
1947 so just do the low-level work of a capture - don't create
1948 a temporary file and fork off *another* child process (so don't
1949 call "do_capture()"). */
1951 /* XXX - hand these stats to the parent process */
1952 capture(&stats_known, &stats);
1954 /* The capture is done; there's nothing more for us to do. */
1957 if (start_capture) {
1958 /* "-k" was specified; start a capture. */
1959 do_capture(save_file);
1962 set_menus_for_capture_in_progress(FALSE);
1966 set_menus_for_capture_in_progress(FALSE);
1971 /* Try to save our geometry. GTK+ provides two routines to get a
1972 window's position relative to the X root window. If I understand the
1973 documentation correctly, gdk_window_get_deskrelative_origin applies
1974 mainly to Enlightenment and gdk_window_get_root_origin applies for
1977 The code below tries both routines, and picks the one that returns
1978 the upper-left-most coordinates.
1982 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
1983 http://www.gtk.org/faq/#AEN600 */
1985 /* Re-read our saved preferences. */
1986 /* XXX - Move all of this into a separate function? */
1987 prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1989 if (pf_path == NULL) {
1990 if (prefs->gui_geometry_save_position) {
1991 if (top_level->window != NULL) {
1992 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1993 if (gdk_window_get_deskrelative_origin(top_level->window,
1994 &desk_x, &desk_y)) {
1995 if (desk_x <= root_x && desk_y <= root_y) {
2001 if (prefs->gui_geometry_main_x != root_x) {
2002 prefs->gui_geometry_main_x = root_x;
2003 prefs_write_needed = TRUE;
2005 if (prefs->gui_geometry_main_y != root_y) {
2006 prefs->gui_geometry_main_y = root_y;
2007 prefs_write_needed = TRUE;
2011 if (prefs->gui_geometry_save_size) {
2012 if (top_level->window != NULL) {
2013 /* XXX - Is this the "approved" method? */
2014 gdk_window_get_size(top_level->window, &top_width, &top_height);
2016 if (prefs->gui_geometry_main_width != top_width) {
2017 prefs->gui_geometry_main_width = top_width;
2018 prefs_write_needed = TRUE;
2020 if (prefs->gui_geometry_main_height != top_height) {
2021 prefs->gui_geometry_main_height = top_height;
2022 prefs_write_needed = TRUE;
2026 if (prefs_write_needed) {
2027 write_prefs(&pf_path);
2035 /* Shutdown windows sockets */
2038 /* For some unknown reason, the "atexit()" call in "create_console()"
2039 doesn't arrange that "destroy_console()" be called when we exit,
2040 so we call it here if a console was created. */
2041 if (console_was_created)
2047 /* This isn't reached, but we need it to keep GCC from complaining
2048 that "main()" returns without returning a value - it knows that
2049 "exit()" never returns, but it doesn't know that "gtk_exit()"
2050 doesn't, as GTK+ doesn't declare it with the attribute
2052 return 0; /* not reached */
2057 /* We build this as a GUI subsystem application on Win32, so
2058 "WinMain()", not "main()", gets called.
2060 Hack shamelessly stolen from the Win32 port of the GIMP. */
2062 #define _stdcall __attribute__((stdcall))
2066 WinMain (struct HINSTANCE__ *hInstance,
2067 struct HINSTANCE__ *hPrevInstance,
2071 has_no_console = TRUE;
2072 return main (__argc, __argv);
2076 * If this application has no console window to which its standard output
2077 * would go, create one.
2080 create_console(void)
2082 if (has_no_console) {
2083 /* We have no console to which to print the version string, so
2084 create one and make it the standard input, output, and error. */
2085 if (!AllocConsole())
2086 return; /* couldn't create console */
2087 freopen("CONIN$", "r", stdin);
2088 freopen("CONOUT$", "w", stdout);
2089 freopen("CONOUT$", "w", stderr);
2091 /* Well, we have a console now. */
2092 has_no_console = FALSE;
2093 console_was_created = TRUE;
2095 /* Now register "destroy_console()" as a routine to be called just
2096 before the application exits, so that we can destroy the console
2097 after the user has typed a key (so that the console doesn't just
2098 disappear out from under them, giving the user no chance to see
2099 the message(s) we put in there). */
2100 atexit(destroy_console);
2105 destroy_console(void)
2107 printf("\n\nPress any key to exit\n");
2112 /* This routine should not be necessary, at least as I read the GLib
2113 source code, as it looks as if GLib is, on Win32, *supposed* to
2114 create a console window into which to display its output.
2116 That doesn't happen, however. I suspect there's something completely
2117 broken about that code in GLib-for-Win32, and that it may be related
2118 to the breakage that forces us to just call "printf()" on the message
2119 rather than passing the message on to "g_log_default_handler()"
2120 (which is the routine that does the aforementioned non-functional
2121 console window creation). */
2123 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2124 const char *message, gpointer user_data)
2127 if (console_was_created) {
2128 /* For some unknown reason, the above doesn't appear to actually cause
2129 anything to be sent to the standard output, so we'll just splat the
2130 message out directly, just to make sure it gets out. */
2131 printf("%s\n", message);
2133 g_log_default_handler(log_domain, log_level, message, user_data);
2137 /* Given a font name, construct the name of the next heavier version of
2140 #define XLFD_WEIGHT 3 /* index of the "weight" field */
2142 /* Map from a given weight to the appropriate weight for the "bold"
2144 XXX - the XLFD says these strings shouldn't be used for font matching;
2145 can we get the weight, as a number, from GDK, and ask GDK to find us
2146 a font just like the given font, but with the appropriate higher
2148 static const struct {
2152 { "ultralight", "light" },
2153 { "extralight", "semilight" },
2154 { "light", "medium" },
2155 { "semilight", "semibold" },
2156 { "medium", "bold" },
2157 { "normal", "bold" },
2158 { "semibold", "extrabold" },
2159 { "bold", "ultrabold" }
2161 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
2164 boldify(const char *font_name)
2166 char *bold_font_name;
2167 gchar **xlfd_tokens;
2170 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
2171 if (font_name[0] == '-') {
2172 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
2173 for (i = 0; i < N_WEIGHTS; i++) {
2174 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
2175 weight_map[i].light) == 0) {
2176 g_free(xlfd_tokens[XLFD_WEIGHT]);
2177 xlfd_tokens[XLFD_WEIGHT] =
2178 g_strdup(weight_map[i].heavier);
2182 bold_font_name = g_strjoinv("-", xlfd_tokens);
2183 g_strfreev(xlfd_tokens);
2185 /* Append "bold" to the name of the font. */
2186 bold_font_name = g_strconcat(font_name, "bold", NULL);
2188 return bold_font_name;
2193 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2195 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
2196 *stat_hbox, *column_lb,
2197 *filter_bt, *filter_cm, *filter_te,
2200 GList *filter_list = NULL;
2201 GtkAccelGroup *accel;
2202 GtkStyle *win_style;
2203 GdkBitmap *ascend_bm, *descend_bm;
2204 GdkPixmap *ascend_pm, *descend_pm;
2205 column_arrows *col_arrows;
2207 /* Display filter construct dialog has an Apply button, and "OK" not
2208 only sets our text widget, it activates it (i.e., it causes us to
2209 filter the capture). */
2210 static construct_args_t args = {
2211 "Ethereal: Display Filter",
2217 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2218 gtk_widget_set_name(top_level, "main window");
2219 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
2220 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
2221 gtk_signal_connect (GTK_OBJECT (top_level), "realize",
2222 GTK_SIGNAL_FUNC (window_icon_realize_cb), NULL);
2223 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
2224 if (prefs->gui_geometry_save_position) {
2225 gtk_widget_set_uposition(GTK_WIDGET(top_level),
2226 prefs->gui_geometry_main_x, prefs->gui_geometry_main_y);
2228 if (prefs->gui_geometry_save_size) {
2229 gtk_widget_set_usize(GTK_WIDGET(top_level),
2230 prefs->gui_geometry_main_width, prefs->gui_geometry_main_height);
2232 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
2234 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2236 /* Container for menu bar, paned windows and progress/info box */
2237 main_vbox = gtk_vbox_new(FALSE, 1);
2238 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2239 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2240 gtk_widget_show(main_vbox);
2243 get_main_menu(&menubar, &accel);
2244 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2245 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2246 gtk_widget_show(menubar);
2248 /* Panes for the packet list, tree, and byte view */
2249 u_pane = gtk_vpaned_new();
2250 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
2251 l_pane = gtk_vpaned_new();
2252 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
2253 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
2254 gtk_widget_show(l_pane);
2255 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
2256 gtk_widget_show(u_pane);
2259 pkt_scrollw = scrolled_window_new(NULL, NULL);
2260 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
2261 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2262 gtk_widget_show(pkt_scrollw);
2263 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
2265 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
2266 /* Column titles are filled in below */
2267 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
2269 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * cfile.cinfo.num_cols);
2271 set_plist_sel_browse(prefs->gui_plist_sel_browse);
2272 set_plist_font(m_r_font);
2273 gtk_widget_set_name(packet_list, "packet list");
2274 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
2275 GTK_SIGNAL_FUNC(packet_list_click_column_cb), col_arrows);
2276 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
2277 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
2278 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
2279 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
2280 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2281 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
2282 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
2284 /* Right-justify the packet number column. */
2285 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
2286 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
2289 gtk_widget_set_usize(packet_list, -1, pl_size);
2290 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
2291 GTK_SIGNAL_FUNC(popup_menu_handler),
2292 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
2293 gtk_signal_connect(GTK_OBJECT(packet_list), "button_press_event",
2294 GTK_SIGNAL_FUNC(packet_list_button_pressed_cb), NULL);
2295 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
2296 gtk_widget_show(packet_list);
2299 item_style = gtk_style_new();
2300 gdk_font_unref(item_style->font);
2301 item_style->font = m_r_font;
2302 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view);
2303 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
2304 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
2305 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
2306 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
2307 gtk_signal_connect(GTK_OBJECT(tree_view), "button_press_event",
2308 GTK_SIGNAL_FUNC(popup_menu_handler),
2309 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
2310 gtk_widget_show(tree_view);
2313 byte_nb_ptr = create_byte_view(bv_size, l_pane);
2315 gtk_signal_connect(GTK_OBJECT(byte_nb_ptr), "button_press_event",
2316 GTK_SIGNAL_FUNC(popup_menu_handler),
2317 gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY));
2319 /* Filter/info box */
2320 stat_hbox = gtk_hbox_new(FALSE, 1);
2321 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
2322 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2323 gtk_widget_show(stat_hbox);
2325 filter_bt = gtk_button_new_with_label("Filter:");
2326 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
2327 GTK_SIGNAL_FUNC(display_filter_construct_cb), &args);
2328 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
2329 gtk_widget_show(filter_bt);
2331 filter_cm = gtk_combo_new();
2332 filter_list = g_list_append (filter_list, "");
2333 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
2334 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
2335 gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
2336 gtk_object_set_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY, filter_list);
2337 filter_te = GTK_COMBO(filter_cm)->entry;
2338 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
2339 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
2340 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
2341 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
2342 GTK_SIGNAL_FUNC(filter_activate_cb), filter_te);
2343 gtk_widget_show(filter_cm);
2345 filter_reset = gtk_button_new_with_label("Reset");
2346 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
2347 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
2348 GTK_SIGNAL_FUNC(filter_reset_cb), NULL);
2349 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
2350 gtk_widget_show(filter_reset);
2352 filter_apply = gtk_button_new_with_label("Apply");
2353 gtk_object_set_data(GTK_OBJECT(filter_apply), E_DFILTER_CM_KEY, filter_cm);
2354 gtk_signal_connect(GTK_OBJECT(filter_apply), "clicked",
2355 GTK_SIGNAL_FUNC(filter_activate_cb), filter_te);
2356 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_apply, FALSE, TRUE, 1);
2357 gtk_widget_show(filter_apply);
2359 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
2360 * of any widget that ends up calling a callback which needs
2361 * that text entry pointer */
2362 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
2363 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
2364 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
2365 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
2366 set_menu_object_data("/Display/Match/Selected", E_DFILTER_TE_KEY, filter_te);
2367 set_menu_object_data("/Display/Match/Not Selected", E_DFILTER_TE_KEY, filter_te);
2368 set_menu_object_data("/Display/Match/And Selected", E_DFILTER_TE_KEY, filter_te);
2369 set_menu_object_data("/Display/Match/Or Selected", E_DFILTER_TE_KEY, filter_te);
2370 set_menu_object_data("/Display/Match/And Not Selected", E_DFILTER_TE_KEY, filter_te);
2371 set_menu_object_data("/Display/Match/Or Not Selected", E_DFILTER_TE_KEY, filter_te);
2372 set_menu_object_data("/Display/Prepare/Selected", E_DFILTER_TE_KEY, filter_te);
2373 set_menu_object_data("/Display/Prepare/Not Selected", E_DFILTER_TE_KEY, filter_te);
2374 set_menu_object_data("/Display/Prepare/And Selected", E_DFILTER_TE_KEY, filter_te);
2375 set_menu_object_data("/Display/Prepare/Or Selected", E_DFILTER_TE_KEY, filter_te);
2376 set_menu_object_data("/Display/Prepare/And Not Selected", E_DFILTER_TE_KEY, filter_te);
2377 set_menu_object_data("/Display/Prepare/Or Not Selected", E_DFILTER_TE_KEY, filter_te);
2378 gtk_object_set_data(GTK_OBJECT(popup_menu_object), E_DFILTER_TE_KEY, filter_te);
2379 gtk_object_set_data(GTK_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, packet_list);
2381 info_bar = gtk_statusbar_new();
2382 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2383 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2384 help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2385 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2386 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2387 gtk_widget_show(info_bar);
2389 gtk_widget_show(top_level);
2391 /* Fill in column titles. This must be done after the top level window
2393 win_style = gtk_widget_get_style(top_level);
2394 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
2395 &win_style->bg[GTK_STATE_NORMAL], (gchar **)clist_ascend_xpm);
2396 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
2397 &win_style->bg[GTK_STATE_NORMAL], (gchar **)clist_descend_xpm);
2398 for (i = 0; i < cfile.cinfo.num_cols; i++) {
2399 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
2400 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
2401 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
2402 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
2403 GTK_SHRINK, GTK_SHRINK, 0, 0);
2404 gtk_widget_show(column_lb);
2405 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
2406 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm,
2407 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
2409 gtk_widget_show(col_arrows[i].ascend_pm);
2411 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
2412 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm,
2413 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
2414 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i, col_arrows[i].table);
2415 gtk_widget_show(col_arrows[i].table);
2417 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
2422 set_last_open_dir(char *dirname)
2426 if (last_open_dir) {
2427 g_free(last_open_dir);
2431 len = strlen(dirname);
2432 if (dirname[len-1] != G_DIR_SEPARATOR) {
2433 last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
2438 last_open_dir = NULL;