3 * $Id: main.c,v 1.114 2000/04/04 06:46:41 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. */
1071 /* call initialization routines at program startup time */
1073 ethereal_proto_init(void) {
1082 ethereal_proto_cleanup(void) {
1090 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1093 fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1095 fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1096 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1097 fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1098 fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1100 fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1102 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1103 fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1104 fprintf(stderr, "\t[ -T <tree view height> ]\n");
1108 /* And now our feature presentation... [ fade to music ] */
1110 main(int argc, char *argv[])
1118 extern char *optarg;
1119 gboolean arg_error = FALSE;
1122 char pcap_version[] = "0.4a6";
1124 extern char pcap_version[];
1128 int pf_open_errno = 0;
1131 gboolean start_capture = FALSE;
1132 gchar *save_file = NULL;
1134 gchar err_str[PCAP_ERRBUF_SIZE];
1136 gboolean capture_option_specified = FALSE;
1138 gint pl_size = 280, tv_size = 95, bv_size = 75;
1139 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1140 dfilter *rfcode = NULL;
1141 gboolean rfilter_parse_failed = FALSE;
1144 ethereal_path = argv[0];
1147 command_name = get_basename(ethereal_path);
1148 /* Set "capture_child" to indicate whether this is going to be a child
1149 process for a "-S" capture. */
1150 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1153 /* If invoked with the "-G" flag, we dump out a glossary of
1154 display filter symbols.
1156 We must do this before calling "gtk_init()", because "gtk_init()"
1157 tries to open an X display, and we don't want to have to do any X
1158 stuff just to do a build.
1160 Given that we call "gtk_init()" before doing the regular argument
1161 list processing, so that it can handle X and GTK+ arguments and
1162 remove them from the list at which we look, this means we must do
1163 this before doing the regular argument list processing, as well.
1167 you must give the "-G" flag as the first flag on the command line;
1169 you must give it as "-G", nothing more, nothing less;
1171 any arguments after the "-G" flag will not be used. */
1172 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1173 ethereal_proto_init();
1174 proto_registrar_dump();
1178 /* Let GTK get its args */
1179 gtk_init (&argc, &argv);
1181 prefs = read_prefs(&pf_path);
1182 if (pf_path != NULL) {
1183 /* The preferences file exists, but couldn't be opened; "pf_path" is
1184 its pathname. Remember "errno", as that says why the attempt
1186 pf_open_errno = errno;
1189 /* Initialize the capture file struct */
1191 cf.plist_end = NULL;
1195 cf.user_saved = FALSE;
1196 cf.is_tempfile = FALSE;
1201 cf.cfilter = g_strdup(EMPTY_FILTER);
1204 cf.save_file = NULL;
1205 cf.save_file_fd = -1;
1206 cf.snap = WTAP_MAX_PACKET_SIZE;
1208 cf.cinfo.num_cols = prefs->num_cols;
1209 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1210 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1211 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1212 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1213 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1215 /* Assemble the compile-time options */
1216 snprintf(comp_info_str, 256,
1217 #ifdef GTK_MAJOR_VERSION
1218 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1221 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1225 "with libpcap ", pcap_version,
1227 "without libpcap", "",
1232 "with libz ", ZLIB_VERSION,
1233 #else /* ZLIB_VERSION */
1234 "with libz ", "(version unknown)",
1235 #endif /* ZLIB_VERSION */
1236 #else /* HAVE_LIBZ */
1238 #endif /* HAVE_LIBZ */
1240 /* Oh, this is pretty */
1241 #if defined(HAVE_UCD_SNMP_SNMP_H)
1242 #ifdef HAVE_UCD_SNMP_VERSION_H
1243 "with UCD SNMP ", VersionInfo
1244 #else /* HAVE_UCD_SNMP_VERSION_H */
1245 "with UCD SNMP ", "(version unknown)"
1246 #endif /* HAVE_UCD_SNMP_VERSION_H */
1247 #elif defined(HAVE_SNMP_SNMP_H)
1248 #ifdef HAVE_SNMP_VERSION_H
1249 "with CMU SNMP ", snmp_Version()
1250 #else /* HAVE_SNMP_VERSION_H */
1251 "with CMU SNMP ", "(version unknown)"
1252 #endif /* HAVE_SNMP_VERSION_H */
1258 /* Now get our args */
1259 while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1261 case 'b': /* Bold font */
1262 bold_font = g_strdup(optarg);
1264 case 'B': /* Byte view pane height */
1265 bv_size = atoi(optarg);
1267 case 'c': /* Capture xxx packets */
1269 cf.count = atoi(optarg);
1271 capture_option_specified = TRUE;
1275 case 'D': /* Turn off DSCP printing */
1276 g_ip_dscp_actif = FALSE;
1282 cf.cfilter = g_strdup(optarg);
1284 capture_option_specified = TRUE;
1288 case 'h': /* Print help and exit */
1292 case 'i': /* Use interface xxx */
1294 cf.iface = g_strdup(optarg);
1296 capture_option_specified = TRUE;
1300 case 'k': /* Start capture immediately */
1302 start_capture = TRUE;
1304 capture_option_specified = TRUE;
1308 case 'm': /* Medium font */
1309 medium_font = g_strdup(optarg);
1311 case 'n': /* No name resolution */
1312 g_resolving_actif = 0;
1314 case 'P': /* Packet list pane height */
1315 pl_size = atoi(optarg);
1317 case 'Q': /* Quit after capture (just capture to file) */
1320 start_capture = TRUE; /*** -Q implies -k !! ***/
1322 capture_option_specified = TRUE;
1326 case 'r': /* Read capture file xxx */
1327 /* We may set "last_open_dir" to "cf_name", and if we change
1328 "last_open_dir" later, we free the old value, so we have to
1329 set "cf_name" to something that's been allocated. */
1330 cf_name = g_strdup(optarg);
1332 case 'R': /* Read file filter */
1335 case 's': /* Set the snapshot (capture) length */
1337 cf.snap = atoi(optarg);
1339 capture_option_specified = TRUE;
1343 case 'S': /* "Sync" mode: used for following file ala tail -f */
1347 capture_option_specified = TRUE;
1351 case 't': /* Time stamp type */
1352 if (strcmp(optarg, "r") == 0)
1353 timestamp_type = RELATIVE;
1354 else if (strcmp(optarg, "a") == 0)
1355 timestamp_type = ABSOLUTE;
1356 else if (strcmp(optarg, "d") == 0)
1357 timestamp_type = DELTA;
1359 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1361 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1362 fprintf(stderr, "or \"d\" for delta.\n");
1366 case 'T': /* Tree view pane height */
1367 tv_size = atoi(optarg);
1369 case 'v': /* Show version and exit */
1370 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1373 case 'w': /* Write to capture file xxx */
1375 save_file = g_strdup(optarg);
1377 capture_option_specified = TRUE;
1381 case 'W': /* Write to capture file FD xxx */
1383 cf.save_file_fd = atoi(optarg);
1385 capture_option_specified = TRUE;
1390 case '?': /* Bad flag - print usage message */
1396 #ifndef HAVE_LIBPCAP
1397 if (capture_option_specified)
1398 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1403 if (start_capture) {
1404 /* We're supposed to do a live capture; did the user specify an interface
1406 if (cf.iface == NULL) {
1407 /* No - pick the first one from the list of interfaces. */
1408 if_list = get_interface_list(&err, err_str);
1409 if (if_list == NULL) {
1412 case CANT_GET_INTERFACE_LIST:
1413 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1417 case NO_INTERFACES_FOUND:
1418 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1423 cf.iface = g_strdup(if_list->data); /* first interface */
1424 free_interface_list(if_list);
1427 if (capture_child) {
1428 if (cf.save_file_fd == -1) {
1429 /* XXX - send this to the standard output as something our parent
1430 should put in an error message box? */
1431 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1437 /* Build the column format array */
1438 for (i = 0; i < cf.cinfo.num_cols; i++) {
1439 cf.cinfo.col_fmt[i] = get_column_format(i);
1440 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1441 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1443 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1444 if (cf.cinfo.col_fmt[i] == COL_INFO)
1445 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1447 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1451 cf.snap = WTAP_MAX_PACKET_SIZE;
1452 else if (cf.snap < MIN_PACKET_SIZE)
1453 cf.snap = MIN_PACKET_SIZE;
1455 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1456 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1457 gtk_rc_parse(rc_file);
1459 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1460 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1464 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1465 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1469 create_main_window(pl_size, tv_size, bv_size, prefs);
1472 Hmmm should we do it here
1475 ethereal_proto_init(); /* Init anything that needs initializing */
1478 /* Is this a "child" ethereal, which is only supposed to pop up a
1479 capture box to let us stop the capture, and run a capture
1480 to a file that our parent will read? */
1481 if (!capture_child) {
1483 /* No. Pop up the main window, and read in a capture file if
1486 gtk_widget_show(top_level);
1487 set_menus_for_capture_file(FALSE);
1489 cf.colors = colfilter_new();
1491 /* If we were given the name of a capture file, read it in now;
1492 we defer it until now, so that, if we can't open it, and pop
1493 up an alert box, the alert box is more likely to come up on
1494 top of the main window - but before the preference-file-error
1495 alert box, so, if we get one of those, it's more likely to come
1498 if (rfilter != NULL) {
1499 if (dfilter_compile(rfilter, &rfcode) != 0) {
1500 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1501 rfilter_parse_failed = TRUE;
1504 if (!rfilter_parse_failed) {
1505 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1506 /* "open_cap_file()" succeeded, so it closed the previous
1507 capture file, and thus destroyed any previous read filter
1508 attached to "cf". */
1510 err = read_cap_file(&cf);
1511 /* Save the name of the containing directory specified in the
1512 path name, if any; we can write over cf_name, which is a
1513 good thing, given that "get_dirname()" does write over its
1515 s = get_dirname(cf_name);
1519 dfilter_destroy(rfcode);
1528 /* If we failed to open the preferences file, pop up an alert box;
1529 we defer it until now, so that the alert box is more likely to
1530 come up on top of the main window. */
1531 if (pf_path != NULL) {
1532 simple_dialog(ESD_TYPE_WARN, NULL,
1533 "Could not open preferences file\n\"%s\": %s.", pf_path,
1534 strerror(pf_open_errno));
1538 if (capture_child) {
1539 /* This is the child process for a sync mode or fork mode capture,
1540 so just do the low-level work of a capture - don't create
1541 a temporary file and fork off *another* child process (so don't
1542 call "do_capture()"). */
1546 /* The capture is done; there's nothing more for us to do. */
1549 if (start_capture) {
1550 /* "-k" was specified; start a capture. */
1551 do_capture(save_file);
1554 set_menus_for_capture_in_progress(FALSE);
1558 set_menus_for_capture_in_progress(FALSE);
1563 ethereal_proto_cleanup();
1568 /* This isn't reached, but we need it to keep GCC from complaining
1569 that "main()" returns without returning a value - it knows that
1570 "exit()" never returns, but it doesn't know that "gtk_exit()"
1571 doesn't, as GTK+ doesn't declare it with the attribute
1573 return 0; /* not reached */
1577 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1579 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1581 *filter_bt, *filter_cm, *filter_te,
1583 GList *filter_list = NULL;
1585 GtkAccelGroup *accel;
1589 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1590 gtk_widget_set_name(top_level, "main window");
1591 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1592 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1593 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1594 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1595 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1597 /* Container for menu bar, paned windows and progress/info box */
1598 main_vbox = gtk_vbox_new(FALSE, 1);
1599 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1600 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1601 gtk_widget_show(main_vbox);
1604 get_main_menu(&menubar, &accel);
1605 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1606 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1607 gtk_widget_show(menubar);
1609 /* Panes for the packet list, tree, and byte view */
1610 u_pane = gtk_vpaned_new();
1611 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1612 l_pane = gtk_vpaned_new();
1613 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1614 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1615 gtk_widget_show(l_pane);
1616 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1617 gtk_widget_show(u_pane);
1620 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1621 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1622 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1623 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1624 remember_scrolled_window(pkt_scrollw);
1625 gtk_widget_show(pkt_scrollw);
1626 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1628 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1629 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1630 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1631 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1632 pl_style = gtk_style_new();
1633 gdk_font_unref(pl_style->font);
1634 pl_style->font = m_r_font;
1635 gtk_widget_set_style(packet_list, pl_style);
1636 gtk_widget_set_name(packet_list, "packet list");
1637 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1638 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1639 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1640 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1641 for (i = 0; i < cf.cinfo.num_cols; i++) {
1642 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1643 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1645 /* Right-justify the packet number column. */
1646 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1647 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1650 /* Save static column sizes to use during a "-S" capture, so that
1651 the columns don't resize during a live capture. */
1652 cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1653 get_column_longest_string(get_column_format(i)));
1655 gtk_widget_set_usize(packet_list, -1, pl_size);
1656 gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1657 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1658 gtk_widget_show(packet_list);
1661 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1662 prefs->gui_scrollbar_on_right);
1663 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1664 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1665 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1666 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1667 gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1668 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1669 gtk_widget_show(tree_view);
1671 item_style = gtk_style_new();
1672 gdk_font_unref(item_style->font);
1673 item_style->font = m_r_font;
1676 create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1677 prefs->gui_scrollbar_on_right);
1679 /* Progress/filter/info box */
1680 stat_hbox = gtk_hbox_new(FALSE, 1);
1681 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1682 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1683 gtk_widget_show(stat_hbox);
1685 prog_bar = gtk_progress_bar_new();
1686 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1687 gtk_widget_show(prog_bar);
1689 filter_bt = gtk_button_new_with_label("Filter:");
1690 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1691 GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1692 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1693 gtk_widget_show(filter_bt);
1695 filter_cm = gtk_combo_new();
1696 filter_list = g_list_append (filter_list, "");
1697 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1698 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1699 filter_te = GTK_COMBO(filter_cm)->entry;
1700 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1701 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1702 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1703 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1704 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1705 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1706 gtk_widget_show(filter_cm);
1708 filter_reset = gtk_button_new_with_label("Reset");
1709 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1710 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1711 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1712 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1713 gtk_widget_show(filter_reset);
1715 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1716 * of any widget that ends up calling a callback which needs
1717 * that text entry pointer */
1718 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1719 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1720 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1721 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1722 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1724 info_bar = gtk_statusbar_new();
1725 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1726 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1727 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1728 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1729 gtk_widget_show(info_bar);