3 * $Id: main.c,v 1.123 2000/06/27 04:36:01 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, "wb" );
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(&cfile, 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, "rb" );
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 = cfile.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(&cfile, 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(&cfile, 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(&cfile, NULL);
833 /* GTKClist compare routine, overrides default to allow numeric comparison */
835 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
837 /* Get row text strings */
838 char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
839 char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
841 /* Attempt to convert to numbers */
842 double num1 = atof(text1);
843 double num2 = atof(text2);
845 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
847 if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
848 ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
849 ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
850 (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
851 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
852 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
853 (col_fmt == COL_PACKET_LENGTH)) {
855 /* Compare numeric column */
859 else if (num1 > num2)
867 /* Compare text column */
869 return (text1 != NULL);
874 return strcmp(text1, text2);
878 /* What to do when a column is clicked */
880 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
882 if (column == clist->sort_column) {
883 if (clist->sort_type == GTK_SORT_ASCENDING)
884 clist->sort_type = GTK_SORT_DESCENDING;
886 clist->sort_type = GTK_SORT_ASCENDING;
889 clist->sort_type = GTK_SORT_ASCENDING;
890 gtk_clist_set_sort_column(clist, column);
893 gtk_clist_sort(clist);
896 /* What to do when a list item is selected/unselected */
898 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
901 select_packet(&cfile, row);
905 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
906 unselect_packet(&cfile);
910 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
915 finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
918 finfo_selected = finfo;
920 packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame->cap_len,
921 finfo->start, finfo->length, cfile.current_frame->flags.encoding);
925 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
927 finfo_selected = NULL;
928 packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame->cap_len,
929 -1, -1, cfile.current_frame->flags.encoding);
932 void collapse_all_cb(GtkWidget *widget, gpointer data) {
933 if (cfile.protocol_tree)
934 collapse_all_tree(cfile.protocol_tree, tree_view);
937 void expand_all_cb(GtkWidget *widget, gpointer data) {
938 if (cfile.protocol_tree)
939 expand_all_tree(cfile.protocol_tree, tree_view);
942 void resolve_name_cb(GtkWidget *widget, gpointer data) {
943 if (cfile.protocol_tree) {
944 int tmp = g_resolving_actif;
945 g_resolving_actif = 1;
946 gtk_clist_clear ( GTK_CLIST(tree_view) );
947 proto_tree_draw(cfile.protocol_tree, tree_view);
948 g_resolving_actif = tmp;
952 /* Set the scrollbar placement of a scrolled window based upon pos value:
953 0 = left, 1 = right */
955 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
958 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
959 GTK_CORNER_TOP_LEFT);
961 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
962 GTK_CORNER_TOP_RIGHT);
966 /* List of all scrolled windows, so we can globally set the scrollbar
967 placement of them. */
968 static GList *scrolled_windows;
970 /* Add a scrolled window to the list of scrolled windows. */
972 remember_scrolled_window(GtkWidget *scrollw)
974 scrolled_windows = g_list_append(scrolled_windows, scrollw);
977 /* Remove a scrolled window from the list of scrolled windows. */
979 forget_scrolled_window(GtkWidget *scrollw)
981 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
985 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
987 set_scrollbar_placement_scrollw((GtkWidget *)data,
991 /* Set the scrollbar placement of all scrolled windows based on pos value:
992 0 = left, 1 = right */
994 set_scrollbar_placement_all(int pos)
996 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
999 /* Set the selection mode of the packet list window. */
1001 set_plist_sel_browse(gboolean val)
1004 unselect_packet(&cfile);
1006 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
1007 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
1009 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
1012 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
1016 /* Set the selection mode of a given packet tree window. */
1018 set_ptree_sel_browse(GtkWidget *tv, gboolean val)
1020 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
1021 * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
1023 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_SINGLE);
1026 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_BROWSE);
1030 /* Set the selection mode of all packet tree windows. */
1032 set_ptree_sel_browse_all(gboolean val)
1034 set_ptree_sel_browse(tree_view, val);
1035 set_ptree_sel_browse_packet_wins(val);
1038 /* Set the line style of a given packet tree window. */
1040 set_ptree_line_style(GtkWidget *tv, gint style)
1042 /* I'm using an assert here since the preferences code limits
1043 * the user input, both in the GUI and when reading the preferences file.
1044 * If the value is incorrect, it's a program error, not a user-initiated error.
1046 g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
1047 gtk_ctree_set_line_style( GTK_CTREE(tv), style );
1050 /* Set the line style of all packet tree window. */
1052 set_ptree_line_style_all(gint style)
1054 set_ptree_line_style(tree_view, style);
1055 set_ptree_line_style_packet_wins(style);
1058 /* Set the expander style of a given packet tree window. */
1060 set_ptree_expander_style(GtkWidget *tv, gint style)
1062 /* I'm using an assert here since the preferences code limits
1063 * the user input, both in the GUI and when reading the preferences file.
1064 * If the value is incorrect, it's a program error, not a user-initiated error.
1066 g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
1067 gtk_ctree_set_expander_style( GTK_CTREE(tv), style );
1071 set_ptree_expander_style_all(gint style)
1073 set_ptree_expander_style(tree_view, style);
1074 set_ptree_expander_style_packet_wins(style);
1078 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
1080 file_quit_cmd_cb(widget, data);
1082 /* Say that the window should be deleted. */
1087 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
1089 /* XXX - should we check whether the capture file is an
1090 unsaved temporary file for a live capture and, if so,
1091 pop up a "do you want to exit without saving the capture
1092 file?" dialog, and then just return, leaving said dialog
1093 box to forcibly quit if the user clicks "OK"?
1095 If so, note that this should be done in a subroutine that
1096 returns TRUE if we do so, and FALSE otherwise, and that
1097 "main_window_delete_event_cb()" should return its
1100 /* Close any capture file we have open; on some OSes, you can't
1101 unlink a temporary capture file if you have it open.
1102 "close_cap_file()" will unlink it after closing it if
1103 it's a temporary file.
1105 We do this here, rather than after the main loop returns,
1106 as, after the main loop returns, the main window may have
1107 been destroyed (if this is called due to a "destroy"
1108 even on the main window rather than due to the user
1109 selecting a menu item), and there may be a crash
1110 or other problem when "close_cap_file()" tries to
1111 clean up stuff in the main window.
1113 XXX - is there a better place to put this?
1114 Or should we have a routine that *just* closes the
1115 capture file, and doesn't do anything with the UI,
1116 which we'd call here, and another routine that
1117 calls that routine and also cleans up the UI, which
1118 we'd call elsewhere? */
1119 close_cap_file(&cfile, info_bar);
1121 fprintf( stderr, "file_quit_cmd_cb: About to call gtk_main_quit()\n");
1122 /* Exit by leaving the main loop, so that any quit functions
1123 we registered get called. */
1130 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1133 fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1135 fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1136 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1137 fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1138 fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1140 fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1142 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1143 fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1144 fprintf(stderr, "\t[ -T <tree view height> ]\n");
1148 /* And now our feature presentation... [ fade to music ] */
1150 main(int argc, char *argv[])
1158 extern char *optarg;
1159 gboolean arg_error = FALSE;
1162 char pcap_version[] = "0.4a6";
1164 extern char pcap_version[];
1168 int pf_open_errno = 0;
1171 gboolean start_capture = FALSE;
1172 gchar *save_file = NULL;
1174 gchar err_str[PCAP_ERRBUF_SIZE];
1176 gboolean capture_option_specified = FALSE;
1178 gint pl_size = 280, tv_size = 95, bv_size = 75;
1179 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1180 dfilter *rfcode = NULL;
1181 gboolean rfilter_parse_failed = FALSE;
1184 ethereal_path = argv[0];
1187 command_name = get_basename(ethereal_path);
1188 /* Set "capture_child" to indicate whether this is going to be a child
1189 process for a "-S" capture. */
1190 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1193 /* If invoked with the "-G" flag, we dump out a glossary of
1194 display filter symbols.
1196 We must do this before calling "gtk_init()", because "gtk_init()"
1197 tries to open an X display, and we don't want to have to do any X
1198 stuff just to do a build.
1200 Given that we call "gtk_init()" before doing the regular argument
1201 list processing, so that it can handle X and GTK+ arguments and
1202 remove them from the list at which we look, this means we must do
1203 this before doing the regular argument list processing, as well.
1207 you must give the "-G" flag as the first flag on the command line;
1209 you must give it as "-G", nothing more, nothing less;
1211 any arguments after the "-G" flag will not be used. */
1212 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1214 proto_registrar_dump();
1218 /* Set the current locale according to the program environment.
1219 * We haven't localized anything, but some GTK widgets are localized
1220 * (the file selection dialogue, for example) */
1223 /* Let GTK get its args */
1224 gtk_init (&argc, &argv);
1226 prefs = read_prefs(&pf_path);
1227 if (pf_path != NULL) {
1228 /* The preferences file exists, but couldn't be opened; "pf_path" is
1229 its pathname. Remember "errno", as that says why the attempt
1231 pf_open_errno = errno;
1234 /* Initialize the capture file struct */
1236 cfile.plist_end = NULL;
1238 cfile.filename = NULL;
1239 cfile.user_saved = FALSE;
1240 cfile.is_tempfile = FALSE;
1241 cfile.rfcode = NULL;
1242 cfile.dfilter = NULL;
1243 cfile.dfcode = NULL;
1245 cfile.cfilter = g_strdup(EMPTY_FILTER);
1248 cfile.save_file = NULL;
1249 cfile.save_file_fd = -1;
1250 cfile.snap = WTAP_MAX_PACKET_SIZE;
1252 cfile.cinfo.num_cols = prefs->num_cols;
1253 cfile.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
1254 cfile.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cfile.cinfo.num_cols);
1255 cfile.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
1256 cfile.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
1257 cfile.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
1259 /* Assemble the compile-time options */
1260 snprintf(comp_info_str, 256,
1261 #ifdef GTK_MAJOR_VERSION
1262 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1265 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1269 "with libpcap ", pcap_version,
1271 "without libpcap", "",
1276 "with libz ", ZLIB_VERSION,
1277 #else /* ZLIB_VERSION */
1278 "with libz ", "(version unknown)",
1279 #endif /* ZLIB_VERSION */
1280 #else /* HAVE_LIBZ */
1282 #endif /* HAVE_LIBZ */
1284 /* Oh, this is pretty */
1285 #if defined(HAVE_UCD_SNMP_SNMP_H)
1286 #ifdef HAVE_UCD_SNMP_VERSION_H
1287 "with UCD SNMP ", VersionInfo
1288 #else /* HAVE_UCD_SNMP_VERSION_H */
1289 "with UCD SNMP ", "(version unknown)"
1290 #endif /* HAVE_UCD_SNMP_VERSION_H */
1291 #elif defined(HAVE_SNMP_SNMP_H)
1292 #ifdef HAVE_SNMP_VERSION_H
1293 "with CMU SNMP ", snmp_Version()
1294 #else /* HAVE_SNMP_VERSION_H */
1295 "with CMU SNMP ", "(version unknown)"
1296 #endif /* HAVE_SNMP_VERSION_H */
1302 /* Now get our args */
1303 while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
1305 case 'b': /* Bold font */
1306 bold_font = g_strdup(optarg);
1308 case 'B': /* Byte view pane height */
1309 bv_size = atoi(optarg);
1311 case 'c': /* Capture xxx packets */
1313 cfile.count = atoi(optarg);
1315 capture_option_specified = TRUE;
1319 case 'D': /* Turn off DSCP printing */
1320 g_ip_dscp_actif = FALSE;
1325 g_free(cfile.cfilter);
1326 cfile.cfilter = g_strdup(optarg);
1328 capture_option_specified = TRUE;
1332 case 'h': /* Print help and exit */
1336 case 'i': /* Use interface xxx */
1338 cfile.iface = g_strdup(optarg);
1340 capture_option_specified = TRUE;
1344 case 'k': /* Start capture immediately */
1346 start_capture = TRUE;
1348 capture_option_specified = TRUE;
1352 case 'm': /* Medium font */
1353 medium_font = g_strdup(optarg);
1355 case 'n': /* No name resolution */
1356 g_resolving_actif = 0;
1358 case 'P': /* Packet list pane height */
1359 pl_size = atoi(optarg);
1361 case 'Q': /* Quit after capture (just capture to file) */
1364 start_capture = TRUE; /*** -Q implies -k !! ***/
1366 capture_option_specified = TRUE;
1370 case 'r': /* Read capture file xxx */
1371 /* We may set "last_open_dir" to "cf_name", and if we change
1372 "last_open_dir" later, we free the old value, so we have to
1373 set "cf_name" to something that's been allocated. */
1374 cf_name = g_strdup(optarg);
1376 case 'R': /* Read file filter */
1379 case 's': /* Set the snapshot (capture) length */
1381 cfile.snap = atoi(optarg);
1383 capture_option_specified = TRUE;
1387 case 'S': /* "Sync" mode: used for following file ala tail -f */
1391 capture_option_specified = TRUE;
1395 case 't': /* Time stamp type */
1396 if (strcmp(optarg, "r") == 0)
1397 timestamp_type = RELATIVE;
1398 else if (strcmp(optarg, "a") == 0)
1399 timestamp_type = ABSOLUTE;
1400 else if (strcmp(optarg, "d") == 0)
1401 timestamp_type = DELTA;
1403 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1405 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1406 fprintf(stderr, "or \"d\" for delta.\n");
1410 case 'T': /* Tree view pane height */
1411 tv_size = atoi(optarg);
1413 case 'v': /* Show version and exit */
1414 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1417 case 'w': /* Write to capture file xxx */
1419 save_file = g_strdup(optarg);
1421 capture_option_specified = TRUE;
1425 case 'W': /* Write to capture file FD xxx */
1427 cfile.save_file_fd = atoi(optarg);
1429 capture_option_specified = TRUE;
1435 case 'Z': /* Write to pipe FD XXX */
1437 /* associate stdout with pipe */
1439 if (dup2(i, 1) < 0) {
1440 fprintf(stderr, "Unable to dup pipe handle\n");
1444 capture_option_specified = TRUE;
1446 #endif /* HAVE_LIBPCAP */
1451 case '?': /* Bad flag - print usage message */
1457 #ifndef HAVE_LIBPCAP
1458 if (capture_option_specified)
1459 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1464 if (start_capture) {
1465 /* We're supposed to do a live capture; did the user specify an interface
1467 if (cfile.iface == NULL) {
1468 /* No - pick the first one from the list of interfaces. */
1469 if_list = get_interface_list(&err, err_str);
1470 if (if_list == NULL) {
1473 case CANT_GET_INTERFACE_LIST:
1474 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1478 case NO_INTERFACES_FOUND:
1479 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1484 cfile.iface = g_strdup(if_list->data); /* first interface */
1485 free_interface_list(if_list);
1488 if (capture_child) {
1489 if (cfile.save_file_fd == -1) {
1490 /* XXX - send this to the standard output as something our parent
1491 should put in an error message box? */
1492 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1498 /* Build the column format array */
1499 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1500 cfile.cinfo.col_fmt[i] = get_column_format(i);
1501 cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1502 cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1504 get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1505 if (cfile.cinfo.col_fmt[i] == COL_INFO)
1506 cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1508 cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1512 cfile.snap = WTAP_MAX_PACKET_SIZE;
1513 else if (cfile.snap < MIN_PACKET_SIZE)
1514 cfile.snap = MIN_PACKET_SIZE;
1516 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1517 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1518 gtk_rc_parse(rc_file);
1520 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1521 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1525 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1526 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1530 create_main_window(pl_size, tv_size, bv_size, prefs);
1533 Hmmm should we do it here
1536 dissect_init(); /* Init anything that needs initializing */
1539 /* Is this a "child" ethereal, which is only supposed to pop up a
1540 capture box to let us stop the capture, and run a capture
1541 to a file that our parent will read? */
1542 if (!capture_child) {
1544 /* No. Pop up the main window, and read in a capture file if
1547 gtk_widget_show(top_level);
1548 set_menus_for_capture_file(FALSE);
1550 cfile.colors = colfilter_new();
1552 /* If we were given the name of a capture file, read it in now;
1553 we defer it until now, so that, if we can't open it, and pop
1554 up an alert box, the alert box is more likely to come up on
1555 top of the main window - but before the preference-file-error
1556 alert box, so, if we get one of those, it's more likely to come
1559 if (rfilter != NULL) {
1560 if (dfilter_compile(rfilter, &rfcode) != 0) {
1561 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1562 rfilter_parse_failed = TRUE;
1565 if (!rfilter_parse_failed) {
1566 if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1567 /* "open_cap_file()" succeeded, so it closed the previous
1568 capture file, and thus destroyed any previous read filter
1569 attached to "cf". */
1570 cfile.rfcode = rfcode;
1571 err = read_cap_file(&cfile);
1572 /* Save the name of the containing directory specified in the
1573 path name, if any; we can write over cf_name, which is a
1574 good thing, given that "get_dirname()" does write over its
1576 s = get_dirname(cf_name);
1580 dfilter_destroy(rfcode);
1581 cfile.rfcode = NULL;
1589 /* If we failed to open the preferences file, pop up an alert box;
1590 we defer it until now, so that the alert box is more likely to
1591 come up on top of the main window. */
1592 if (pf_path != NULL) {
1593 simple_dialog(ESD_TYPE_WARN, NULL,
1594 "Could not open preferences file\n\"%s\": %s.", pf_path,
1595 strerror(pf_open_errno));
1599 if (capture_child) {
1600 /* This is the child process for a sync mode or fork mode capture,
1601 so just do the low-level work of a capture - don't create
1602 a temporary file and fork off *another* child process (so don't
1603 call "do_capture()"). */
1607 /* The capture is done; there's nothing more for us to do. */
1610 if (start_capture) {
1611 /* "-k" was specified; start a capture. */
1612 do_capture(save_file);
1615 set_menus_for_capture_in_progress(FALSE);
1619 set_menus_for_capture_in_progress(FALSE);
1629 /* This isn't reached, but we need it to keep GCC from complaining
1630 that "main()" returns without returning a value - it knows that
1631 "exit()" never returns, but it doesn't know that "gtk_exit()"
1632 doesn't, as GTK+ doesn't declare it with the attribute
1634 return 0; /* not reached */
1639 /* We build this as a GUI subsystem application on Win32, so
1640 "WinMain()", not "main()", gets called.
1642 Hack shamelessly stolen from the Win32 port of the GIMP. */
1644 #define _stdcall __attribute__((stdcall))
1648 WinMain (struct HINSTANCE__ *hInstance,
1649 struct HINSTANCE__ *hPrevInstance,
1653 return main (__argc, __argv);
1659 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1661 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1663 *filter_bt, *filter_cm, *filter_te,
1665 GList *filter_list = NULL;
1667 GtkAccelGroup *accel;
1671 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1672 gtk_widget_set_name(top_level, "main window");
1673 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1674 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1675 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1676 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1677 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1679 /* Container for menu bar, paned windows and progress/info box */
1680 main_vbox = gtk_vbox_new(FALSE, 1);
1681 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1682 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1683 gtk_widget_show(main_vbox);
1686 get_main_menu(&menubar, &accel);
1687 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1688 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1689 gtk_widget_show(menubar);
1691 /* Panes for the packet list, tree, and byte view */
1692 u_pane = gtk_vpaned_new();
1693 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1694 l_pane = gtk_vpaned_new();
1695 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1696 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1697 gtk_widget_show(l_pane);
1698 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1699 gtk_widget_show(u_pane);
1702 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1703 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1704 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1705 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1706 remember_scrolled_window(pkt_scrollw);
1707 gtk_widget_show(pkt_scrollw);
1708 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1710 packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1711 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1713 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1714 pl_style = gtk_style_new();
1715 gdk_font_unref(pl_style->font);
1716 pl_style->font = m_r_font;
1717 gtk_widget_set_style(packet_list, pl_style);
1718 gtk_widget_set_name(packet_list, "packet list");
1719 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1720 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1721 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1722 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1723 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1724 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1725 for (i = 0; i < cfile.cinfo.num_cols; i++) {
1726 if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1727 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1729 /* Right-justify the packet number column. */
1730 if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1731 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1734 /* Save static column sizes to use during a "-S" capture, so that
1735 the columns don't resize during a live capture. */
1736 cfile.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1737 get_column_longest_string(get_column_format(i)));
1739 gtk_widget_set_usize(packet_list, -1, pl_size);
1740 gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1741 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1742 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1743 gtk_widget_show(packet_list);
1746 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1747 prefs->gui_scrollbar_on_right);
1748 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1749 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1750 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1751 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1752 gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1753 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1754 gtk_widget_show(tree_view);
1756 item_style = gtk_style_new();
1757 gdk_font_unref(item_style->font);
1758 item_style->font = m_r_font;
1761 create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1762 prefs->gui_scrollbar_on_right);
1764 /* Progress/filter/info box */
1765 stat_hbox = gtk_hbox_new(FALSE, 1);
1766 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1767 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1768 gtk_widget_show(stat_hbox);
1770 prog_bar = gtk_progress_bar_new();
1771 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1772 gtk_widget_show(prog_bar);
1774 filter_bt = gtk_button_new_with_label("Filter:");
1775 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1776 GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1777 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1778 gtk_widget_show(filter_bt);
1780 filter_cm = gtk_combo_new();
1781 filter_list = g_list_append (filter_list, "");
1782 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1783 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1784 filter_te = GTK_COMBO(filter_cm)->entry;
1785 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1786 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1787 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1788 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1789 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1790 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1791 gtk_widget_show(filter_cm);
1793 filter_reset = gtk_button_new_with_label("Reset");
1794 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1795 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1796 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1797 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1798 gtk_widget_show(filter_reset);
1800 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1801 * of any widget that ends up calling a callback which needs
1802 * that text entry pointer */
1803 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1804 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1805 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1806 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1807 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1809 info_bar = gtk_statusbar_new();
1810 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1811 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1812 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1813 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1814 gtk_widget_show(info_bar);