3 * $Id: main.c,v 1.115 2000/04/04 07:03:07 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
98 #include "timestamp.h"
105 #include "filter_prefs.h"
106 #include "prefs_dlg.h"
112 #include "simple_dialog.h"
113 #include "proto_draw.h"
116 #include "packet_win.h"
117 #include "gtkglobals.h"
120 FILE *data_out_file = NULL;
123 GtkWidget *top_level, *packet_list, *tree_view, *byte_view,
124 *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
125 static GtkWidget *bv_scrollw;
126 GdkFont *m_r_font, *m_b_font;
127 guint main_ctx, file_ctx;
128 gchar comp_info_str[256];
129 gchar *ethereal_path = NULL;
130 gchar *medium_font = MONO_MEDIUM_FONT;
131 gchar *bold_font = MONO_BOLD_FONT;
132 gchar *last_open_dir = NULL;
134 ts_type timestamp_type = RELATIVE;
136 GtkStyle *item_style;
138 /* Specifies the field currently selected in the GUI protocol tree */
139 field_info *finfo_selected = NULL;
141 static void follow_destroy_cb(GtkWidget *win, gpointer data);
142 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
143 static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
144 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
145 static char* hfinfo_numeric_format(header_field_info *hfinfo);
146 static void create_main_window(gint, gint, gint, e_prefs*);
148 /* About Ethereal window */
150 about_ethereal( GtkWidget *w, gpointer data ) {
151 simple_dialog(ESD_TYPE_INFO, NULL,
152 "Ethereal - Network Protocol Analyzer\n"
153 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
154 "Compiled with %s\n\n"
156 "Check the man page for complete documentation and\n"
157 "for the list of contributors.\n"
159 "\nSee http://ethereal.zing.org/ for more information.",
163 /* Follow the TCP stream, if any, to which the last packet that we called
164 a dissection routine on belongs (this might be the most recently
165 selected packet, or it might be the last packet in the file). */
167 follow_stream_cb( GtkWidget *w, gpointer data ) {
168 char filename1[128+1];
169 GtkWidget *streamwindow, *box, *txt_scrollw, *text, *filter_te;
170 GtkWidget *hbox, *close_bt, *print_bt;
171 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
173 gchar *follow_filter;
175 if( pi.ipproto == 6 ) {
176 /* we got tcp so we can follow */
177 /* Create a temporary file into which to dump the reassembled data
178 from the TCP stream, and set "data_out_file" to refer to it, so
179 that the TCP code will write to it.
181 XXX - it might be nicer to just have the TCP code directly
182 append stuff to the text widget for the TCP stream window,
183 if we can arrange that said window not pop up until we're
185 tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
187 simple_dialog(ESD_TYPE_WARN, NULL,
188 "Could not create temporary file %s: %s", filename1, strerror(errno));
191 data_out_file = fdopen( tmp_fd, "w" );
192 if( data_out_file == NULL ) {
193 simple_dialog(ESD_TYPE_WARN, NULL,
194 "Could not create temporary file %s: %s", filename1, strerror(errno));
200 /* Create a new filter that matches all packets in the TCP stream,
201 and set the display filter entry accordingly */
202 reset_tcp_reassembly();
203 follow_filter = build_follow_filter( &pi );
205 /* set the display filter entry accordingly */
206 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
207 gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
209 /* Run the display filter so it goes in effect. */
210 filter_packets(&cf, follow_filter);
212 /* the data_out_file should now be full of the streams information */
213 fclose( data_out_file );
215 /* the filename1 file now has all the text that was in the session */
216 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
217 gtk_widget_set_name( streamwindow, "TCP stream window" );
219 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
220 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
222 if( incomplete_tcp_stream ) {
223 gtk_window_set_title( GTK_WINDOW(streamwindow),
224 "Contents of TCP stream (incomplete)" );
226 gtk_window_set_title( GTK_WINDOW(streamwindow),
227 "Contents of TCP stream" );
229 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
230 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
232 /* setup the container */
233 box = gtk_vbox_new( FALSE, 0 );
234 gtk_container_add( GTK_CONTAINER(streamwindow), box );
235 gtk_widget_show( box );
237 /* create a scrolled window for the text */
238 txt_scrollw = gtk_scrolled_window_new( NULL, NULL );
239 gtk_box_pack_start( GTK_BOX(box), txt_scrollw, TRUE, TRUE, 0 );
240 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(txt_scrollw),
243 set_scrollbar_placement_scrollw(txt_scrollw, prefs.gui_scrollbar_on_right);
244 remember_scrolled_window(txt_scrollw);
245 gtk_widget_show( txt_scrollw );
247 /* create a text box */
248 text = gtk_text_new( NULL, NULL );
249 gtk_text_set_editable( GTK_TEXT(text), FALSE);
250 gtk_container_add( GTK_CONTAINER(txt_scrollw), text );
251 gtk_widget_show(text);
254 hbox = gtk_hbox_new( FALSE, 1 );
255 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
256 gtk_widget_show(hbox);
258 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
259 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
260 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
262 /* Create Radio Buttons */
263 b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
264 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
265 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
266 gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
267 gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
268 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
269 GTK_OBJECT(streamwindow));
270 gtk_widget_show(b_ascii);
272 b_ebcdic = gtk_radio_button_new_with_label(
273 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
275 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
276 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
277 gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
278 gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
279 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
280 GTK_OBJECT(streamwindow));
281 gtk_widget_show(b_ebcdic);
283 b_hexdump = gtk_radio_button_new_with_label(
284 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
286 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
287 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
288 gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
289 gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
290 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
291 GTK_OBJECT(streamwindow));
292 gtk_widget_show(b_hexdump);
294 /* Create Close Button */
295 close_bt = gtk_button_new_with_label("Close");
296 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
297 GTK_SIGNAL_FUNC(gtk_widget_destroy),
298 GTK_OBJECT(streamwindow));
299 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
300 gtk_widget_show( close_bt );
302 /* Create Print Button */
303 print_bt = gtk_button_new_with_label("Print");
304 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
305 GTK_SIGNAL_FUNC(follow_print_stream),
306 GTK_OBJECT(streamwindow));
307 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
308 gtk_widget_show( print_bt );
310 /* Tuck away the filename and textbox into streamwindow */
311 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
312 #define E_FOLLOW_TEXT_KEY "follow_text_key"
314 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
315 g_strdup(filename1));
316 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
318 follow_load_text(text, filename1, 0);
320 data_out_file = NULL;
322 /* Make sure this widget gets destroyed if we quit the main loop,
323 so that if we exit, we clean up any temporary files we have
324 for "Follow TCP Stream" windows. */
325 gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(streamwindow));
326 gtk_widget_show( streamwindow );
328 simple_dialog(ESD_TYPE_WARN, NULL,
329 "Error following stream. Please make\n"
330 "sure you have a TCP packet selected.");
334 /* The destroy call back has the responsibility of
335 * unlinking the temporary file */
337 follow_destroy_cb(GtkWidget *win, gpointer data)
341 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
342 E_FOLLOW_FILENAME_KEY);
346 gtk_widget_destroy(win);
349 #define E_FOLLOW_ASCII_TYPE 0
350 #define E_FOLLOW_EBCDIC_TYPE 1
351 #define E_FOLLOW_HEXDUMP_TYPE 2
353 /* Handles the ASCII/EBCDIC toggling */
355 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
357 guint8 show_type = E_FOLLOW_ASCII_TYPE;
358 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
361 b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
363 b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
364 E_FOLLOW_EBCDIC_KEY);
365 b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
366 E_FOLLOW_HEXDUMP_KEY);
367 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
369 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
370 E_FOLLOW_FILENAME_KEY);
378 if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
379 show_type = E_FOLLOW_EBCDIC_TYPE;
380 else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
381 show_type = E_FOLLOW_HEXDUMP_TYPE;
383 follow_load_text(text, filename, show_type);
386 #define FLT_BUF_SIZE 1024
388 follow_read_stream(char *filename, guint8 show_type,
389 void (*print_line)(char *, int, gboolean, void *), void *arg)
393 guint32 client_addr = 0;
394 guint16 client_port = 0;
396 guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
399 data_out_file = fopen( filename, "r" );
400 if( data_out_file ) {
401 char buffer[FLT_BUF_SIZE];
403 while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
404 if (client_addr == 0) {
405 client_addr = sc.src_addr;
406 client_port = sc.src_port;
408 if (client_addr == sc.src_addr && client_port == sc.src_port) {
410 global_pos = &global_client_pos;
414 global_pos = &global_server_pos;
417 while (sc.dlen > 0) {
418 bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
419 nchars = fread( buffer, 1, bcount, data_out_file );
424 case E_FOLLOW_EBCDIC_TYPE:
425 /* If our native arch is ASCII, call: */
426 EBCDIC_to_ASCII(buffer, nchars);
427 case E_FOLLOW_ASCII_TYPE:
428 /* If our native arch is EBCDIC, call:
429 * ASCII_TO_EBCDIC(buffer, nchars);
431 (*print_line)( buffer, nchars, is_server, arg );
433 case E_FOLLOW_HEXDUMP_TYPE:
435 while (current_pos < nchars)
438 gchar hexchars[] = "0123456789abcdef";
440 /* is_server indentation : put 63 spaces at the begenning
442 sprintf(hexbuf, is_server ?
445 "%08X ", *global_pos);
446 cur = strlen(hexbuf);
447 for (i=0; i < 16 && current_pos+i < nchars; i++) {
448 hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
449 hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
451 hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
458 hexbuf[cur++] = '\n';
460 (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
466 if( ferror( data_out_file ) ) {
467 simple_dialog(ESD_TYPE_WARN, NULL,
468 "Error reading temporary file %s: %s", filename, strerror(errno));
470 fclose( data_out_file );
471 data_out_file = NULL;
473 simple_dialog(ESD_TYPE_WARN, NULL,
474 "Could not open temporary file %s: %s", filename, strerror(errno));
479 * XXX - for text printing, we probably want to wrap lines at 80 characters;
480 * for PostScript printing, we probably want to wrap them at the appropriate
481 * width, and perhaps put some kind of dingbat (to use the technical term)
482 * to indicate a wrapped line, along the lines of what's done when displaying
483 * this in a window, as per Warren Young's suggestion.
485 * For now, we support only text printing.
488 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
492 fwrite(buffer, nchars, 1, fh);
496 follow_print_stream(GtkWidget *w, gpointer parent_w)
502 guint8 show_type = E_FOLLOW_ASCII_TYPE;
505 switch (prefs.pr_dest) {
507 print_dest = prefs.pr_cmd;
512 print_dest = prefs.pr_file;
515 default: /* "Can't happen" */
516 simple_dialog(ESD_TYPE_WARN, NULL,
517 "Couldn't figure out where to send the print "
518 "job. Check your preferences.");
522 fh = open_print_dest(to_file, print_dest);
526 simple_dialog(ESD_TYPE_WARN, NULL,
527 "Couldn't run print command %s.", prefs.pr_cmd);
531 simple_dialog(ESD_TYPE_WARN, NULL,
532 file_write_error_message(errno),
539 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
540 E_FOLLOW_EBCDIC_KEY);
541 if (GTK_TOGGLE_BUTTON(button)->active)
542 show_type = E_FOLLOW_EBCDIC_TYPE;
543 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
544 E_FOLLOW_HEXDUMP_KEY);
545 if (GTK_TOGGLE_BUTTON(button)->active)
546 show_type = E_FOLLOW_HEXDUMP_TYPE;
548 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
549 E_FOLLOW_FILENAME_KEY);
551 if (filename != NULL) {
552 print_preamble(fh, PR_FMT_TEXT);
553 follow_read_stream(filename, show_type, follow_print_text, fh);
554 print_finale(fh, PR_FMT_TEXT);
555 close_print_dest(to_file, fh);
558 simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
563 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
565 GtkWidget *text = arg;
568 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
569 &prefs.st_server_bg, buffer, nchars );
571 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
572 &prefs.st_client_bg, buffer, nchars );
576 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
580 /* Delete any info already in text box */
581 bytes_already = gtk_text_get_length(GTK_TEXT(text));
582 if (bytes_already > 0) {
583 gtk_text_set_point(GTK_TEXT(text), 0);
584 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
587 /* stop the updates while we fill the text box */
588 gtk_text_freeze( GTK_TEXT(text) );
589 follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
590 gtk_text_thaw( GTK_TEXT(text) );
593 /* Match selected byte pattern */
595 match_selected_cb(GtkWidget *w, gpointer data)
598 GtkWidget *filter_te;
599 char *ptr, *format, *stringified;
600 int i, dfilter_len, abbrev_len;
602 header_field_info *hfinfo;
604 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
606 if (!finfo_selected) {
607 simple_dialog(ESD_TYPE_WARN, NULL,
608 "Error determining selected bytes. Please make\n"
609 "sure you have selected a field within the tree\n"
610 "view to be matched.");
614 hfinfo = finfo_selected->hfinfo;
616 abbrev_len = strlen(hfinfo->abbrev);
618 switch(hfinfo->type) {
621 dfilter_len = abbrev_len + 2;
622 buf = g_malloc0(dfilter_len);
623 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
635 dfilter_len = abbrev_len + 20;
636 buf = g_malloc0(dfilter_len);
637 format = hfinfo_numeric_format(hfinfo);
638 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
642 dfilter_len = abbrev_len + 4 + 15 + 1;
643 buf = g_malloc0(dfilter_len);
644 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
645 ipv4_addr_str(&(finfo_selected->value.ipv4)));
649 dfilter_len = abbrev_len + 15;
650 buf = g_malloc0(dfilter_len);
651 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
652 finfo_selected->value.numeric);
656 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
657 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
658 buf = g_malloc0(dfilter_len);
659 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
664 dfilter_len = abbrev_len + 30;
665 buf = g_malloc0(dfilter_len);
666 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
667 finfo_selected->value.floating);
671 dfilter_len = abbrev_len + 22;
672 buf = g_malloc0(dfilter_len);
673 snprintf(buf, dfilter_len, "%s == %s",
675 ether_to_str(finfo_selected->value.ether));
679 case FT_ABSOLUTE_TIME:
680 case FT_RELATIVE_TIME:
681 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
682 sizeof(struct timeval));
686 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
687 fi->value.string = g_strdup(va_arg(ap, char*));
695 c = cf.pd + finfo_selected->start;
696 buf = g_malloc0(32 + finfo_selected->length * 3);
699 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
700 ptr = buf+strlen(buf);
702 if (finfo_selected->length == 1) {
703 sprintf(ptr, "0x%02x", *c++);
706 for (i=0;i<finfo_selected->length; i++) {
708 sprintf(ptr, "%02x", *c++);
711 sprintf(ptr, ":%02x", *c++);
713 ptr = buf+strlen(buf);
719 /* create a new one and set the display filter entry accordingly */
720 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
722 /* Run the display filter so it goes in effect. */
723 filter_packets(&cf, buf);
725 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
729 hfinfo_numeric_format(header_field_info *hfinfo)
733 /* Pick the proper format string */
734 switch(hfinfo->display) {
737 case BASE_OCT: /* I'm lazy */
738 case BASE_BIN: /* I'm lazy */
739 switch(hfinfo->type) {
753 g_assert_not_reached();
758 switch(hfinfo->type) {
760 format = "%s == 0x%02x";
763 format = "%s == 0x%04x";
766 format = "%s == 0x%06x";
769 format = "%s == 0x%08x";
772 g_assert_not_reached();
777 g_assert_not_reached();
784 /* Run the current display filter on the current packet set, and
787 filter_activate_cb(GtkWidget *w, gpointer data)
789 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
790 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
791 GList *li, *nl = NULL;
792 gboolean add_filter = TRUE;
794 char *s = gtk_entry_get_text(GTK_ENTRY(w));
796 /* GtkCombos don't let us get at their list contents easily, so we maintain
797 our own filter list, and feed it to gtk_combo_set_popdown_strings when
798 a new filter is added. */
799 if (filter_packets(&cf, g_strdup(s))) {
800 li = g_list_first(filter_list);
802 if (li->data && strcmp(s, li->data) == 0)
808 filter_list = g_list_append(filter_list, g_strdup(s));
809 li = g_list_first(filter_list);
811 nl = g_list_append(nl, strdup(li->data));
814 gtk_combo_set_popdown_strings(filter_cm, nl);
815 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
820 /* redisplay with no display filter */
822 filter_reset_cb(GtkWidget *w, gpointer data)
824 GtkWidget *filter_te = NULL;
826 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
827 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
830 filter_packets(&cf, NULL);
833 /* What to do when a list item is selected/unselected */
835 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
846 select_packet(&cf, row);
850 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
851 unselect_packet(&cf);
855 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
860 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
863 finfo_selected = finfo;
865 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
866 finfo->start, finfo->length, 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);
887 void resolve_name_cb(GtkWidget *widget, gpointer data) {
888 if (cf.protocol_tree) {
889 int tmp = g_resolving_actif;
890 g_resolving_actif = 1;
891 gtk_clist_clear ( GTK_CLIST(tree_view) );
892 proto_tree_draw(cf.protocol_tree, tree_view);
893 g_resolving_actif = tmp;
897 /* Set the scrollbar placement of a scrolled window based upon pos value:
898 0 = left, 1 = right */
900 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
903 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
904 GTK_CORNER_TOP_LEFT);
906 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
907 GTK_CORNER_TOP_RIGHT);
911 /* List of all scrolled windows, so we can globally set the scrollbar
912 placement of them. */
913 static GList *scrolled_windows;
915 /* Add a scrolled window to the list of scrolled windows. */
917 remember_scrolled_window(GtkWidget *scrollw)
919 scrolled_windows = g_list_append(scrolled_windows, scrollw);
922 /* Remove a scrolled window from the list of scrolled windows. */
924 forget_scrolled_window(GtkWidget *scrollw)
926 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
930 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
932 set_scrollbar_placement_scrollw((GtkWidget *)data,
936 /* Set the scrollbar placement of all scrolled windows based on pos value:
937 0 = left, 1 = right */
939 set_scrollbar_placement_all(int pos)
941 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
944 /* Set the selection mode of the packet list window. */
946 set_plist_sel_browse(gboolean val)
949 unselect_packet(&cf);
951 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
952 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
954 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
957 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
961 /* Set the selection mode of a given packet tree window. */
963 set_ptree_sel_browse(GtkWidget *tv, gboolean val)
965 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
966 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
968 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_SINGLE);
971 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_BROWSE);
975 /* Set the selection mode of all packet tree windows. */
977 set_ptree_sel_browse_all(gboolean val)
979 set_ptree_sel_browse(tree_view, val);
980 set_ptree_sel_browse_packet_wins(val);
983 /* Set the line style of a given packet tree window. */
985 set_ptree_line_style(GtkWidget *tv, gint style)
987 /* I'm using an assert here since the preferences code limits
988 * the user input, both in the GUI and when reading the preferences file.
989 * If the value is incorrect, it's a program error, not a user-initiated error.
991 g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
992 gtk_ctree_set_line_style( GTK_CTREE(tv), style );
995 /* Set the line style of all packet tree window. */
997 set_ptree_line_style_all(gint style)
999 set_ptree_line_style(tree_view, style);
1000 set_ptree_line_style_packet_wins(style);
1003 /* Set the expander style of a given packet tree window. */
1005 set_ptree_expander_style(GtkWidget *tv, gint style)
1007 /* I'm using an assert here since the preferences code limits
1008 * the user input, both in the GUI and when reading the preferences file.
1009 * If the value is incorrect, it's a program error, not a user-initiated error.
1011 g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
1012 gtk_ctree_set_expander_style( GTK_CTREE(tv), style );
1016 set_ptree_expander_style_all(gint style)
1018 set_ptree_expander_style(tree_view, style);
1019 set_ptree_expander_style_packet_wins(style);
1023 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
1025 file_quit_cmd_cb(widget, data);
1027 /* Say that the window should be deleted. */
1032 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
1034 /* XXX - should we check whether the capture file is an
1035 unsaved temporary file for a live capture and, if so,
1036 pop up a "do you want to exit without saving the capture
1037 file?" dialog, and then just return, leaving said dialog
1038 box to forcibly quit if the user clicks "OK"?
1040 If so, note that this should be done in a subroutine that
1041 returns TRUE if we do so, and FALSE otherwise, and that
1042 "main_window_delete_event_cb()" should return its
1045 /* Close any capture file we have open; on some OSes, you can't
1046 unlink a temporary capture file if you have it open.
1047 "close_cap_file()" will unlink it after closing it if
1048 it's a temporary file.
1050 We do this here, rather than after the main loop returns,
1051 as, after the main loop returns, the main window may have
1052 been destroyed (if this is called due to a "destroy"
1053 even on the main window rather than due to the user
1054 selecting a menu item), and there may be a crash
1055 or other problem when "close_cap_file()" tries to
1056 clean up stuff in the main window.
1058 XXX - is there a better place to put this?
1059 Or should we have a routine that *just* closes the
1060 capture file, and doesn't do anything with the UI,
1061 which we'd call here, and another routine that
1062 calls that routine and also cleans up the UI, which
1063 we'd call elsewhere? */
1064 close_cap_file(&cf, info_bar);
1066 /* Exit by leaving the main loop, so that any quit functions
1067 we registered get called. */
1074 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1077 fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1079 fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1080 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1081 fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1082 fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1084 fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1086 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1087 fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1088 fprintf(stderr, "\t[ -T <tree view height> ]\n");
1092 /* And now our feature presentation... [ fade to music ] */
1094 main(int argc, char *argv[])
1102 extern char *optarg;
1103 gboolean arg_error = FALSE;
1106 char pcap_version[] = "0.4a6";
1108 extern char pcap_version[];
1112 int pf_open_errno = 0;
1115 gboolean start_capture = FALSE;
1116 gchar *save_file = NULL;
1118 gchar err_str[PCAP_ERRBUF_SIZE];
1120 gboolean capture_option_specified = FALSE;
1122 gint pl_size = 280, tv_size = 95, bv_size = 75;
1123 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1124 dfilter *rfcode = NULL;
1125 gboolean rfilter_parse_failed = FALSE;
1128 ethereal_path = argv[0];
1131 command_name = get_basename(ethereal_path);
1132 /* Set "capture_child" to indicate whether this is going to be a child
1133 process for a "-S" capture. */
1134 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1137 /* If invoked with the "-G" flag, we dump out a glossary of
1138 display filter symbols.
1140 We must do this before calling "gtk_init()", because "gtk_init()"
1141 tries to open an X display, and we don't want to have to do any X
1142 stuff just to do a build.
1144 Given that we call "gtk_init()" before doing the regular argument
1145 list processing, so that it can handle X and GTK+ arguments and
1146 remove them from the list at which we look, this means we must do
1147 this before doing the regular argument list processing, as well.
1151 you must give the "-G" flag as the first flag on the command line;
1153 you must give it as "-G", nothing more, nothing less;
1155 any arguments after the "-G" flag will not be used. */
1156 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1158 proto_registrar_dump();
1162 /* Let GTK get its args */
1163 gtk_init (&argc, &argv);
1165 prefs = read_prefs(&pf_path);
1166 if (pf_path != NULL) {
1167 /* The preferences file exists, but couldn't be opened; "pf_path" is
1168 its pathname. Remember "errno", as that says why the attempt
1170 pf_open_errno = errno;
1173 /* Initialize the capture file struct */
1175 cf.plist_end = NULL;
1179 cf.user_saved = FALSE;
1180 cf.is_tempfile = FALSE;
1185 cf.cfilter = g_strdup(EMPTY_FILTER);
1188 cf.save_file = NULL;
1189 cf.save_file_fd = -1;
1190 cf.snap = WTAP_MAX_PACKET_SIZE;
1192 cf.cinfo.num_cols = prefs->num_cols;
1193 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1194 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1195 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1196 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1197 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1199 /* Assemble the compile-time options */
1200 snprintf(comp_info_str, 256,
1201 #ifdef GTK_MAJOR_VERSION
1202 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1205 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1209 "with libpcap ", pcap_version,
1211 "without libpcap", "",
1216 "with libz ", ZLIB_VERSION,
1217 #else /* ZLIB_VERSION */
1218 "with libz ", "(version unknown)",
1219 #endif /* ZLIB_VERSION */
1220 #else /* HAVE_LIBZ */
1222 #endif /* HAVE_LIBZ */
1224 /* Oh, this is pretty */
1225 #if defined(HAVE_UCD_SNMP_SNMP_H)
1226 #ifdef HAVE_UCD_SNMP_VERSION_H
1227 "with UCD SNMP ", VersionInfo
1228 #else /* HAVE_UCD_SNMP_VERSION_H */
1229 "with UCD SNMP ", "(version unknown)"
1230 #endif /* HAVE_UCD_SNMP_VERSION_H */
1231 #elif defined(HAVE_SNMP_SNMP_H)
1232 #ifdef HAVE_SNMP_VERSION_H
1233 "with CMU SNMP ", snmp_Version()
1234 #else /* HAVE_SNMP_VERSION_H */
1235 "with CMU SNMP ", "(version unknown)"
1236 #endif /* HAVE_SNMP_VERSION_H */
1242 /* Now get our args */
1243 while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1245 case 'b': /* Bold font */
1246 bold_font = g_strdup(optarg);
1248 case 'B': /* Byte view pane height */
1249 bv_size = atoi(optarg);
1251 case 'c': /* Capture xxx packets */
1253 cf.count = atoi(optarg);
1255 capture_option_specified = TRUE;
1259 case 'D': /* Turn off DSCP printing */
1260 g_ip_dscp_actif = FALSE;
1266 cf.cfilter = g_strdup(optarg);
1268 capture_option_specified = TRUE;
1272 case 'h': /* Print help and exit */
1276 case 'i': /* Use interface xxx */
1278 cf.iface = g_strdup(optarg);
1280 capture_option_specified = TRUE;
1284 case 'k': /* Start capture immediately */
1286 start_capture = TRUE;
1288 capture_option_specified = TRUE;
1292 case 'm': /* Medium font */
1293 medium_font = g_strdup(optarg);
1295 case 'n': /* No name resolution */
1296 g_resolving_actif = 0;
1298 case 'P': /* Packet list pane height */
1299 pl_size = atoi(optarg);
1301 case 'Q': /* Quit after capture (just capture to file) */
1304 start_capture = TRUE; /*** -Q implies -k !! ***/
1306 capture_option_specified = TRUE;
1310 case 'r': /* Read capture file xxx */
1311 /* We may set "last_open_dir" to "cf_name", and if we change
1312 "last_open_dir" later, we free the old value, so we have to
1313 set "cf_name" to something that's been allocated. */
1314 cf_name = g_strdup(optarg);
1316 case 'R': /* Read file filter */
1319 case 's': /* Set the snapshot (capture) length */
1321 cf.snap = atoi(optarg);
1323 capture_option_specified = TRUE;
1327 case 'S': /* "Sync" mode: used for following file ala tail -f */
1331 capture_option_specified = TRUE;
1335 case 't': /* Time stamp type */
1336 if (strcmp(optarg, "r") == 0)
1337 timestamp_type = RELATIVE;
1338 else if (strcmp(optarg, "a") == 0)
1339 timestamp_type = ABSOLUTE;
1340 else if (strcmp(optarg, "d") == 0)
1341 timestamp_type = DELTA;
1343 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1345 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1346 fprintf(stderr, "or \"d\" for delta.\n");
1350 case 'T': /* Tree view pane height */
1351 tv_size = atoi(optarg);
1353 case 'v': /* Show version and exit */
1354 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1357 case 'w': /* Write to capture file xxx */
1359 save_file = g_strdup(optarg);
1361 capture_option_specified = TRUE;
1365 case 'W': /* Write to capture file FD xxx */
1367 cf.save_file_fd = atoi(optarg);
1369 capture_option_specified = TRUE;
1374 case '?': /* Bad flag - print usage message */
1380 #ifndef HAVE_LIBPCAP
1381 if (capture_option_specified)
1382 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1387 if (start_capture) {
1388 /* We're supposed to do a live capture; did the user specify an interface
1390 if (cf.iface == NULL) {
1391 /* No - pick the first one from the list of interfaces. */
1392 if_list = get_interface_list(&err, err_str);
1393 if (if_list == NULL) {
1396 case CANT_GET_INTERFACE_LIST:
1397 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1401 case NO_INTERFACES_FOUND:
1402 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1407 cf.iface = g_strdup(if_list->data); /* first interface */
1408 free_interface_list(if_list);
1411 if (capture_child) {
1412 if (cf.save_file_fd == -1) {
1413 /* XXX - send this to the standard output as something our parent
1414 should put in an error message box? */
1415 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1421 /* Build the column format array */
1422 for (i = 0; i < cf.cinfo.num_cols; i++) {
1423 cf.cinfo.col_fmt[i] = get_column_format(i);
1424 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1425 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1427 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1428 if (cf.cinfo.col_fmt[i] == COL_INFO)
1429 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1431 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1435 cf.snap = WTAP_MAX_PACKET_SIZE;
1436 else if (cf.snap < MIN_PACKET_SIZE)
1437 cf.snap = MIN_PACKET_SIZE;
1439 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1440 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1441 gtk_rc_parse(rc_file);
1443 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1444 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1448 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1449 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1453 create_main_window(pl_size, tv_size, bv_size, prefs);
1456 Hmmm should we do it here
1459 dissect_init(); /* Init anything that needs initializing */
1462 /* Is this a "child" ethereal, which is only supposed to pop up a
1463 capture box to let us stop the capture, and run a capture
1464 to a file that our parent will read? */
1465 if (!capture_child) {
1467 /* No. Pop up the main window, and read in a capture file if
1470 gtk_widget_show(top_level);
1471 set_menus_for_capture_file(FALSE);
1473 cf.colors = colfilter_new();
1475 /* If we were given the name of a capture file, read it in now;
1476 we defer it until now, so that, if we can't open it, and pop
1477 up an alert box, the alert box is more likely to come up on
1478 top of the main window - but before the preference-file-error
1479 alert box, so, if we get one of those, it's more likely to come
1482 if (rfilter != NULL) {
1483 if (dfilter_compile(rfilter, &rfcode) != 0) {
1484 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1485 rfilter_parse_failed = TRUE;
1488 if (!rfilter_parse_failed) {
1489 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1490 /* "open_cap_file()" succeeded, so it closed the previous
1491 capture file, and thus destroyed any previous read filter
1492 attached to "cf". */
1494 err = read_cap_file(&cf);
1495 /* Save the name of the containing directory specified in the
1496 path name, if any; we can write over cf_name, which is a
1497 good thing, given that "get_dirname()" does write over its
1499 s = get_dirname(cf_name);
1503 dfilter_destroy(rfcode);
1512 /* If we failed to open the preferences file, pop up an alert box;
1513 we defer it until now, so that the alert box is more likely to
1514 come up on top of the main window. */
1515 if (pf_path != NULL) {
1516 simple_dialog(ESD_TYPE_WARN, NULL,
1517 "Could not open preferences file\n\"%s\": %s.", pf_path,
1518 strerror(pf_open_errno));
1522 if (capture_child) {
1523 /* This is the child process for a sync mode or fork mode capture,
1524 so just do the low-level work of a capture - don't create
1525 a temporary file and fork off *another* child process (so don't
1526 call "do_capture()"). */
1530 /* The capture is done; there's nothing more for us to do. */
1533 if (start_capture) {
1534 /* "-k" was specified; start a capture. */
1535 do_capture(save_file);
1538 set_menus_for_capture_in_progress(FALSE);
1542 set_menus_for_capture_in_progress(FALSE);
1552 /* This isn't reached, but we need it to keep GCC from complaining
1553 that "main()" returns without returning a value - it knows that
1554 "exit()" never returns, but it doesn't know that "gtk_exit()"
1555 doesn't, as GTK+ doesn't declare it with the attribute
1557 return 0; /* not reached */
1561 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1563 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1565 *filter_bt, *filter_cm, *filter_te,
1567 GList *filter_list = NULL;
1569 GtkAccelGroup *accel;
1573 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1574 gtk_widget_set_name(top_level, "main window");
1575 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1576 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1577 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1578 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1579 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1581 /* Container for menu bar, paned windows and progress/info box */
1582 main_vbox = gtk_vbox_new(FALSE, 1);
1583 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1584 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1585 gtk_widget_show(main_vbox);
1588 get_main_menu(&menubar, &accel);
1589 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1590 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1591 gtk_widget_show(menubar);
1593 /* Panes for the packet list, tree, and byte view */
1594 u_pane = gtk_vpaned_new();
1595 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1596 l_pane = gtk_vpaned_new();
1597 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1598 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1599 gtk_widget_show(l_pane);
1600 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1601 gtk_widget_show(u_pane);
1604 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1605 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1606 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1607 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1608 remember_scrolled_window(pkt_scrollw);
1609 gtk_widget_show(pkt_scrollw);
1610 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1612 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1613 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1614 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1615 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1616 pl_style = gtk_style_new();
1617 gdk_font_unref(pl_style->font);
1618 pl_style->font = m_r_font;
1619 gtk_widget_set_style(packet_list, pl_style);
1620 gtk_widget_set_name(packet_list, "packet list");
1621 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1622 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1623 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1624 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1625 for (i = 0; i < cf.cinfo.num_cols; i++) {
1626 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1627 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1629 /* Right-justify the packet number column. */
1630 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1631 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1634 /* Save static column sizes to use during a "-S" capture, so that
1635 the columns don't resize during a live capture. */
1636 cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1637 get_column_longest_string(get_column_format(i)));
1639 gtk_widget_set_usize(packet_list, -1, pl_size);
1640 gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1641 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1642 gtk_widget_show(packet_list);
1645 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1646 prefs->gui_scrollbar_on_right);
1647 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1648 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1649 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1650 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1651 gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1652 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1653 gtk_widget_show(tree_view);
1655 item_style = gtk_style_new();
1656 gdk_font_unref(item_style->font);
1657 item_style->font = m_r_font;
1660 create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1661 prefs->gui_scrollbar_on_right);
1663 /* Progress/filter/info box */
1664 stat_hbox = gtk_hbox_new(FALSE, 1);
1665 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1666 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1667 gtk_widget_show(stat_hbox);
1669 prog_bar = gtk_progress_bar_new();
1670 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1671 gtk_widget_show(prog_bar);
1673 filter_bt = gtk_button_new_with_label("Filter:");
1674 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1675 GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1676 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1677 gtk_widget_show(filter_bt);
1679 filter_cm = gtk_combo_new();
1680 filter_list = g_list_append (filter_list, "");
1681 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1682 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1683 filter_te = GTK_COMBO(filter_cm)->entry;
1684 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1685 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1686 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1687 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1688 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1689 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1690 gtk_widget_show(filter_cm);
1692 filter_reset = gtk_button_new_with_label("Reset");
1693 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1694 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1695 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1696 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1697 gtk_widget_show(filter_reset);
1699 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1700 * of any widget that ends up calling a callback which needs
1701 * that text entry pointer */
1702 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1703 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1704 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1705 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1706 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1708 info_bar = gtk_statusbar_new();
1709 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1710 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1711 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1712 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1713 gtk_widget_show(info_bar);