3 * $Id: main.c,v 1.89 2000/01/15 10:50:23 oabad 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"
100 #include "prefs_dlg.h"
106 #include "simple_dialog.h"
107 #include "proto_draw.h"
110 #include "gtkglobals.h"
113 FILE *data_out_file = NULL;
116 GtkWidget *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
117 *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw,
118 *bv_vscroll_left, *bv_vscroll_right;
119 GdkFont *m_r_font, *m_b_font;
120 guint main_ctx, file_ctx;
121 gchar comp_info_str[256];
122 gchar *ethereal_path = NULL;
123 gchar *medium_font = MONO_MEDIUM_FONT;
124 gchar *bold_font = MONO_BOLD_FONT;
125 gchar *last_open_dir = NULL;
127 ts_type timestamp_type = RELATIVE;
129 GtkStyle *item_style;
131 /* Specifies the field currently selected in the GUI protocol tree */
132 field_info *finfo_selected = NULL;
134 static void follow_destroy_cb(GtkWidget *win, gpointer data);
135 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
136 static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
137 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
138 static char* hfinfo_numeric_format(header_field_info *hfinfo);
140 /* About Ethereal window */
142 about_ethereal( GtkWidget *w, gpointer data ) {
143 simple_dialog(ESD_TYPE_INFO, NULL,
144 "Ethereal - Network Protocol Analyzer\n"
145 "Version %s (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
146 "Compiled with %s\n\n"
148 "Check the man page for complete documentation and\n"
149 "for the list of contributors.\n"
151 "\nSee http://ethereal.zing.org/ for more information.",
152 VERSION, comp_info_str);
155 /* Follow the TCP stream, if any, to which the last packet that we called
156 a dissection routine on belongs (this might be the most recently
157 selected packet, or it might be the last packet in the file). */
159 follow_stream_cb( GtkWidget *w, gpointer data ) {
160 char filename1[128+1];
161 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
163 GtkWidget *hbox, *close_bt, *print_bt;
164 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
166 gchar *follow_filter;
168 if( pi.ipproto == 6 ) {
169 /* we got tcp so we can follow */
170 /* Create a temporary file into which to dump the reassembled data
171 from the TCP stream, and set "data_out_file" to refer to it, so
172 that the TCP code will write to it.
174 XXX - it might be nicer to just have the TCP code directly
175 append stuff to the text widget for the TCP stream window,
176 if we can arrange that said window not pop up until we're
178 tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
180 simple_dialog(ESD_TYPE_WARN, NULL,
181 "Could not create temporary file %s: %s", filename1, strerror(errno));
184 data_out_file = fdopen( tmp_fd, "w" );
185 if( data_out_file == NULL ) {
186 simple_dialog(ESD_TYPE_WARN, NULL,
187 "Could not create temporary file %s: %s", filename1, strerror(errno));
193 /* Create a new filter that matches all packets in the TCP stream,
194 and set the display filter entry accordingly */
195 reset_tcp_reassembly();
196 follow_filter = build_follow_filter( &pi );
198 /* set the display filter entry accordingly */
199 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
200 gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
202 /* Run the display filter so it goes in effect. */
203 filter_packets(&cf, follow_filter);
205 /* the data_out_file should now be full of the streams information */
206 fclose( data_out_file );
208 /* the filename1 file now has all the text that was in the session */
209 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
210 gtk_widget_set_name( streamwindow, "TCP stream window" );
212 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
213 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
214 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
215 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
217 if( incomplete_tcp_stream ) {
218 gtk_window_set_title( GTK_WINDOW(streamwindow),
219 "Contents of TCP stream (incomplete)" );
221 gtk_window_set_title( GTK_WINDOW(streamwindow),
222 "Contents of TCP stream" );
224 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
225 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
227 /* setup the container */
228 box = gtk_vbox_new( FALSE, 0 );
229 gtk_container_add( GTK_CONTAINER(streamwindow), box );
230 gtk_widget_show( box );
232 /* set up the table we attach to */
233 table = gtk_table_new( 1, 2, FALSE );
234 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
235 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
236 gtk_widget_show( table );
238 /* create a text box */
239 text = gtk_text_new( NULL, NULL );
240 gtk_text_set_editable( GTK_TEXT(text), FALSE);
241 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
242 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
243 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
244 gtk_widget_show(text);
247 hbox = gtk_hbox_new( FALSE, 1 );
248 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
249 gtk_widget_show(hbox);
251 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
252 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
253 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
255 /* Create Radio Buttons */
256 b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
257 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
258 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
259 gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
260 gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
261 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
262 GTK_OBJECT(streamwindow));
263 gtk_widget_show(b_ascii);
265 b_ebcdic = gtk_radio_button_new_with_label(
266 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
268 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
269 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
270 gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
271 gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
272 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
273 GTK_OBJECT(streamwindow));
274 gtk_widget_show(b_ebcdic);
276 b_hexdump = gtk_radio_button_new_with_label(
277 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
279 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
280 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
281 gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
282 gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
283 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
284 GTK_OBJECT(streamwindow));
285 gtk_widget_show(b_hexdump);
287 /* Create Close Button */
288 close_bt = gtk_button_new_with_label("Close");
289 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
290 GTK_SIGNAL_FUNC(gtk_widget_destroy),
291 GTK_OBJECT(streamwindow));
292 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
293 gtk_widget_show( close_bt );
295 /* Create Print Button */
296 print_bt = gtk_button_new_with_label("Print");
297 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
298 GTK_SIGNAL_FUNC(follow_print_stream),
299 GTK_OBJECT(streamwindow));
300 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
301 gtk_widget_show( print_bt );
303 /* create the scrollbar */
304 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
305 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
306 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
307 gtk_widget_show( vscrollbar );
308 gtk_widget_realize( text );
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;
321 gtk_widget_show( streamwindow );
323 simple_dialog(ESD_TYPE_WARN, NULL,
324 "Error following stream. Please make\n"
325 "sure you have a TCP packet selected.");
329 /* The destroy call back has the responsibility of
330 * unlinking the temporary file */
332 follow_destroy_cb(GtkWidget *win, gpointer data)
336 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
337 E_FOLLOW_FILENAME_KEY);
341 gtk_widget_destroy(win);
344 #define E_FOLLOW_ASCII_TYPE 0
345 #define E_FOLLOW_EBCDIC_TYPE 1
346 #define E_FOLLOW_HEXDUMP_TYPE 2
348 /* Handles the ASCII/EBCDIC toggling */
350 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
352 guint8 show_type = E_FOLLOW_ASCII_TYPE;
353 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
356 b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
358 b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
359 E_FOLLOW_EBCDIC_KEY);
360 b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
361 E_FOLLOW_HEXDUMP_KEY);
362 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
364 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
365 E_FOLLOW_FILENAME_KEY);
373 if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
374 show_type = E_FOLLOW_EBCDIC_TYPE;
375 else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
376 show_type = E_FOLLOW_HEXDUMP_TYPE;
378 follow_load_text(text, filename, show_type);
381 #define FLT_BUF_SIZE 1024
383 follow_read_stream(char *filename, guint8 show_type,
384 void (*print_line)(char *, int, gboolean, void *), void *arg)
388 guint32 client_addr = 0;
389 guint16 client_port = 0;
391 guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
394 data_out_file = fopen( filename, "r" );
395 if( data_out_file ) {
396 char buffer[FLT_BUF_SIZE];
398 while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
399 if (client_addr == 0) {
400 client_addr = sc.src_addr;
401 client_port = sc.src_port;
403 if (client_addr == sc.src_addr && client_port == sc.src_port) {
405 global_pos = &global_client_pos;
409 global_pos = &global_server_pos;
412 while (sc.dlen > 0) {
413 bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
414 nchars = fread( buffer, 1, bcount, data_out_file );
419 case E_FOLLOW_EBCDIC_TYPE:
420 /* If our native arch is ASCII, call: */
421 EBCDIC_to_ASCII(buffer, nchars);
422 case E_FOLLOW_ASCII_TYPE:
423 /* If our native arch is EBCDIC, call:
424 * ASCII_TO_EBCDIC(buffer, nchars);
426 (*print_line)( buffer, nchars, is_server, arg );
428 case E_FOLLOW_HEXDUMP_TYPE:
430 while (current_pos < nchars)
433 gchar hexchars[] = "0123456789abcdef";
435 /* is_server indentation : put 63 spaces at the begenning
437 sprintf(hexbuf, is_server ?
440 "%08X ", *global_pos);
441 cur = strlen(hexbuf);
442 for (i=0; i < 16 && current_pos+i < nchars; i++) {
443 hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
444 hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
446 hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
453 hexbuf[cur++] = '\n';
455 (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
461 if( ferror( data_out_file ) ) {
462 simple_dialog(ESD_TYPE_WARN, NULL,
463 "Error reading temporary file %s: %s", filename, strerror(errno));
465 fclose( data_out_file );
467 simple_dialog(ESD_TYPE_WARN, NULL,
468 "Could not open temporary file %s: %s", filename, strerror(errno));
473 * XXX - for text printing, we probably want to wrap lines at 80 characters;
474 * for PostScript printing, we probably want to wrap them at the appropriate
475 * width, and perhaps put some kind of dingbat (to use the technical term)
476 * to indicate a wrapped line, along the lines of what's done when displaying
477 * this in a window, as per Warren Young's suggestion.
479 * For now, we support only text printing.
482 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
486 fwrite(buffer, nchars, 1, fh);
490 follow_print_stream(GtkWidget *w, gpointer parent_w)
496 guint8 show_type = E_FOLLOW_ASCII_TYPE;
499 switch (prefs.pr_dest) {
501 print_dest = prefs.pr_cmd;
506 print_dest = prefs.pr_file;
509 default: /* "Can't happen" */
510 simple_dialog(ESD_TYPE_WARN, NULL,
511 "Couldn't figure out where to send the print "
512 "job. Check your preferences.");
516 fh = open_print_dest(to_file, print_dest);
520 simple_dialog(ESD_TYPE_WARN, NULL,
521 "Couldn't run print command %s.", prefs.pr_cmd);
525 simple_dialog(ESD_TYPE_WARN, NULL,
526 file_write_error_message(errno),
533 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
534 E_FOLLOW_EBCDIC_KEY);
535 if (GTK_TOGGLE_BUTTON(button)->active)
536 show_type = E_FOLLOW_EBCDIC_TYPE;
537 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
538 E_FOLLOW_HEXDUMP_KEY);
539 if (GTK_TOGGLE_BUTTON(button)->active)
540 show_type = E_FOLLOW_HEXDUMP_TYPE;
542 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
543 E_FOLLOW_FILENAME_KEY);
545 if (filename != NULL) {
546 print_preamble(fh, PR_FMT_TEXT);
547 follow_read_stream(filename, show_type, follow_print_text, fh);
548 print_finale(fh, PR_FMT_TEXT);
549 close_print_dest(to_file, fh);
552 simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
557 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
559 GtkWidget *text = arg;
562 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
563 &prefs.st_server_bg, buffer, nchars );
565 gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
566 &prefs.st_client_bg, buffer, nchars );
570 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
574 /* Delete any info already in text box */
575 bytes_already = gtk_text_get_length(GTK_TEXT(text));
576 if (bytes_already > 0) {
577 gtk_text_set_point(GTK_TEXT(text), 0);
578 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
581 /* stop the updates while we fill the text box */
582 gtk_text_freeze( GTK_TEXT(text) );
583 follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
584 gtk_text_thaw( GTK_TEXT(text) );
587 /* Match selected byte pattern */
589 match_selected_cb(GtkWidget *w, gpointer data)
592 GtkWidget *filter_te;
593 char *ptr, *format, *stringified;
594 int i, dfilter_len, abbrev_len;
596 header_field_info *hfinfo;
598 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
600 if (!finfo_selected) {
601 simple_dialog(ESD_TYPE_WARN, NULL,
602 "Error determining selected bytes. Please make\n"
603 "sure you have selected a field within the tree\n"
604 "view to be matched.");
608 hfinfo = finfo_selected->hfinfo;
610 abbrev_len = strlen(hfinfo->abbrev);
612 switch(hfinfo->type) {
615 dfilter_len = abbrev_len + 2;
616 buf = g_malloc0(dfilter_len);
617 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
629 dfilter_len = abbrev_len + 20;
630 buf = g_malloc0(dfilter_len);
631 format = hfinfo_numeric_format(hfinfo);
632 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
636 dfilter_len = abbrev_len + 4 + 15 + 1;
637 buf = g_malloc0(dfilter_len);
638 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
639 ipv4_addr_str(&(finfo_selected->value.ipv4)));
643 dfilter_len = abbrev_len + 15;
644 buf = g_malloc0(dfilter_len);
645 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
646 finfo_selected->value.numeric);
650 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
651 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
652 buf = g_malloc0(dfilter_len);
653 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
658 dfilter_len = abbrev_len + 30;
659 buf = g_malloc0(dfilter_len);
660 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
661 finfo_selected->value.floating);
665 dfilter_len = abbrev_len + 22;
666 buf = g_malloc0(dfilter_len);
667 snprintf(buf, dfilter_len, "%s == %s",
669 ether_to_str(finfo_selected->value.ether));
673 case FT_ABSOLUTE_TIME:
674 case FT_RELATIVE_TIME:
675 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
676 sizeof(struct timeval));
680 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
681 fi->value.string = g_strdup(va_arg(ap, char*));
689 c = cf.pd + finfo_selected->start;
690 buf = g_malloc0(32 + finfo_selected->length * 3);
693 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
694 ptr = buf+strlen(buf);
696 if (finfo_selected->length == 1) {
697 sprintf(ptr, "0x%02x", *c++);
700 for (i=0;i<finfo_selected->length; i++) {
702 sprintf(ptr, "%02x", *c++);
705 sprintf(ptr, ":%02x", *c++);
707 ptr = buf+strlen(buf);
713 /* create a new one and set the display filter entry accordingly */
714 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
716 /* Run the display filter so it goes in effect. */
717 filter_packets(&cf, buf);
719 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
723 hfinfo_numeric_format(header_field_info *hfinfo)
727 /* Pick the proper format string */
728 switch(hfinfo->display) {
731 case BASE_OCT: /* I'm lazy */
732 case BASE_BIN: /* I'm lazy */
733 switch(hfinfo->type) {
747 g_assert_not_reached();
752 switch(hfinfo->type) {
754 format = "%s == 0x%02x";
757 format = "%s == 0x%04x";
760 format = "%s == 0x%06x";
763 format = "%s == 0x%08x";
766 g_assert_not_reached();
771 g_assert_not_reached();
778 /* Run the current display filter on the current packet set, and
781 filter_activate_cb(GtkWidget *w, gpointer data)
783 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
784 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
785 GList *li, *nl = NULL;
786 gboolean add_filter = TRUE;
788 char *s = gtk_entry_get_text(GTK_ENTRY(w));
790 /* GtkCombos don't let us get at their list contents easily, so we maintain
791 our own filter list, and feed it to gtk_combo_set_popdown_strings when
792 a new filter is added. */
793 if (filter_packets(&cf, g_strdup(s))) {
794 li = g_list_first(filter_list);
796 if (li->data && strcmp(s, li->data) == 0)
802 filter_list = g_list_append(filter_list, g_strdup(s));
803 li = g_list_first(filter_list);
805 nl = g_list_append(nl, strdup(li->data));
808 gtk_combo_set_popdown_strings(filter_cm, nl);
809 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
814 /* redisplay with no display filter */
816 filter_reset_cb(GtkWidget *w, gpointer data)
818 GtkWidget *filter_te = NULL;
820 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
821 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
824 filter_packets(&cf, NULL);
827 /* What to do when a list item is selected/unselected */
829 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
840 select_packet(&cf, row);
844 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
845 unselect_packet(&cf);
849 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
852 int tree_selected_start = -1;
853 int tree_selected_len = -1;
856 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
859 finfo_selected = finfo;
860 tree_selected_start = finfo->start;
861 tree_selected_len = finfo->length;
863 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
864 tree_selected_start, tree_selected_len, cf.current_frame->encoding);
868 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
870 finfo_selected = NULL;
871 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
872 -1, -1, cf.current_frame->encoding);
875 void collapse_all_cb(GtkWidget *widget, gpointer data) {
876 if (cf.protocol_tree)
877 collapse_all_tree(cf.protocol_tree, tree_view);
880 void expand_all_cb(GtkWidget *widget, gpointer data) {
881 if (cf.protocol_tree)
882 expand_all_tree(cf.protocol_tree, tree_view);
886 set_scrollbar_placement(int pos) /* 0=left, 1=right */
889 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
890 GTK_CORNER_TOP_LEFT );
891 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
892 GTK_CORNER_TOP_LEFT );
893 gtk_widget_hide(bv_vscroll_left);
894 gtk_widget_show(bv_vscroll_right);
897 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
898 GTK_CORNER_TOP_RIGHT );
899 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
900 GTK_CORNER_TOP_RIGHT );
901 gtk_widget_hide(bv_vscroll_right);
902 gtk_widget_show(bv_vscroll_left);
907 set_plist_sel_browse(gboolean val)
910 unselect_packet(&cf);
912 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
913 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
915 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
918 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
923 set_ptree_sel_browse(gboolean val)
925 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
926 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
928 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
931 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
936 set_ptree_line_style(gint style)
938 /* I'm using an assert here since the preferences code limits
939 * the user input, both in the GUI and when reading the preferences file.
940 * If the value is incorrect, it's a program error, not a user-initiated error.
942 g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
943 gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
947 set_ptree_expander_style(gint style)
949 /* I'm using an assert here since the preferences code limits
950 * the user input, both in the GUI and when reading the preferences file.
951 * If the value is incorrect, it's a program error, not a user-initiated error.
953 g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
954 gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
959 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
960 /* If we have a capture file open, and it's a temporary file,
962 if (cf.filename != NULL && cf.is_tempfile)
967 /* call initialization routines at program startup time */
969 ethereal_proto_init(void) {
980 ethereal_proto_cleanup(void) {
988 fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
989 VERSION, comp_info_str);
991 fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
993 fprintf(stderr, " [-f <capture filter>] [-i interface] [-m <medium font>] [-n]\n");
994 fprintf(stderr, " [-P <packet list height>] [-r infile] [-R <read filter>]\n");
995 fprintf(stderr, " [-s snaplen] [-t <time stamp format>] [-T <tree view height>]\n");
996 fprintf(stderr, " [-w savefile]\n");
998 fprintf(stderr, "%s [-vh] [-b <bold font>] [-B <byte view height>] [-m <medium font>]\n",
1000 fprintf(stderr, " [-n] [-P <packet list height>] [-r infile] [-R <read filter>]\n");
1001 fprintf(stderr, " [-t <time stamp format>] [-T <tree view height>]\n");
1005 /* And now our feature presentation... [ fade to music ] */
1007 main(int argc, char *argv[])
1016 extern char *optarg;
1017 gboolean arg_error = FALSE;
1020 extern char pcap_version[];
1023 int pf_open_errno = 0;
1026 gboolean start_capture = FALSE;
1027 gchar *save_file = NULL;
1028 gchar err_str[PCAP_ERRBUF_SIZE];
1030 gboolean capture_option_specified = FALSE;
1032 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1033 *bv_table, *stat_hbox,
1034 *filter_bt, *filter_cm, *filter_te,
1036 GList *filter_list = NULL;
1038 GtkAccelGroup *accel;
1039 gint pl_size = 280, tv_size = 95, bv_size = 75;
1040 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1041 dfilter *rfcode = NULL;
1042 gboolean rfilter_parse_failed = FALSE;
1045 ethereal_path = argv[0];
1048 command_name = strrchr(ethereal_path, '/');
1049 if (command_name == NULL)
1050 command_name = ethereal_path;
1053 /* Set "capture_child" to indicate whether this is going to be a child
1054 process for a "-S" capture. */
1055 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1058 /* If invoked with the "-G" flag, we dump out a glossary of
1059 display filter symbols.
1061 We must do this before calling "gtk_init()", because "gtk_init()"
1062 tries to open an X display, and we don't want to have to do any X
1063 stuff just to do a build.
1065 Given that we call "gtk_init()" before doing the regular argument
1066 list processing, so that it can handle X and GTK+ arguments and
1067 remove them from the list at which we look, this means we must do
1068 this before doing the regular argument list processing, as well.
1072 you must give the "-G" flag as the first flag on the command line;
1074 you must give it as "-G", nothing more, nothing less;
1076 any arguments after the "-G" flag will not be used. */
1077 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1078 ethereal_proto_init();
1079 proto_registrar_dump();
1083 /* Let GTK get its args */
1084 gtk_init (&argc, &argv);
1086 prefs = read_prefs(&pf_path);
1087 if (pf_path != NULL) {
1088 /* The preferences file exists, but couldn't be opened; "pf_path" is
1089 its pathname. Remember "errno", as that says why the attempt
1091 pf_open_errno = errno;
1094 /* Initialize the capture file struct */
1096 cf.plist_end = NULL;
1100 cf.user_saved = FALSE;
1101 cf.is_tempfile = FALSE;
1106 cf.cfilter = g_strdup(EMPTY_FILTER);
1109 cf.save_file = NULL;
1110 cf.save_file_fd = -1;
1111 cf.snap = WTAP_MAX_PACKET_SIZE;
1113 cf.cinfo.num_cols = prefs->num_cols;
1114 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1115 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1116 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1117 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1118 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1120 /* Assemble the compile-time options */
1121 snprintf(comp_info_str, 256,
1122 #ifdef GTK_MAJOR_VERSION
1123 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1126 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1130 "with libpcap ", pcap_version,
1132 "without libpcap", "",
1137 "with libz ", ZLIB_VERSION,
1138 #else /* ZLIB_VERSION */
1139 "with libz ", "(version unknown)",
1140 #endif /* ZLIB_VERSION */
1141 #else /* HAVE_LIBZ */
1143 #endif /* HAVE_LIBZ */
1145 /* Oh, this is pretty */
1146 #if defined(HAVE_UCD_SNMP_SNMP_H)
1147 #ifdef HAVE_UCD_SNMP_VERSION_H
1148 "with UCD SNMP ", VersionInfo
1149 #else /* HAVE_UCD_SNMP_VERSION_H */
1150 "with UCD SNMP ", "(version unknown)"
1151 #endif /* HAVE_UCD_SNMP_VERSION_H */
1152 #elif defined(HAVE_SNMP_SNMP_H)
1153 #ifdef HAVE_SNMP_VERSION_H
1154 "with CMU SNMP ", snmp_Version()
1155 #else /* HAVE_SNMP_VERSION_H */
1156 "with CMU SNMP ", "(version unknown)"
1157 #endif /* HAVE_SNMP_VERSION_H */
1164 /* Now get our args */
1165 while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1167 case 'b': /* Bold font */
1168 bold_font = g_strdup(optarg);
1170 case 'B': /* Byte view pane height */
1171 bv_size = atoi(optarg);
1173 case 'c': /* Capture xxx packets */
1175 cf.count = atoi(optarg);
1177 capture_option_specified = TRUE;
1185 cf.cfilter = g_strdup(optarg);
1187 capture_option_specified = TRUE;
1191 case 'h': /* Print help and exit */
1195 case 'i': /* Use interface xxx */
1197 cf.iface = g_strdup(optarg);
1199 capture_option_specified = TRUE;
1203 case 'k': /* Start capture immediately */
1205 start_capture = TRUE;
1207 capture_option_specified = TRUE;
1211 case 'm': /* Medium font */
1212 medium_font = g_strdup(optarg);
1214 case 'n': /* No name resolution */
1215 g_resolving_actif = 0;
1217 case 'P': /* Packet list pane height */
1218 pl_size = atoi(optarg);
1220 case 'Q': /* Quit after capture (just capture to file) */
1223 start_capture = TRUE; /*** -Q implies -k !! ***/
1225 capture_option_specified = TRUE;
1229 case 'r': /* Read capture file xxx */
1230 /* We may set "last_open_dir" to "cf_name", and if we change
1231 "last_open_dir" later, we free the old value, so we have to
1232 set "cf_name" to something that's been allocated. */
1233 cf_name = g_strdup(optarg);
1235 case 'R': /* Read file filter */
1238 case 's': /* Set the snapshot (capture) length */
1240 cf.snap = atoi(optarg);
1242 capture_option_specified = TRUE;
1246 case 'S': /* "Sync" mode: used for following file ala tail -f */
1250 capture_option_specified = TRUE;
1254 case 't': /* Time stamp type */
1255 if (strcmp(optarg, "r") == 0)
1256 timestamp_type = RELATIVE;
1257 else if (strcmp(optarg, "a") == 0)
1258 timestamp_type = ABSOLUTE;
1259 else if (strcmp(optarg, "d") == 0)
1260 timestamp_type = DELTA;
1262 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1264 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1265 fprintf(stderr, "or \"d\" for delta.\n");
1269 case 'T': /* Tree view pane height */
1270 tv_size = atoi(optarg);
1272 case 'v': /* Show version and exit */
1273 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1276 case 'w': /* Write to capture file xxx */
1278 save_file = g_strdup(optarg);
1280 capture_option_specified = TRUE;
1284 case 'W': /* Write to capture file FD xxx */
1286 cf.save_file_fd = atoi(optarg);
1288 capture_option_specified = TRUE;
1293 case '?': /* Bad flag - print usage message */
1300 #ifndef HAVE_LIBPCAP
1301 if (capture_option_specified)
1302 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1309 if (start_capture) {
1310 /* We're supposed to do a live capture; did the user specify an interface
1312 if (cf.iface == NULL) {
1313 /* No - have libpcap pick one. */
1314 cf.iface = pcap_lookupdev(err_str);
1315 if (cf.iface == NULL) {
1316 /* It couldn't pick one. */
1317 fprintf(stderr, "ethereal: %s\n", err_str);
1322 if (capture_child) {
1323 if (cf.save_file_fd == -1) {
1324 /* XXX - send this to the standard output as something our parent
1325 should put in an error message box? */
1326 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1332 /* Build the column format array */
1333 for (i = 0; i < cf.cinfo.num_cols; i++) {
1334 cf.cinfo.col_fmt[i] = get_column_format(i);
1335 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1336 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1338 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1339 if (cf.cinfo.col_fmt[i] == COL_INFO)
1340 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1342 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1346 cf.snap = WTAP_MAX_PACKET_SIZE;
1347 else if (cf.snap < MIN_PACKET_SIZE)
1348 cf.snap = MIN_PACKET_SIZE;
1350 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1351 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1352 gtk_rc_parse(rc_file);
1354 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1355 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1359 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1360 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1365 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1366 gtk_widget_set_name(top_level, "main window");
1367 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1368 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1369 gtk_signal_connect(GTK_OBJECT(top_level), "destroy",
1370 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1371 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1372 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1373 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1375 /* Container for menu bar, paned windows and progress/info box */
1376 main_vbox = gtk_vbox_new(FALSE, 1);
1377 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1378 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1379 gtk_widget_show(main_vbox);
1382 get_main_menu(&menubar, &accel);
1383 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1384 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1385 gtk_widget_show(menubar);
1387 /* Panes for the packet list, tree, and byte view */
1388 u_pane = gtk_vpaned_new();
1389 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1390 l_pane = gtk_vpaned_new();
1391 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1392 gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
1393 gtk_widget_show(u_pane);
1394 gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
1395 gtk_widget_show(l_pane);
1398 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1399 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1400 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1401 gtk_widget_show(pkt_scrollw);
1402 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1404 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1405 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1406 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1407 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1408 pl_style = gtk_style_new();
1409 gdk_font_unref(pl_style->font);
1410 pl_style->font = m_r_font;
1411 gtk_widget_set_style(packet_list, pl_style);
1412 gtk_widget_set_name(packet_list, "packet list");
1413 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1414 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1415 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1416 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1417 for (i = 0; i < cf.cinfo.num_cols; i++) {
1418 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1419 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1421 /* Right-justify the packet number column. */
1422 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1423 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1426 /* Save static column sizes to use during a "-S" capture, so that
1427 the columns don't resize during a live capture. */
1428 cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1429 get_column_longest_string(get_column_format(i)));
1431 gtk_widget_set_usize(packet_list, -1, pl_size);
1432 gtk_widget_show(packet_list);
1435 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1436 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1437 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1438 gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
1439 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1440 gtk_widget_show(tv_scrollw);
1442 tree_view = gtk_ctree_new(1, 0);
1443 /* I need this next line to make the widget work correctly with hidden
1444 * column titles and GTK_SELECTION_BROWSE */
1445 gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1446 gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1447 set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
1448 set_ptree_line_style(prefs->gui_ptree_line_style);
1449 set_ptree_expander_style(prefs->gui_ptree_expander_style);
1451 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1452 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1453 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1454 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1455 gtk_widget_show(tree_view);
1457 item_style = gtk_style_new();
1458 gdk_font_unref(item_style->font);
1459 item_style->font = m_r_font;
1461 /* Byte view. The table is only one row high, but 3 columns
1462 * wide. The middle column contains the GtkText with the hex dump.
1463 * The left and right columns contain vertical scrollbars. They both
1464 * do the same thing, but only one will be shown at a time, in accordance
1465 * with where the user wants the other vertical scrollbars places
1466 * (on the left or the right).
1468 bv_table = gtk_table_new (1, 3, FALSE);
1469 gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
1470 gtk_widget_set_usize(bv_table, -1, bv_size);
1471 gtk_widget_show(bv_table);
1473 byte_view = gtk_text_new(NULL, NULL);
1474 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1475 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1476 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
1477 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1478 gtk_widget_show(byte_view);
1480 /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
1481 * in the GTK+ distribution, so I removed the horizontal scroll bar
1482 * that used to be here. I tried the gtk_text widget with a
1483 * gtk_scrolled_window w/ viewport, but the vertical scrollowing
1484 * did not work well, and sometimes a few pixels were cut off on
1487 bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1488 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
1489 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1491 bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1492 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
1493 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1495 /* Now that the 3 panes are created, set the vertical scrollbar
1496 * on the left or right according to the user's preference */
1497 set_scrollbar_placement(prefs->gui_scrollbar_on_right);
1499 /* Progress/filter/info box */
1500 stat_hbox = gtk_hbox_new(FALSE, 1);
1501 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1502 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1503 gtk_widget_show(stat_hbox);
1505 prog_bar = gtk_progress_bar_new();
1506 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1507 gtk_widget_show(prog_bar);
1509 filter_bt = gtk_button_new_with_label("Filter:");
1510 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1511 GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
1512 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1513 gtk_widget_show(filter_bt);
1515 filter_cm = gtk_combo_new();
1516 filter_list = g_list_append (filter_list, "");
1517 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1518 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1519 filter_te = GTK_COMBO(filter_cm)->entry;
1520 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1521 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1522 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1523 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1524 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1525 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1526 gtk_widget_show(filter_cm);
1528 filter_reset = gtk_button_new_with_label("Reset");
1529 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1530 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1531 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1532 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1533 gtk_widget_show(filter_reset);
1535 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1536 * of any widget that ends up calling a callback which needs
1537 * that text entry pointer */
1538 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1539 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1540 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1541 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1542 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1544 info_bar = gtk_statusbar_new();
1545 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1546 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1547 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1548 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1549 gtk_widget_show(info_bar);
1552 Hmmm should we do it here
1555 ethereal_proto_init(); /* Init anything that needs initializing */
1558 /* Is this a "child" ethereal, which is only supposed to pop up a
1559 capture box to let us stop the capture, and run a capture
1560 to a file that our parent will read? */
1561 if (!capture_child) {
1563 /* No. Pop up the main window, and read in a capture file if
1566 gtk_widget_show(top_level);
1568 cf.colors = colfilter_new();
1570 /* If we were given the name of a capture file, read it in now;
1571 we defer it until now, so that, if we can't open it, and pop
1572 up an alert box, the alert box is more likely to come up on
1573 top of the main window - but before the preference-file-error
1574 alert box, so, if we get one of those, it's more likely to come
1577 if (rfilter != NULL) {
1578 if (dfilter_compile(rfilter, &rfcode) != 0) {
1579 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1580 rfilter_parse_failed = TRUE;
1583 if (!rfilter_parse_failed) {
1584 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1585 /* "open_cap_file()" succeeded, so it closed the previous
1586 capture file, and thus destroyed any previous read filter
1587 attached to "cf". */
1589 err = read_cap_file(&cf);
1590 s = strrchr(cf_name, '/');
1592 last_open_dir = cf_name;
1596 dfilter_destroy(rfcode);
1605 /* If we failed to open the preferences file, pop up an alert box;
1606 we defer it until now, so that the alert box is more likely to
1607 come up on top of the main window. */
1608 if (pf_path != NULL) {
1609 simple_dialog(ESD_TYPE_WARN, NULL,
1610 "Could not open preferences file\n\"%s\": %s.", pf_path,
1611 strerror(pf_open_errno));
1615 if (capture_child) {
1616 /* This is the child process for a sync mode or fork mode capture,
1617 so just do the low-level work of a capture - don't create
1618 a temporary file and fork off *another* child process (so don't
1619 call "do_capture()"). */
1623 /* The capture is done; there's nothing more for us to do. */
1626 if (start_capture) {
1627 /* "-k" was specified; start a capture. */
1628 do_capture(save_file);
1635 ethereal_proto_cleanup();