3 * $Id: main.c,v 1.105 2000/02/13 10:36:06 guy 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 "filter_prefs.h"
102 #include "prefs_dlg.h"
108 #include "simple_dialog.h"
109 #include "proto_draw.h"
112 #include "gtkglobals.h"
115 FILE *data_out_file = NULL;
118 GtkWidget *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
119 *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
120 static GtkWidget *bv_vscroll_left, *bv_vscroll_right;
121 GdkFont *m_r_font, *m_b_font;
122 guint main_ctx, file_ctx;
123 gchar comp_info_str[256];
124 gchar *ethereal_path = NULL;
125 gchar *medium_font = MONO_MEDIUM_FONT;
126 gchar *bold_font = MONO_BOLD_FONT;
127 gchar *last_open_dir = NULL;
129 ts_type timestamp_type = RELATIVE;
131 GtkStyle *item_style;
133 /* Specifies the field currently selected in the GUI protocol tree */
134 field_info *finfo_selected = NULL;
136 static void follow_destroy_cb(GtkWidget *win, gpointer data);
137 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
138 static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
139 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
140 static char* hfinfo_numeric_format(header_field_info *hfinfo);
141 static void create_main_window(gint, gint, gint, e_prefs*);
143 /* About Ethereal window */
145 about_ethereal( GtkWidget *w, gpointer data ) {
146 simple_dialog(ESD_TYPE_INFO, NULL,
147 "Ethereal - Network Protocol Analyzer\n"
148 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
149 "Compiled with %s\n\n"
151 "Check the man page for complete documentation and\n"
152 "for the list of contributors.\n"
154 "\nSee http://ethereal.zing.org/ for more information.",
158 /* Follow the TCP stream, if any, to which the last packet that we called
159 a dissection routine on belongs (this might be the most recently
160 selected packet, or it might be the last packet in the file). */
162 follow_stream_cb( GtkWidget *w, gpointer data ) {
163 char filename1[128+1];
164 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
166 GtkWidget *hbox, *close_bt, *print_bt;
167 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
169 gchar *follow_filter;
171 if( pi.ipproto == 6 ) {
172 /* we got tcp so we can follow */
173 /* Create a temporary file into which to dump the reassembled data
174 from the TCP stream, and set "data_out_file" to refer to it, so
175 that the TCP code will write to it.
177 XXX - it might be nicer to just have the TCP code directly
178 append stuff to the text widget for the TCP stream window,
179 if we can arrange that said window not pop up until we're
181 tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
183 simple_dialog(ESD_TYPE_WARN, NULL,
184 "Could not create temporary file %s: %s", filename1, strerror(errno));
187 data_out_file = fdopen( tmp_fd, "w" );
188 if( data_out_file == NULL ) {
189 simple_dialog(ESD_TYPE_WARN, NULL,
190 "Could not create temporary file %s: %s", filename1, strerror(errno));
196 /* Create a new filter that matches all packets in the TCP stream,
197 and set the display filter entry accordingly */
198 reset_tcp_reassembly();
199 follow_filter = build_follow_filter( &pi );
201 /* set the display filter entry accordingly */
202 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
203 gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
205 /* Run the display filter so it goes in effect. */
206 filter_packets(&cf, follow_filter);
208 /* the data_out_file should now be full of the streams information */
209 fclose( data_out_file );
211 /* the filename1 file now has all the text that was in the session */
212 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
213 gtk_widget_set_name( streamwindow, "TCP stream window" );
215 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
216 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
217 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
218 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
220 if( incomplete_tcp_stream ) {
221 gtk_window_set_title( GTK_WINDOW(streamwindow),
222 "Contents of TCP stream (incomplete)" );
224 gtk_window_set_title( GTK_WINDOW(streamwindow),
225 "Contents of TCP stream" );
227 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
228 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
230 /* setup the container */
231 box = gtk_vbox_new( FALSE, 0 );
232 gtk_container_add( GTK_CONTAINER(streamwindow), box );
233 gtk_widget_show( box );
235 /* set up the table we attach to */
236 table = gtk_table_new( 1, 2, FALSE );
237 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
238 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
239 gtk_widget_show( table );
241 /* create a text box */
242 text = gtk_text_new( NULL, NULL );
243 gtk_text_set_editable( GTK_TEXT(text), FALSE);
244 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
245 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
246 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
247 gtk_widget_show(text);
250 hbox = gtk_hbox_new( FALSE, 1 );
251 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
252 gtk_widget_show(hbox);
254 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
255 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
256 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
258 /* Create Radio Buttons */
259 b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
260 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
261 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
262 gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
263 gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
264 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
265 GTK_OBJECT(streamwindow));
266 gtk_widget_show(b_ascii);
268 b_ebcdic = gtk_radio_button_new_with_label(
269 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
271 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
272 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
273 gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
274 gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
275 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
276 GTK_OBJECT(streamwindow));
277 gtk_widget_show(b_ebcdic);
279 b_hexdump = gtk_radio_button_new_with_label(
280 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
282 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
283 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
284 gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
285 gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
286 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
287 GTK_OBJECT(streamwindow));
288 gtk_widget_show(b_hexdump);
290 /* Create Close Button */
291 close_bt = gtk_button_new_with_label("Close");
292 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
293 GTK_SIGNAL_FUNC(gtk_widget_destroy),
294 GTK_OBJECT(streamwindow));
295 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
296 gtk_widget_show( close_bt );
298 /* Create Print Button */
299 print_bt = gtk_button_new_with_label("Print");
300 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
301 GTK_SIGNAL_FUNC(follow_print_stream),
302 GTK_OBJECT(streamwindow));
303 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
304 gtk_widget_show( print_bt );
306 /* create the scrollbar */
307 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
308 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
309 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
310 gtk_widget_show( vscrollbar );
311 gtk_widget_realize( text );
313 /* Tuck away the filename and textbox into streamwindow */
314 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
315 #define E_FOLLOW_TEXT_KEY "follow_text_key"
317 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
318 g_strdup(filename1));
319 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
321 follow_load_text(text, filename1, 0);
323 data_out_file = NULL;
324 gtk_widget_show( streamwindow );
326 simple_dialog(ESD_TYPE_WARN, NULL,
327 "Error following stream. Please make\n"
328 "sure you have a TCP packet selected.");
332 /* The destroy call back has the responsibility of
333 * unlinking the temporary file */
335 follow_destroy_cb(GtkWidget *win, gpointer data)
339 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
340 E_FOLLOW_FILENAME_KEY);
344 gtk_widget_destroy(win);
347 #define E_FOLLOW_ASCII_TYPE 0
348 #define E_FOLLOW_EBCDIC_TYPE 1
349 #define E_FOLLOW_HEXDUMP_TYPE 2
351 /* Handles the ASCII/EBCDIC toggling */
353 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
355 guint8 show_type = E_FOLLOW_ASCII_TYPE;
356 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
359 b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
361 b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
362 E_FOLLOW_EBCDIC_KEY);
363 b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
364 E_FOLLOW_HEXDUMP_KEY);
365 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
367 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
368 E_FOLLOW_FILENAME_KEY);
376 if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
377 show_type = E_FOLLOW_EBCDIC_TYPE;
378 else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
379 show_type = E_FOLLOW_HEXDUMP_TYPE;
381 follow_load_text(text, filename, show_type);
384 #define FLT_BUF_SIZE 1024
386 follow_read_stream(char *filename, guint8 show_type,
387 void (*print_line)(char *, int, gboolean, void *), void *arg)
391 guint32 client_addr = 0;
392 guint16 client_port = 0;
394 guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
397 data_out_file = fopen( filename, "r" );
398 if( data_out_file ) {
399 char buffer[FLT_BUF_SIZE];
401 while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
402 if (client_addr == 0) {
403 client_addr = sc.src_addr;
404 client_port = sc.src_port;
406 if (client_addr == sc.src_addr && client_port == sc.src_port) {
408 global_pos = &global_client_pos;
412 global_pos = &global_server_pos;
415 while (sc.dlen > 0) {
416 bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
417 nchars = fread( buffer, 1, bcount, data_out_file );
422 case E_FOLLOW_EBCDIC_TYPE:
423 /* If our native arch is ASCII, call: */
424 EBCDIC_to_ASCII(buffer, nchars);
425 case E_FOLLOW_ASCII_TYPE:
426 /* If our native arch is EBCDIC, call:
427 * ASCII_TO_EBCDIC(buffer, nchars);
429 (*print_line)( buffer, nchars, is_server, arg );
431 case E_FOLLOW_HEXDUMP_TYPE:
433 while (current_pos < nchars)
436 gchar hexchars[] = "0123456789abcdef";
438 /* is_server indentation : put 63 spaces at the begenning
440 sprintf(hexbuf, is_server ?
443 "%08X ", *global_pos);
444 cur = strlen(hexbuf);
445 for (i=0; i < 16 && current_pos+i < nchars; i++) {
446 hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
447 hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
449 hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
456 hexbuf[cur++] = '\n';
458 (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
464 if( ferror( data_out_file ) ) {
465 simple_dialog(ESD_TYPE_WARN, NULL,
466 "Error reading temporary file %s: %s", filename, strerror(errno));
468 fclose( data_out_file );
469 data_out_file = NULL;
471 simple_dialog(ESD_TYPE_WARN, NULL,
472 "Could not open temporary file %s: %s", filename, strerror(errno));
477 * XXX - for text printing, we probably want to wrap lines at 80 characters;
478 * for PostScript printing, we probably want to wrap them at the appropriate
479 * width, and perhaps put some kind of dingbat (to use the technical term)
480 * to indicate a wrapped line, along the lines of what's done when displaying
481 * this in a window, as per Warren Young's suggestion.
483 * For now, we support only text printing.
486 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
490 fwrite(buffer, nchars, 1, fh);
494 follow_print_stream(GtkWidget *w, gpointer parent_w)
500 guint8 show_type = E_FOLLOW_ASCII_TYPE;
503 switch (prefs.pr_dest) {
505 print_dest = prefs.pr_cmd;
510 print_dest = prefs.pr_file;
513 default: /* "Can't happen" */
514 simple_dialog(ESD_TYPE_WARN, NULL,
515 "Couldn't figure out where to send the print "
516 "job. Check your preferences.");
520 fh = open_print_dest(to_file, print_dest);
524 simple_dialog(ESD_TYPE_WARN, NULL,
525 "Couldn't run print command %s.", prefs.pr_cmd);
529 simple_dialog(ESD_TYPE_WARN, NULL,
530 file_write_error_message(errno),
537 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
538 E_FOLLOW_EBCDIC_KEY);
539 if (GTK_TOGGLE_BUTTON(button)->active)
540 show_type = E_FOLLOW_EBCDIC_TYPE;
541 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
542 E_FOLLOW_HEXDUMP_KEY);
543 if (GTK_TOGGLE_BUTTON(button)->active)
544 show_type = E_FOLLOW_HEXDUMP_TYPE;
546 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
547 E_FOLLOW_FILENAME_KEY);
549 if (filename != NULL) {
550 print_preamble(fh, PR_FMT_TEXT);
551 follow_read_stream(filename, show_type, follow_print_text, fh);
552 print_finale(fh, PR_FMT_TEXT);
553 close_print_dest(to_file, fh);
556 simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
561 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
563 GtkWidget *text = arg;
566 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
567 &prefs.st_server_bg, buffer, nchars );
569 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
570 &prefs.st_client_bg, buffer, nchars );
574 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
578 /* Delete any info already in text box */
579 bytes_already = gtk_text_get_length(GTK_TEXT(text));
580 if (bytes_already > 0) {
581 gtk_text_set_point(GTK_TEXT(text), 0);
582 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
585 /* stop the updates while we fill the text box */
586 gtk_text_freeze( GTK_TEXT(text) );
587 follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
588 gtk_text_thaw( GTK_TEXT(text) );
591 /* Match selected byte pattern */
593 match_selected_cb(GtkWidget *w, gpointer data)
596 GtkWidget *filter_te;
597 char *ptr, *format, *stringified;
598 int i, dfilter_len, abbrev_len;
600 header_field_info *hfinfo;
602 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
604 if (!finfo_selected) {
605 simple_dialog(ESD_TYPE_WARN, NULL,
606 "Error determining selected bytes. Please make\n"
607 "sure you have selected a field within the tree\n"
608 "view to be matched.");
612 hfinfo = finfo_selected->hfinfo;
614 abbrev_len = strlen(hfinfo->abbrev);
616 switch(hfinfo->type) {
619 dfilter_len = abbrev_len + 2;
620 buf = g_malloc0(dfilter_len);
621 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
633 dfilter_len = abbrev_len + 20;
634 buf = g_malloc0(dfilter_len);
635 format = hfinfo_numeric_format(hfinfo);
636 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
640 dfilter_len = abbrev_len + 4 + 15 + 1;
641 buf = g_malloc0(dfilter_len);
642 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
643 ipv4_addr_str(&(finfo_selected->value.ipv4)));
647 dfilter_len = abbrev_len + 15;
648 buf = g_malloc0(dfilter_len);
649 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
650 finfo_selected->value.numeric);
654 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
655 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
656 buf = g_malloc0(dfilter_len);
657 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
662 dfilter_len = abbrev_len + 30;
663 buf = g_malloc0(dfilter_len);
664 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
665 finfo_selected->value.floating);
669 dfilter_len = abbrev_len + 22;
670 buf = g_malloc0(dfilter_len);
671 snprintf(buf, dfilter_len, "%s == %s",
673 ether_to_str(finfo_selected->value.ether));
677 case FT_ABSOLUTE_TIME:
678 case FT_RELATIVE_TIME:
679 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
680 sizeof(struct timeval));
684 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
685 fi->value.string = g_strdup(va_arg(ap, char*));
693 c = cf.pd + finfo_selected->start;
694 buf = g_malloc0(32 + finfo_selected->length * 3);
697 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
698 ptr = buf+strlen(buf);
700 if (finfo_selected->length == 1) {
701 sprintf(ptr, "0x%02x", *c++);
704 for (i=0;i<finfo_selected->length; i++) {
706 sprintf(ptr, "%02x", *c++);
709 sprintf(ptr, ":%02x", *c++);
711 ptr = buf+strlen(buf);
717 /* create a new one and set the display filter entry accordingly */
718 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
720 /* Run the display filter so it goes in effect. */
721 filter_packets(&cf, buf);
723 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
727 hfinfo_numeric_format(header_field_info *hfinfo)
731 /* Pick the proper format string */
732 switch(hfinfo->display) {
735 case BASE_OCT: /* I'm lazy */
736 case BASE_BIN: /* I'm lazy */
737 switch(hfinfo->type) {
751 g_assert_not_reached();
756 switch(hfinfo->type) {
758 format = "%s == 0x%02x";
761 format = "%s == 0x%04x";
764 format = "%s == 0x%06x";
767 format = "%s == 0x%08x";
770 g_assert_not_reached();
775 g_assert_not_reached();
782 /* Run the current display filter on the current packet set, and
785 filter_activate_cb(GtkWidget *w, gpointer data)
787 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
788 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
789 GList *li, *nl = NULL;
790 gboolean add_filter = TRUE;
792 char *s = gtk_entry_get_text(GTK_ENTRY(w));
794 /* GtkCombos don't let us get at their list contents easily, so we maintain
795 our own filter list, and feed it to gtk_combo_set_popdown_strings when
796 a new filter is added. */
797 if (filter_packets(&cf, g_strdup(s))) {
798 li = g_list_first(filter_list);
800 if (li->data && strcmp(s, li->data) == 0)
806 filter_list = g_list_append(filter_list, g_strdup(s));
807 li = g_list_first(filter_list);
809 nl = g_list_append(nl, strdup(li->data));
812 gtk_combo_set_popdown_strings(filter_cm, nl);
813 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
818 /* redisplay with no display filter */
820 filter_reset_cb(GtkWidget *w, gpointer data)
822 GtkWidget *filter_te = NULL;
824 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
825 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
828 filter_packets(&cf, NULL);
831 /* What to do when a list item is selected/unselected */
833 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
844 select_packet(&cf, row);
848 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
849 unselect_packet(&cf);
853 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
856 int tree_selected_start = -1;
857 int tree_selected_len = -1;
860 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
863 finfo_selected = finfo;
864 tree_selected_start = finfo->start;
865 tree_selected_len = finfo->length;
867 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
868 tree_selected_start, tree_selected_len, cf.current_frame->encoding);
872 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
874 finfo_selected = NULL;
875 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
876 -1, -1, cf.current_frame->encoding);
879 void collapse_all_cb(GtkWidget *widget, gpointer data) {
880 if (cf.protocol_tree)
881 collapse_all_tree(cf.protocol_tree, tree_view);
884 void expand_all_cb(GtkWidget *widget, gpointer data) {
885 if (cf.protocol_tree)
886 expand_all_tree(cf.protocol_tree, tree_view);
890 set_scrollbar_placement(int pos) /* 0=left, 1=right */
893 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
894 GTK_CORNER_TOP_LEFT );
895 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
896 GTK_CORNER_TOP_LEFT );
897 gtk_widget_hide(bv_vscroll_left);
898 gtk_widget_show(bv_vscroll_right);
901 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
902 GTK_CORNER_TOP_RIGHT );
903 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
904 GTK_CORNER_TOP_RIGHT );
905 gtk_widget_hide(bv_vscroll_right);
906 gtk_widget_show(bv_vscroll_left);
911 set_plist_sel_browse(gboolean val)
914 unselect_packet(&cf);
916 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
917 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
919 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
922 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
927 set_ptree_sel_browse(gboolean val)
929 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
930 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
932 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
935 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
940 set_ptree_line_style(gint style)
942 /* I'm using an assert here since the preferences code limits
943 * the user input, both in the GUI and when reading the preferences file.
944 * If the value is incorrect, it's a program error, not a user-initiated error.
946 g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
947 gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
951 set_ptree_expander_style(gint style)
953 /* I'm using an assert here since the preferences code limits
954 * the user input, both in the GUI and when reading the preferences file.
955 * If the value is incorrect, it's a program error, not a user-initiated error.
957 g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
958 gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
963 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
965 /* Close any capture file we have open; on some OSes, you can't
966 unlink a temporary capture file if you have it open.
967 "close_cap_file()" will unlink it after closing it if
968 it's a temporary file. */
969 close_cap_file(&cf, info_bar);
973 /* call initialization routines at program startup time */
975 ethereal_proto_init(void) {
986 ethereal_proto_cleanup(void) {
994 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
997 fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
999 fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1000 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1001 fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1002 fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1004 fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1006 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1007 fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1008 fprintf(stderr, "\t[ -T <tree view height> ]\n");
1012 /* And now our feature presentation... [ fade to music ] */
1014 main(int argc, char *argv[])
1023 extern char *optarg;
1024 gboolean arg_error = FALSE;
1028 char pcap_version[] = "0.4a6";
1030 extern char pcap_version[];
1034 int pf_open_errno = 0;
1037 gboolean start_capture = FALSE;
1038 gchar *save_file = NULL;
1040 gchar err_str[PCAP_ERRBUF_SIZE];
1042 gboolean capture_option_specified = FALSE;
1044 gint pl_size = 280, tv_size = 95, bv_size = 75;
1045 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1046 dfilter *rfcode = NULL;
1047 gboolean rfilter_parse_failed = FALSE;
1050 ethereal_path = argv[0];
1053 command_name = get_basename(ethereal_path);
1054 /* Set "capture_child" to indicate whether this is going to be a child
1055 process for a "-S" capture. */
1056 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1059 /* If invoked with the "-G" flag, we dump out a glossary of
1060 display filter symbols.
1062 We must do this before calling "gtk_init()", because "gtk_init()"
1063 tries to open an X display, and we don't want to have to do any X
1064 stuff just to do a build.
1066 Given that we call "gtk_init()" before doing the regular argument
1067 list processing, so that it can handle X and GTK+ arguments and
1068 remove them from the list at which we look, this means we must do
1069 this before doing the regular argument list processing, as well.
1073 you must give the "-G" flag as the first flag on the command line;
1075 you must give it as "-G", nothing more, nothing less;
1077 any arguments after the "-G" flag will not be used. */
1078 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1079 ethereal_proto_init();
1080 proto_registrar_dump();
1084 /* Let GTK get its args */
1085 gtk_init (&argc, &argv);
1087 prefs = read_prefs(&pf_path);
1088 if (pf_path != NULL) {
1089 /* The preferences file exists, but couldn't be opened; "pf_path" is
1090 its pathname. Remember "errno", as that says why the attempt
1092 pf_open_errno = errno;
1095 /* Initialize the capture file struct */
1097 cf.plist_end = NULL;
1101 cf.user_saved = FALSE;
1102 cf.is_tempfile = FALSE;
1107 cf.cfilter = g_strdup(EMPTY_FILTER);
1110 cf.save_file = NULL;
1111 cf.save_file_fd = -1;
1112 cf.snap = WTAP_MAX_PACKET_SIZE;
1114 cf.cinfo.num_cols = prefs->num_cols;
1115 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1116 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1117 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1118 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1119 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1121 /* Assemble the compile-time options */
1122 snprintf(comp_info_str, 256,
1123 #ifdef GTK_MAJOR_VERSION
1124 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1127 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1131 "with libpcap ", pcap_version,
1133 "without libpcap", "",
1138 "with libz ", ZLIB_VERSION,
1139 #else /* ZLIB_VERSION */
1140 "with libz ", "(version unknown)",
1141 #endif /* ZLIB_VERSION */
1142 #else /* HAVE_LIBZ */
1144 #endif /* HAVE_LIBZ */
1146 /* Oh, this is pretty */
1147 #if defined(HAVE_UCD_SNMP_SNMP_H)
1148 #ifdef HAVE_UCD_SNMP_VERSION_H
1149 "with UCD SNMP ", VersionInfo
1150 #else /* HAVE_UCD_SNMP_VERSION_H */
1151 "with UCD SNMP ", "(version unknown)"
1152 #endif /* HAVE_UCD_SNMP_VERSION_H */
1153 #elif defined(HAVE_SNMP_SNMP_H)
1154 #ifdef HAVE_SNMP_VERSION_H
1155 "with CMU SNMP ", snmp_Version()
1156 #else /* HAVE_SNMP_VERSION_H */
1157 "with CMU SNMP ", "(version unknown)"
1158 #endif /* HAVE_SNMP_VERSION_H */
1165 /* Now get our args */
1166 while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1168 case 'b': /* Bold font */
1169 bold_font = g_strdup(optarg);
1171 case 'B': /* Byte view pane height */
1172 bv_size = atoi(optarg);
1174 case 'c': /* Capture xxx packets */
1176 cf.count = atoi(optarg);
1178 capture_option_specified = TRUE;
1182 case 'D': /* Turn off DSCP printing */
1183 g_ip_dscp_actif = FALSE;
1189 cf.cfilter = g_strdup(optarg);
1191 capture_option_specified = TRUE;
1195 case 'h': /* Print help and exit */
1199 case 'i': /* Use interface xxx */
1201 cf.iface = g_strdup(optarg);
1203 capture_option_specified = TRUE;
1207 case 'k': /* Start capture immediately */
1209 start_capture = TRUE;
1211 capture_option_specified = TRUE;
1215 case 'm': /* Medium font */
1216 medium_font = g_strdup(optarg);
1218 case 'n': /* No name resolution */
1219 g_resolving_actif = 0;
1221 case 'P': /* Packet list pane height */
1222 pl_size = atoi(optarg);
1224 case 'Q': /* Quit after capture (just capture to file) */
1227 start_capture = TRUE; /*** -Q implies -k !! ***/
1229 capture_option_specified = TRUE;
1233 case 'r': /* Read capture file xxx */
1234 /* We may set "last_open_dir" to "cf_name", and if we change
1235 "last_open_dir" later, we free the old value, so we have to
1236 set "cf_name" to something that's been allocated. */
1237 cf_name = g_strdup(optarg);
1239 case 'R': /* Read file filter */
1242 case 's': /* Set the snapshot (capture) length */
1244 cf.snap = atoi(optarg);
1246 capture_option_specified = TRUE;
1250 case 'S': /* "Sync" mode: used for following file ala tail -f */
1254 capture_option_specified = TRUE;
1258 case 't': /* Time stamp type */
1259 if (strcmp(optarg, "r") == 0)
1260 timestamp_type = RELATIVE;
1261 else if (strcmp(optarg, "a") == 0)
1262 timestamp_type = ABSOLUTE;
1263 else if (strcmp(optarg, "d") == 0)
1264 timestamp_type = DELTA;
1266 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1268 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1269 fprintf(stderr, "or \"d\" for delta.\n");
1273 case 'T': /* Tree view pane height */
1274 tv_size = atoi(optarg);
1276 case 'v': /* Show version and exit */
1277 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1280 case 'w': /* Write to capture file xxx */
1282 save_file = g_strdup(optarg);
1284 capture_option_specified = TRUE;
1288 case 'W': /* Write to capture file FD xxx */
1290 cf.save_file_fd = atoi(optarg);
1292 capture_option_specified = TRUE;
1297 case '?': /* Bad flag - print usage message */
1304 #ifndef HAVE_LIBPCAP
1305 if (capture_option_specified)
1306 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1313 if (start_capture) {
1314 /* We're supposed to do a live capture; did the user specify an interface
1316 if (cf.iface == NULL) {
1317 /* No - pick the first one from the list of interfaces. */
1318 if_list = get_interface_list(&err, err_str);
1319 if (if_list == NULL) {
1322 case CANT_GET_INTERFACE_LIST:
1323 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1327 case NO_INTERFACES_FOUND:
1328 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1333 cf.iface = g_strdup(if_list->data); /* first interface */
1334 free_interface_list(if_list);
1337 if (capture_child) {
1338 if (cf.save_file_fd == -1) {
1339 /* XXX - send this to the standard output as something our parent
1340 should put in an error message box? */
1341 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1347 /* Build the column format array */
1348 for (i = 0; i < cf.cinfo.num_cols; i++) {
1349 cf.cinfo.col_fmt[i] = get_column_format(i);
1350 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1351 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1353 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1354 if (cf.cinfo.col_fmt[i] == COL_INFO)
1355 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1357 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1361 cf.snap = WTAP_MAX_PACKET_SIZE;
1362 else if (cf.snap < MIN_PACKET_SIZE)
1363 cf.snap = MIN_PACKET_SIZE;
1365 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1366 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1367 gtk_rc_parse(rc_file);
1369 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1370 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1374 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1375 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1379 create_main_window(pl_size, tv_size, bv_size, prefs);
1382 Hmmm should we do it here
1385 ethereal_proto_init(); /* Init anything that needs initializing */
1388 /* Is this a "child" ethereal, which is only supposed to pop up a
1389 capture box to let us stop the capture, and run a capture
1390 to a file that our parent will read? */
1391 if (!capture_child) {
1393 /* No. Pop up the main window, and read in a capture file if
1396 gtk_widget_show(top_level);
1397 set_menus_for_capture_file(FALSE);
1399 cf.colors = colfilter_new();
1401 /* If we were given the name of a capture file, read it in now;
1402 we defer it until now, so that, if we can't open it, and pop
1403 up an alert box, the alert box is more likely to come up on
1404 top of the main window - but before the preference-file-error
1405 alert box, so, if we get one of those, it's more likely to come
1408 if (rfilter != NULL) {
1409 if (dfilter_compile(rfilter, &rfcode) != 0) {
1410 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1411 rfilter_parse_failed = TRUE;
1414 if (!rfilter_parse_failed) {
1415 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1416 /* "open_cap_file()" succeeded, so it closed the previous
1417 capture file, and thus destroyed any previous read filter
1418 attached to "cf". */
1420 err = read_cap_file(&cf);
1421 /* Save the name of the containing directory specified in the
1422 path name, if any; we can write over cf_name, which is a
1423 good thing, given that "get_dirname()" does write over its
1425 s = get_dirname(cf_name);
1429 dfilter_destroy(rfcode);
1438 /* If we failed to open the preferences file, pop up an alert box;
1439 we defer it until now, so that the alert box is more likely to
1440 come up on top of the main window. */
1441 if (pf_path != NULL) {
1442 simple_dialog(ESD_TYPE_WARN, NULL,
1443 "Could not open preferences file\n\"%s\": %s.", pf_path,
1444 strerror(pf_open_errno));
1448 if (capture_child) {
1449 /* This is the child process for a sync mode or fork mode capture,
1450 so just do the low-level work of a capture - don't create
1451 a temporary file and fork off *another* child process (so don't
1452 call "do_capture()"). */
1456 /* The capture is done; there's nothing more for us to do. */
1459 if (start_capture) {
1460 /* "-k" was specified; start a capture. */
1461 do_capture(save_file);
1464 set_menus_for_capture_in_progress(FALSE);
1468 set_menus_for_capture_in_progress(FALSE);
1473 ethereal_proto_cleanup();
1480 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1482 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1483 *bv_table, *stat_hbox,
1484 *filter_bt, *filter_cm, *filter_te,
1486 GList *filter_list = NULL;
1488 GtkAccelGroup *accel;
1492 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1493 gtk_widget_set_name(top_level, "main window");
1494 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1495 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1496 gtk_signal_connect(GTK_OBJECT(top_level), "destroy",
1497 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1498 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1499 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1500 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1502 /* Container for menu bar, paned windows and progress/info box */
1503 main_vbox = gtk_vbox_new(FALSE, 1);
1504 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1505 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1506 gtk_widget_show(main_vbox);
1509 get_main_menu(&menubar, &accel);
1510 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1511 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1512 gtk_widget_show(menubar);
1514 /* Panes for the packet list, tree, and byte view */
1515 u_pane = gtk_vpaned_new();
1516 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1517 l_pane = gtk_vpaned_new();
1518 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1519 gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
1520 gtk_widget_show(u_pane);
1521 gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
1522 gtk_widget_show(l_pane);
1525 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1526 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1527 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1528 gtk_widget_show(pkt_scrollw);
1529 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1531 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1532 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1533 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1534 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1535 pl_style = gtk_style_new();
1536 gdk_font_unref(pl_style->font);
1537 pl_style->font = m_r_font;
1538 gtk_widget_set_style(packet_list, pl_style);
1539 gtk_widget_set_name(packet_list, "packet list");
1540 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1541 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1542 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1543 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1544 for (i = 0; i < cf.cinfo.num_cols; i++) {
1545 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1546 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1548 /* Right-justify the packet number column. */
1549 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1550 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1553 /* Save static column sizes to use during a "-S" capture, so that
1554 the columns don't resize during a live capture. */
1555 cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1556 get_column_longest_string(get_column_format(i)));
1558 gtk_widget_set_usize(packet_list, -1, pl_size);
1559 gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1560 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1561 gtk_widget_show(packet_list);
1564 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1565 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1566 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1567 gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
1568 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1569 gtk_widget_show(tv_scrollw);
1571 tree_view = gtk_ctree_new(1, 0);
1572 /* I need this next line to make the widget work correctly with hidden
1573 * column titles and GTK_SELECTION_BROWSE */
1574 gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1575 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1576 set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
1577 set_ptree_line_style(prefs->gui_ptree_line_style);
1578 set_ptree_expander_style(prefs->gui_ptree_expander_style);
1580 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1581 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1582 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1583 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1584 gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1585 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1586 gtk_widget_show(tree_view);
1588 item_style = gtk_style_new();
1589 gdk_font_unref(item_style->font);
1590 item_style->font = m_r_font;
1592 /* Byte view. The table is only one row high, but 3 columns
1593 * wide. The middle column contains the GtkText with the hex dump.
1594 * The left and right columns contain vertical scrollbars. They both
1595 * do the same thing, but only one will be shown at a time, in accordance
1596 * with where the user wants the other vertical scrollbars places
1597 * (on the left or the right).
1599 bv_table = gtk_table_new (1, 3, FALSE);
1600 gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
1601 gtk_widget_set_usize(bv_table, -1, bv_size);
1602 gtk_widget_show(bv_table);
1604 byte_view = gtk_text_new(NULL, NULL);
1605 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1606 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1607 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
1608 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1609 gtk_widget_show(byte_view);
1611 /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
1612 * in the GTK+ distribution, so I removed the horizontal scroll bar
1613 * that used to be here. I tried the gtk_text widget with a
1614 * gtk_scrolled_window w/ viewport, but the vertical scrollowing
1615 * did not work well, and sometimes a few pixels were cut off on
1618 bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1619 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
1620 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1622 bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1623 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
1624 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1626 /* Now that the 3 panes are created, set the vertical scrollbar
1627 * on the left or right according to the user's preference */
1628 set_scrollbar_placement(prefs->gui_scrollbar_on_right);
1630 /* Progress/filter/info box */
1631 stat_hbox = gtk_hbox_new(FALSE, 1);
1632 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1633 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1634 gtk_widget_show(stat_hbox);
1636 prog_bar = gtk_progress_bar_new();
1637 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1638 gtk_widget_show(prog_bar);
1640 filter_bt = gtk_button_new_with_label("Filter:");
1641 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1642 GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
1643 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1644 gtk_widget_show(filter_bt);
1646 filter_cm = gtk_combo_new();
1647 filter_list = g_list_append (filter_list, "");
1648 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1649 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1650 filter_te = GTK_COMBO(filter_cm)->entry;
1651 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1652 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1653 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1654 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1655 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1656 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1657 gtk_widget_show(filter_cm);
1659 filter_reset = gtk_button_new_with_label("Reset");
1660 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1661 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1662 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1663 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1664 gtk_widget_show(filter_reset);
1666 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1667 * of any widget that ends up calling a callback which needs
1668 * that text entry pointer */
1669 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1670 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1671 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1672 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1673 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1675 info_bar = gtk_statusbar_new();
1676 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1677 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1678 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1679 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1680 gtk_widget_show(info_bar);