3 * $Id: main.c,v 1.99 2000/01/25 17:32:52 gram Exp $
5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@zing.org>
7 * Copyright 1998 Gerald Combs
9 * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10 * needed by dissect routines
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 * - Check for end of packet in dissect_* routines.
31 * - Multiple window support
32 * - Add cut/copy/paste
33 * - Create header parsing routines
34 * - Make byte view selections more fancy?
53 #include <sys/types.h>
57 #include <io.h> /* open/close on win32 */
64 #ifdef HAVE_NETINET_IN_H
65 #include <netinet/in.h>
70 #ifdef NEED_SNPRINTF_H
76 # include "snprintf.h"
79 #if defined(HAVE_UCD_SNMP_SNMP_H)
80 #ifdef HAVE_UCD_SNMP_VERSION_H
81 #include <ucd-snmp/version.h>
82 #endif /* HAVE_UCD_SNMP_VERSION_H */
83 #elif defined(HAVE_SNMP_SNMP_H)
84 #ifdef HAVE_SNMP_VERSION_H
85 #include <snmp/version.h>
86 #endif /* HAVE_SNMP_VERSION_H */
89 #ifdef NEED_STRERROR_H
94 #include "timestamp.h"
101 #include "prefs_dlg.h"
107 #include "simple_dialog.h"
108 #include "proto_draw.h"
111 #include "gtkglobals.h"
114 FILE *data_out_file = NULL;
117 GtkWidget *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
118 *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
119 static GtkWidget *bv_vscroll_left, *bv_vscroll_right;
120 GdkFont *m_r_font, *m_b_font;
121 guint main_ctx, file_ctx;
122 gchar comp_info_str[256];
123 gchar *ethereal_path = NULL;
124 gchar *medium_font = MONO_MEDIUM_FONT;
125 gchar *bold_font = MONO_BOLD_FONT;
126 gchar *last_open_dir = NULL;
128 ts_type timestamp_type = RELATIVE;
130 GtkStyle *item_style;
132 /* Specifies the field currently selected in the GUI protocol tree */
133 field_info *finfo_selected = NULL;
135 static void follow_destroy_cb(GtkWidget *win, gpointer data);
136 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
137 static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
138 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
139 static char* hfinfo_numeric_format(header_field_info *hfinfo);
140 static void create_main_window(gint, gint, gint, e_prefs*);
142 /* About Ethereal window */
144 about_ethereal( GtkWidget *w, gpointer data ) {
145 simple_dialog(ESD_TYPE_INFO, NULL,
146 "Ethereal - Network Protocol Analyzer\n"
147 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
148 "Compiled with %s\n\n"
150 "Check the man page for complete documentation and\n"
151 "for the list of contributors.\n"
153 "\nSee http://ethereal.zing.org/ for more information.",
157 /* Follow the TCP stream, if any, to which the last packet that we called
158 a dissection routine on belongs (this might be the most recently
159 selected packet, or it might be the last packet in the file). */
161 follow_stream_cb( GtkWidget *w, gpointer data ) {
162 char filename1[128+1];
163 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
165 GtkWidget *hbox, *close_bt, *print_bt;
166 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
168 gchar *follow_filter;
170 if( pi.ipproto == 6 ) {
171 /* we got tcp so we can follow */
172 /* Create a temporary file into which to dump the reassembled data
173 from the TCP stream, and set "data_out_file" to refer to it, so
174 that the TCP code will write to it.
176 XXX - it might be nicer to just have the TCP code directly
177 append stuff to the text widget for the TCP stream window,
178 if we can arrange that said window not pop up until we're
180 tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
182 simple_dialog(ESD_TYPE_WARN, NULL,
183 "Could not create temporary file %s: %s", filename1, strerror(errno));
186 data_out_file = fdopen( tmp_fd, "w" );
187 if( data_out_file == NULL ) {
188 simple_dialog(ESD_TYPE_WARN, NULL,
189 "Could not create temporary file %s: %s", filename1, strerror(errno));
195 /* Create a new filter that matches all packets in the TCP stream,
196 and set the display filter entry accordingly */
197 reset_tcp_reassembly();
198 follow_filter = build_follow_filter( &pi );
200 /* set the display filter entry accordingly */
201 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
202 gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
204 /* Run the display filter so it goes in effect. */
205 filter_packets(&cf, follow_filter);
207 /* the data_out_file should now be full of the streams information */
208 fclose( data_out_file );
210 /* the filename1 file now has all the text that was in the session */
211 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
212 gtk_widget_set_name( streamwindow, "TCP stream window" );
214 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
215 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
216 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
217 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
219 if( incomplete_tcp_stream ) {
220 gtk_window_set_title( GTK_WINDOW(streamwindow),
221 "Contents of TCP stream (incomplete)" );
223 gtk_window_set_title( GTK_WINDOW(streamwindow),
224 "Contents of TCP stream" );
226 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
227 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
229 /* setup the container */
230 box = gtk_vbox_new( FALSE, 0 );
231 gtk_container_add( GTK_CONTAINER(streamwindow), box );
232 gtk_widget_show( box );
234 /* set up the table we attach to */
235 table = gtk_table_new( 1, 2, FALSE );
236 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
237 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
238 gtk_widget_show( table );
240 /* create a text box */
241 text = gtk_text_new( NULL, NULL );
242 gtk_text_set_editable( GTK_TEXT(text), FALSE);
243 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
244 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
245 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
246 gtk_widget_show(text);
249 hbox = gtk_hbox_new( FALSE, 1 );
250 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
251 gtk_widget_show(hbox);
253 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
254 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
255 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
257 /* Create Radio Buttons */
258 b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
259 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
260 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
261 gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
262 gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
263 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
264 GTK_OBJECT(streamwindow));
265 gtk_widget_show(b_ascii);
267 b_ebcdic = gtk_radio_button_new_with_label(
268 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
270 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
271 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
272 gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
273 gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
274 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
275 GTK_OBJECT(streamwindow));
276 gtk_widget_show(b_ebcdic);
278 b_hexdump = gtk_radio_button_new_with_label(
279 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
281 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
282 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
283 gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
284 gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
285 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
286 GTK_OBJECT(streamwindow));
287 gtk_widget_show(b_hexdump);
289 /* Create Close Button */
290 close_bt = gtk_button_new_with_label("Close");
291 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
292 GTK_SIGNAL_FUNC(gtk_widget_destroy),
293 GTK_OBJECT(streamwindow));
294 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
295 gtk_widget_show( close_bt );
297 /* Create Print Button */
298 print_bt = gtk_button_new_with_label("Print");
299 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
300 GTK_SIGNAL_FUNC(follow_print_stream),
301 GTK_OBJECT(streamwindow));
302 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
303 gtk_widget_show( print_bt );
305 /* create the scrollbar */
306 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
307 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
308 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
309 gtk_widget_show( vscrollbar );
310 gtk_widget_realize( text );
312 /* Tuck away the filename and textbox into streamwindow */
313 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
314 #define E_FOLLOW_TEXT_KEY "follow_text_key"
316 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
317 g_strdup(filename1));
318 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
320 follow_load_text(text, filename1, 0);
322 data_out_file = NULL;
323 gtk_widget_show( streamwindow );
325 simple_dialog(ESD_TYPE_WARN, NULL,
326 "Error following stream. Please make\n"
327 "sure you have a TCP packet selected.");
331 /* The destroy call back has the responsibility of
332 * unlinking the temporary file */
334 follow_destroy_cb(GtkWidget *win, gpointer data)
338 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
339 E_FOLLOW_FILENAME_KEY);
343 gtk_widget_destroy(win);
346 #define E_FOLLOW_ASCII_TYPE 0
347 #define E_FOLLOW_EBCDIC_TYPE 1
348 #define E_FOLLOW_HEXDUMP_TYPE 2
350 /* Handles the ASCII/EBCDIC toggling */
352 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
354 guint8 show_type = E_FOLLOW_ASCII_TYPE;
355 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
358 b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
360 b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
361 E_FOLLOW_EBCDIC_KEY);
362 b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
363 E_FOLLOW_HEXDUMP_KEY);
364 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
366 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
367 E_FOLLOW_FILENAME_KEY);
375 if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
376 show_type = E_FOLLOW_EBCDIC_TYPE;
377 else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
378 show_type = E_FOLLOW_HEXDUMP_TYPE;
380 follow_load_text(text, filename, show_type);
383 #define FLT_BUF_SIZE 1024
385 follow_read_stream(char *filename, guint8 show_type,
386 void (*print_line)(char *, int, gboolean, void *), void *arg)
390 guint32 client_addr = 0;
391 guint16 client_port = 0;
393 guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
396 data_out_file = fopen( filename, "r" );
397 if( data_out_file ) {
398 char buffer[FLT_BUF_SIZE];
400 while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
401 if (client_addr == 0) {
402 client_addr = sc.src_addr;
403 client_port = sc.src_port;
405 if (client_addr == sc.src_addr && client_port == sc.src_port) {
407 global_pos = &global_client_pos;
411 global_pos = &global_server_pos;
414 while (sc.dlen > 0) {
415 bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
416 nchars = fread( buffer, 1, bcount, data_out_file );
421 case E_FOLLOW_EBCDIC_TYPE:
422 /* If our native arch is ASCII, call: */
423 EBCDIC_to_ASCII(buffer, nchars);
424 case E_FOLLOW_ASCII_TYPE:
425 /* If our native arch is EBCDIC, call:
426 * ASCII_TO_EBCDIC(buffer, nchars);
428 (*print_line)( buffer, nchars, is_server, arg );
430 case E_FOLLOW_HEXDUMP_TYPE:
432 while (current_pos < nchars)
435 gchar hexchars[] = "0123456789abcdef";
437 /* is_server indentation : put 63 spaces at the begenning
439 sprintf(hexbuf, is_server ?
442 "%08X ", *global_pos);
443 cur = strlen(hexbuf);
444 for (i=0; i < 16 && current_pos+i < nchars; i++) {
445 hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
446 hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
448 hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
455 hexbuf[cur++] = '\n';
457 (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
463 if( ferror( data_out_file ) ) {
464 simple_dialog(ESD_TYPE_WARN, NULL,
465 "Error reading temporary file %s: %s", filename, strerror(errno));
467 fclose( data_out_file );
469 simple_dialog(ESD_TYPE_WARN, NULL,
470 "Could not open temporary file %s: %s", filename, strerror(errno));
475 * XXX - for text printing, we probably want to wrap lines at 80 characters;
476 * for PostScript printing, we probably want to wrap them at the appropriate
477 * width, and perhaps put some kind of dingbat (to use the technical term)
478 * to indicate a wrapped line, along the lines of what's done when displaying
479 * this in a window, as per Warren Young's suggestion.
481 * For now, we support only text printing.
484 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
488 fwrite(buffer, nchars, 1, fh);
492 follow_print_stream(GtkWidget *w, gpointer parent_w)
498 guint8 show_type = E_FOLLOW_ASCII_TYPE;
501 switch (prefs.pr_dest) {
503 print_dest = prefs.pr_cmd;
508 print_dest = prefs.pr_file;
511 default: /* "Can't happen" */
512 simple_dialog(ESD_TYPE_WARN, NULL,
513 "Couldn't figure out where to send the print "
514 "job. Check your preferences.");
518 fh = open_print_dest(to_file, print_dest);
522 simple_dialog(ESD_TYPE_WARN, NULL,
523 "Couldn't run print command %s.", prefs.pr_cmd);
527 simple_dialog(ESD_TYPE_WARN, NULL,
528 file_write_error_message(errno),
535 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
536 E_FOLLOW_EBCDIC_KEY);
537 if (GTK_TOGGLE_BUTTON(button)->active)
538 show_type = E_FOLLOW_EBCDIC_TYPE;
539 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
540 E_FOLLOW_HEXDUMP_KEY);
541 if (GTK_TOGGLE_BUTTON(button)->active)
542 show_type = E_FOLLOW_HEXDUMP_TYPE;
544 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
545 E_FOLLOW_FILENAME_KEY);
547 if (filename != NULL) {
548 print_preamble(fh, PR_FMT_TEXT);
549 follow_read_stream(filename, show_type, follow_print_text, fh);
550 print_finale(fh, PR_FMT_TEXT);
551 close_print_dest(to_file, fh);
554 simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
559 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
561 GtkWidget *text = arg;
564 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
565 &prefs.st_server_bg, buffer, nchars );
567 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
568 &prefs.st_client_bg, buffer, nchars );
572 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
576 /* Delete any info already in text box */
577 bytes_already = gtk_text_get_length(GTK_TEXT(text));
578 if (bytes_already > 0) {
579 gtk_text_set_point(GTK_TEXT(text), 0);
580 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
583 /* stop the updates while we fill the text box */
584 gtk_text_freeze( GTK_TEXT(text) );
585 follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
586 gtk_text_thaw( GTK_TEXT(text) );
589 /* Match selected byte pattern */
591 match_selected_cb(GtkWidget *w, gpointer data)
594 GtkWidget *filter_te;
595 char *ptr, *format, *stringified;
596 int i, dfilter_len, abbrev_len;
598 header_field_info *hfinfo;
600 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
602 if (!finfo_selected) {
603 simple_dialog(ESD_TYPE_WARN, NULL,
604 "Error determining selected bytes. Please make\n"
605 "sure you have selected a field within the tree\n"
606 "view to be matched.");
610 hfinfo = finfo_selected->hfinfo;
612 abbrev_len = strlen(hfinfo->abbrev);
614 switch(hfinfo->type) {
617 dfilter_len = abbrev_len + 2;
618 buf = g_malloc0(dfilter_len);
619 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
631 dfilter_len = abbrev_len + 20;
632 buf = g_malloc0(dfilter_len);
633 format = hfinfo_numeric_format(hfinfo);
634 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
638 dfilter_len = abbrev_len + 4 + 15 + 1;
639 buf = g_malloc0(dfilter_len);
640 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
641 ipv4_addr_str(&(finfo_selected->value.ipv4)));
645 dfilter_len = abbrev_len + 15;
646 buf = g_malloc0(dfilter_len);
647 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
648 finfo_selected->value.numeric);
652 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
653 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
654 buf = g_malloc0(dfilter_len);
655 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
660 dfilter_len = abbrev_len + 30;
661 buf = g_malloc0(dfilter_len);
662 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
663 finfo_selected->value.floating);
667 dfilter_len = abbrev_len + 22;
668 buf = g_malloc0(dfilter_len);
669 snprintf(buf, dfilter_len, "%s == %s",
671 ether_to_str(finfo_selected->value.ether));
675 case FT_ABSOLUTE_TIME:
676 case FT_RELATIVE_TIME:
677 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
678 sizeof(struct timeval));
682 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
683 fi->value.string = g_strdup(va_arg(ap, char*));
691 c = cf.pd + finfo_selected->start;
692 buf = g_malloc0(32 + finfo_selected->length * 3);
695 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
696 ptr = buf+strlen(buf);
698 if (finfo_selected->length == 1) {
699 sprintf(ptr, "0x%02x", *c++);
702 for (i=0;i<finfo_selected->length; i++) {
704 sprintf(ptr, "%02x", *c++);
707 sprintf(ptr, ":%02x", *c++);
709 ptr = buf+strlen(buf);
715 /* create a new one and set the display filter entry accordingly */
716 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
718 /* Run the display filter so it goes in effect. */
719 filter_packets(&cf, buf);
721 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
725 hfinfo_numeric_format(header_field_info *hfinfo)
729 /* Pick the proper format string */
730 switch(hfinfo->display) {
733 case BASE_OCT: /* I'm lazy */
734 case BASE_BIN: /* I'm lazy */
735 switch(hfinfo->type) {
749 g_assert_not_reached();
754 switch(hfinfo->type) {
756 format = "%s == 0x%02x";
759 format = "%s == 0x%04x";
762 format = "%s == 0x%06x";
765 format = "%s == 0x%08x";
768 g_assert_not_reached();
773 g_assert_not_reached();
780 /* Run the current display filter on the current packet set, and
783 filter_activate_cb(GtkWidget *w, gpointer data)
785 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
786 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
787 GList *li, *nl = NULL;
788 gboolean add_filter = TRUE;
790 char *s = gtk_entry_get_text(GTK_ENTRY(w));
792 /* GtkCombos don't let us get at their list contents easily, so we maintain
793 our own filter list, and feed it to gtk_combo_set_popdown_strings when
794 a new filter is added. */
795 if (filter_packets(&cf, g_strdup(s))) {
796 li = g_list_first(filter_list);
798 if (li->data && strcmp(s, li->data) == 0)
804 filter_list = g_list_append(filter_list, g_strdup(s));
805 li = g_list_first(filter_list);
807 nl = g_list_append(nl, strdup(li->data));
810 gtk_combo_set_popdown_strings(filter_cm, nl);
811 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
816 /* redisplay with no display filter */
818 filter_reset_cb(GtkWidget *w, gpointer data)
820 GtkWidget *filter_te = NULL;
822 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
823 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
826 filter_packets(&cf, NULL);
829 /* What to do when a list item is selected/unselected */
831 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
842 select_packet(&cf, row);
846 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
847 unselect_packet(&cf);
851 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
854 int tree_selected_start = -1;
855 int tree_selected_len = -1;
858 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
861 finfo_selected = finfo;
862 tree_selected_start = finfo->start;
863 tree_selected_len = finfo->length;
865 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
866 tree_selected_start, tree_selected_len, cf.current_frame->encoding);
870 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
872 finfo_selected = NULL;
873 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
874 -1, -1, cf.current_frame->encoding);
877 void collapse_all_cb(GtkWidget *widget, gpointer data) {
878 if (cf.protocol_tree)
879 collapse_all_tree(cf.protocol_tree, tree_view);
882 void expand_all_cb(GtkWidget *widget, gpointer data) {
883 if (cf.protocol_tree)
884 expand_all_tree(cf.protocol_tree, tree_view);
888 set_scrollbar_placement(int pos) /* 0=left, 1=right */
891 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
892 GTK_CORNER_TOP_LEFT );
893 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
894 GTK_CORNER_TOP_LEFT );
895 gtk_widget_hide(bv_vscroll_left);
896 gtk_widget_show(bv_vscroll_right);
899 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
900 GTK_CORNER_TOP_RIGHT );
901 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
902 GTK_CORNER_TOP_RIGHT );
903 gtk_widget_hide(bv_vscroll_right);
904 gtk_widget_show(bv_vscroll_left);
909 set_plist_sel_browse(gboolean val)
912 unselect_packet(&cf);
914 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
915 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
917 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
920 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
925 set_ptree_sel_browse(gboolean val)
927 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
928 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
930 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
933 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
938 set_ptree_line_style(gint style)
940 /* I'm using an assert here since the preferences code limits
941 * the user input, both in the GUI and when reading the preferences file.
942 * If the value is incorrect, it's a program error, not a user-initiated error.
944 g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
945 gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
949 set_ptree_expander_style(gint style)
951 /* I'm using an assert here since the preferences code limits
952 * the user input, both in the GUI and when reading the preferences file.
953 * If the value is incorrect, it's a program error, not a user-initiated error.
955 g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
956 gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
961 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
962 /* If we have a capture file open, and it's a temporary file,
964 if (cf.filename != NULL && cf.is_tempfile)
969 /* call initialization routines at program startup time */
971 ethereal_proto_init(void) {
982 ethereal_proto_cleanup(void) {
990 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
993 fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
995 fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
996 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
997 fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
998 fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1000 fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1002 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1003 fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1004 fprintf(stderr, "\t[ -T <tree view height> ]\n");
1008 /* And now our feature presentation... [ fade to music ] */
1010 main(int argc, char *argv[])
1019 extern char *optarg;
1020 gboolean arg_error = FALSE;
1023 extern char pcap_version[];
1026 int pf_open_errno = 0;
1029 gboolean start_capture = FALSE;
1030 gchar *save_file = NULL;
1032 gchar err_str[PCAP_ERRBUF_SIZE];
1034 gboolean capture_option_specified = FALSE;
1036 gint pl_size = 280, tv_size = 95, bv_size = 75;
1037 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1038 dfilter *rfcode = NULL;
1039 gboolean rfilter_parse_failed = FALSE;
1042 ethereal_path = argv[0];
1045 command_name = get_basename(ethereal_path);
1046 /* Set "capture_child" to indicate whether this is going to be a child
1047 process for a "-S" capture. */
1048 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1051 /* If invoked with the "-G" flag, we dump out a glossary of
1052 display filter symbols.
1054 We must do this before calling "gtk_init()", because "gtk_init()"
1055 tries to open an X display, and we don't want to have to do any X
1056 stuff just to do a build.
1058 Given that we call "gtk_init()" before doing the regular argument
1059 list processing, so that it can handle X and GTK+ arguments and
1060 remove them from the list at which we look, this means we must do
1061 this before doing the regular argument list processing, as well.
1065 you must give the "-G" flag as the first flag on the command line;
1067 you must give it as "-G", nothing more, nothing less;
1069 any arguments after the "-G" flag will not be used. */
1070 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1071 ethereal_proto_init();
1072 proto_registrar_dump();
1076 /* Let GTK get its args */
1077 gtk_init (&argc, &argv);
1079 prefs = read_prefs(&pf_path);
1080 if (pf_path != NULL) {
1081 /* The preferences file exists, but couldn't be opened; "pf_path" is
1082 its pathname. Remember "errno", as that says why the attempt
1084 pf_open_errno = errno;
1087 /* Initialize the capture file struct */
1089 cf.plist_end = NULL;
1093 cf.user_saved = FALSE;
1094 cf.is_tempfile = FALSE;
1099 cf.cfilter = g_strdup(EMPTY_FILTER);
1102 cf.save_file = NULL;
1103 cf.save_file_fd = -1;
1104 cf.snap = WTAP_MAX_PACKET_SIZE;
1106 cf.cinfo.num_cols = prefs->num_cols;
1107 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1108 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1109 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1110 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1111 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1113 /* Assemble the compile-time options */
1114 snprintf(comp_info_str, 256,
1115 #ifdef GTK_MAJOR_VERSION
1116 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1119 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1123 "with libpcap ", pcap_version,
1125 "without libpcap", "",
1130 "with libz ", ZLIB_VERSION,
1131 #else /* ZLIB_VERSION */
1132 "with libz ", "(version unknown)",
1133 #endif /* ZLIB_VERSION */
1134 #else /* HAVE_LIBZ */
1136 #endif /* HAVE_LIBZ */
1138 /* Oh, this is pretty */
1139 #if defined(HAVE_UCD_SNMP_SNMP_H)
1140 #ifdef HAVE_UCD_SNMP_VERSION_H
1141 "with UCD SNMP ", VersionInfo
1142 #else /* HAVE_UCD_SNMP_VERSION_H */
1143 "with UCD SNMP ", "(version unknown)"
1144 #endif /* HAVE_UCD_SNMP_VERSION_H */
1145 #elif defined(HAVE_SNMP_SNMP_H)
1146 #ifdef HAVE_SNMP_VERSION_H
1147 "with CMU SNMP ", snmp_Version()
1148 #else /* HAVE_SNMP_VERSION_H */
1149 "with CMU SNMP ", "(version unknown)"
1150 #endif /* HAVE_SNMP_VERSION_H */
1157 /* Now get our args */
1158 while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1160 case 'b': /* Bold font */
1161 bold_font = g_strdup(optarg);
1163 case 'B': /* Byte view pane height */
1164 bv_size = atoi(optarg);
1166 case 'c': /* Capture xxx packets */
1168 cf.count = atoi(optarg);
1170 capture_option_specified = TRUE;
1174 case 'D': /* Turn off DSCP printing */
1175 g_ip_dscp_actif = FALSE;
1181 cf.cfilter = g_strdup(optarg);
1183 capture_option_specified = TRUE;
1187 case 'h': /* Print help and exit */
1191 case 'i': /* Use interface xxx */
1193 cf.iface = g_strdup(optarg);
1195 capture_option_specified = TRUE;
1199 case 'k': /* Start capture immediately */
1201 start_capture = TRUE;
1203 capture_option_specified = TRUE;
1207 case 'm': /* Medium font */
1208 medium_font = g_strdup(optarg);
1210 case 'n': /* No name resolution */
1211 g_resolving_actif = 0;
1213 case 'P': /* Packet list pane height */
1214 pl_size = atoi(optarg);
1216 case 'Q': /* Quit after capture (just capture to file) */
1219 start_capture = TRUE; /*** -Q implies -k !! ***/
1221 capture_option_specified = TRUE;
1225 case 'r': /* Read capture file xxx */
1226 /* We may set "last_open_dir" to "cf_name", and if we change
1227 "last_open_dir" later, we free the old value, so we have to
1228 set "cf_name" to something that's been allocated. */
1229 cf_name = g_strdup(optarg);
1231 case 'R': /* Read file filter */
1234 case 's': /* Set the snapshot (capture) length */
1236 cf.snap = atoi(optarg);
1238 capture_option_specified = TRUE;
1242 case 'S': /* "Sync" mode: used for following file ala tail -f */
1246 capture_option_specified = TRUE;
1250 case 't': /* Time stamp type */
1251 if (strcmp(optarg, "r") == 0)
1252 timestamp_type = RELATIVE;
1253 else if (strcmp(optarg, "a") == 0)
1254 timestamp_type = ABSOLUTE;
1255 else if (strcmp(optarg, "d") == 0)
1256 timestamp_type = DELTA;
1258 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1260 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1261 fprintf(stderr, "or \"d\" for delta.\n");
1265 case 'T': /* Tree view pane height */
1266 tv_size = atoi(optarg);
1268 case 'v': /* Show version and exit */
1269 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1272 case 'w': /* Write to capture file xxx */
1274 save_file = g_strdup(optarg);
1276 capture_option_specified = TRUE;
1280 case 'W': /* Write to capture file FD xxx */
1282 cf.save_file_fd = atoi(optarg);
1284 capture_option_specified = TRUE;
1289 case '?': /* Bad flag - print usage message */
1296 #ifndef HAVE_LIBPCAP
1297 if (capture_option_specified)
1298 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1305 if (start_capture) {
1306 /* We're supposed to do a live capture; did the user specify an interface
1308 if (cf.iface == NULL) {
1309 /* No - pick the first one from the list of interfaces. */
1310 if_list = get_interface_list(&err, err_str);
1311 if (if_list == NULL) {
1314 case CANT_GET_INTERFACE_LIST:
1315 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1319 case NO_INTERFACES_FOUND:
1320 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1325 cf.iface = g_strdup(if_list->data); /* first interface */
1326 free_interface_list(if_list);
1329 if (capture_child) {
1330 if (cf.save_file_fd == -1) {
1331 /* XXX - send this to the standard output as something our parent
1332 should put in an error message box? */
1333 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1339 /* Build the column format array */
1340 for (i = 0; i < cf.cinfo.num_cols; i++) {
1341 cf.cinfo.col_fmt[i] = get_column_format(i);
1342 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1343 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1345 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1346 if (cf.cinfo.col_fmt[i] == COL_INFO)
1347 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1349 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1353 cf.snap = WTAP_MAX_PACKET_SIZE;
1354 else if (cf.snap < MIN_PACKET_SIZE)
1355 cf.snap = MIN_PACKET_SIZE;
1357 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1358 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1359 gtk_rc_parse(rc_file);
1361 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1362 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1366 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1367 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1371 create_main_window(pl_size, tv_size, bv_size, prefs);
1374 Hmmm should we do it here
1377 ethereal_proto_init(); /* Init anything that needs initializing */
1380 /* Is this a "child" ethereal, which is only supposed to pop up a
1381 capture box to let us stop the capture, and run a capture
1382 to a file that our parent will read? */
1383 if (!capture_child) {
1385 /* No. Pop up the main window, and read in a capture file if
1388 gtk_widget_show(top_level);
1389 set_menus_for_capture_file(FALSE);
1391 cf.colors = colfilter_new();
1393 /* If we were given the name of a capture file, read it in now;
1394 we defer it until now, so that, if we can't open it, and pop
1395 up an alert box, the alert box is more likely to come up on
1396 top of the main window - but before the preference-file-error
1397 alert box, so, if we get one of those, it's more likely to come
1400 if (rfilter != NULL) {
1401 if (dfilter_compile(rfilter, &rfcode) != 0) {
1402 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1403 rfilter_parse_failed = TRUE;
1406 if (!rfilter_parse_failed) {
1407 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1408 /* "open_cap_file()" succeeded, so it closed the previous
1409 capture file, and thus destroyed any previous read filter
1410 attached to "cf". */
1412 err = read_cap_file(&cf);
1413 /* Save the name of the containing directory specified in the
1414 path name, if any; we can write over cf_name, which is a
1415 good thing, given that "get_dirname()" does write over its
1417 s = get_dirname(cf_name);
1421 dfilter_destroy(rfcode);
1430 /* If we failed to open the preferences file, pop up an alert box;
1431 we defer it until now, so that the alert box is more likely to
1432 come up on top of the main window. */
1433 if (pf_path != NULL) {
1434 simple_dialog(ESD_TYPE_WARN, NULL,
1435 "Could not open preferences file\n\"%s\": %s.", pf_path,
1436 strerror(pf_open_errno));
1440 if (capture_child) {
1441 /* This is the child process for a sync mode or fork mode capture,
1442 so just do the low-level work of a capture - don't create
1443 a temporary file and fork off *another* child process (so don't
1444 call "do_capture()"). */
1448 /* The capture is done; there's nothing more for us to do. */
1451 if (start_capture) {
1452 /* "-k" was specified; start a capture. */
1453 do_capture(save_file);
1456 set_menus_for_capture_in_progress(FALSE);
1463 ethereal_proto_cleanup();
1470 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1472 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1473 *bv_table, *stat_hbox,
1474 *filter_bt, *filter_cm, *filter_te,
1476 GList *filter_list = NULL;
1478 GtkAccelGroup *accel;
1482 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1483 gtk_widget_set_name(top_level, "main window");
1484 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1485 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1486 gtk_signal_connect(GTK_OBJECT(top_level), "destroy",
1487 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1488 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1489 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1490 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1492 /* Container for menu bar, paned windows and progress/info box */
1493 main_vbox = gtk_vbox_new(FALSE, 1);
1494 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1495 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1496 gtk_widget_show(main_vbox);
1499 get_main_menu(&menubar, &accel);
1500 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1501 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1502 gtk_widget_show(menubar);
1504 /* Panes for the packet list, tree, and byte view */
1505 u_pane = gtk_vpaned_new();
1506 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1507 l_pane = gtk_vpaned_new();
1508 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1509 gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
1510 gtk_widget_show(u_pane);
1511 gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
1512 gtk_widget_show(l_pane);
1515 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1516 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1517 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1518 gtk_widget_show(pkt_scrollw);
1519 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1521 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1522 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1523 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1524 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1525 pl_style = gtk_style_new();
1526 gdk_font_unref(pl_style->font);
1527 pl_style->font = m_r_font;
1528 gtk_widget_set_style(packet_list, pl_style);
1529 gtk_widget_set_name(packet_list, "packet list");
1530 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1531 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1532 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1533 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1534 for (i = 0; i < cf.cinfo.num_cols; i++) {
1535 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1536 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1538 /* Right-justify the packet number column. */
1539 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1540 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1543 /* Save static column sizes to use during a "-S" capture, so that
1544 the columns don't resize during a live capture. */
1545 cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1546 get_column_longest_string(get_column_format(i)));
1548 gtk_widget_set_usize(packet_list, -1, pl_size);
1549 gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1550 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1551 gtk_widget_show(packet_list);
1554 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1555 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1556 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1557 gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
1558 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1559 gtk_widget_show(tv_scrollw);
1561 tree_view = gtk_ctree_new(1, 0);
1562 /* I need this next line to make the widget work correctly with hidden
1563 * column titles and GTK_SELECTION_BROWSE */
1564 gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1565 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1566 set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
1567 set_ptree_line_style(prefs->gui_ptree_line_style);
1568 set_ptree_expander_style(prefs->gui_ptree_expander_style);
1570 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1571 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1572 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1573 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1574 gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1575 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1576 gtk_widget_show(tree_view);
1578 item_style = gtk_style_new();
1579 gdk_font_unref(item_style->font);
1580 item_style->font = m_r_font;
1582 /* Byte view. The table is only one row high, but 3 columns
1583 * wide. The middle column contains the GtkText with the hex dump.
1584 * The left and right columns contain vertical scrollbars. They both
1585 * do the same thing, but only one will be shown at a time, in accordance
1586 * with where the user wants the other vertical scrollbars places
1587 * (on the left or the right).
1589 bv_table = gtk_table_new (1, 3, FALSE);
1590 gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
1591 gtk_widget_set_usize(bv_table, -1, bv_size);
1592 gtk_widget_show(bv_table);
1594 byte_view = gtk_text_new(NULL, NULL);
1595 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1596 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1597 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
1598 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1599 gtk_widget_show(byte_view);
1601 /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
1602 * in the GTK+ distribution, so I removed the horizontal scroll bar
1603 * that used to be here. I tried the gtk_text widget with a
1604 * gtk_scrolled_window w/ viewport, but the vertical scrollowing
1605 * did not work well, and sometimes a few pixels were cut off on
1608 bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1609 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
1610 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1612 bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1613 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
1614 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1616 /* Now that the 3 panes are created, set the vertical scrollbar
1617 * on the left or right according to the user's preference */
1618 set_scrollbar_placement(prefs->gui_scrollbar_on_right);
1620 /* Progress/filter/info box */
1621 stat_hbox = gtk_hbox_new(FALSE, 1);
1622 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1623 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1624 gtk_widget_show(stat_hbox);
1626 prog_bar = gtk_progress_bar_new();
1627 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1628 gtk_widget_show(prog_bar);
1630 filter_bt = gtk_button_new_with_label("Filter:");
1631 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1632 GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
1633 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1634 gtk_widget_show(filter_bt);
1636 filter_cm = gtk_combo_new();
1637 filter_list = g_list_append (filter_list, "");
1638 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1639 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1640 filter_te = GTK_COMBO(filter_cm)->entry;
1641 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1642 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1643 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1644 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1645 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1646 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1647 gtk_widget_show(filter_cm);
1649 filter_reset = gtk_button_new_with_label("Reset");
1650 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1651 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1652 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1653 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1654 gtk_widget_show(filter_reset);
1656 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1657 * of any widget that ends up calling a callback which needs
1658 * that text entry pointer */
1659 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1660 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1661 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1662 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1663 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1665 info_bar = gtk_statusbar_new();
1666 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1667 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1668 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1669 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1670 gtk_widget_show(info_bar);