3 * $Id: main.c,v 1.122 2000/06/24 05:06:29 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(&cf, follow_filter);
212 /* the data_out_file should now be full of the streams information */
213 fclose( data_out_file );
215 /* the filename1 file now has all the text that was in the session */
216 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
217 gtk_widget_set_name( streamwindow, "TCP stream window" );
219 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
220 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
222 if( incomplete_tcp_stream ) {
223 gtk_window_set_title( GTK_WINDOW(streamwindow),
224 "Contents of TCP stream (incomplete)" );
226 gtk_window_set_title( GTK_WINDOW(streamwindow),
227 "Contents of TCP stream" );
229 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
230 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
232 /* setup the container */
233 box = gtk_vbox_new( FALSE, 0 );
234 gtk_container_add( GTK_CONTAINER(streamwindow), box );
235 gtk_widget_show( box );
237 /* create a scrolled window for the text */
238 txt_scrollw = gtk_scrolled_window_new( NULL, NULL );
239 gtk_box_pack_start( GTK_BOX(box), txt_scrollw, TRUE, TRUE, 0 );
240 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(txt_scrollw),
243 set_scrollbar_placement_scrollw(txt_scrollw, prefs.gui_scrollbar_on_right);
244 remember_scrolled_window(txt_scrollw);
245 gtk_widget_show( txt_scrollw );
247 /* create a text box */
248 text = gtk_text_new( NULL, NULL );
249 gtk_text_set_editable( GTK_TEXT(text), FALSE);
250 gtk_container_add( GTK_CONTAINER(txt_scrollw), text );
251 gtk_widget_show(text);
254 hbox = gtk_hbox_new( FALSE, 1 );
255 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
256 gtk_widget_show(hbox);
258 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
259 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
260 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
262 /* Create Radio Buttons */
263 b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
264 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
265 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
266 gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
267 gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
268 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
269 GTK_OBJECT(streamwindow));
270 gtk_widget_show(b_ascii);
272 b_ebcdic = gtk_radio_button_new_with_label(
273 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
275 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
276 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
277 gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
278 gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
279 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
280 GTK_OBJECT(streamwindow));
281 gtk_widget_show(b_ebcdic);
283 b_hexdump = gtk_radio_button_new_with_label(
284 gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
286 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
287 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
288 gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
289 gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
290 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
291 GTK_OBJECT(streamwindow));
292 gtk_widget_show(b_hexdump);
294 /* Create Close Button */
295 close_bt = gtk_button_new_with_label("Close");
296 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
297 GTK_SIGNAL_FUNC(gtk_widget_destroy),
298 GTK_OBJECT(streamwindow));
299 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
300 gtk_widget_show( close_bt );
302 /* Create Print Button */
303 print_bt = gtk_button_new_with_label("Print");
304 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
305 GTK_SIGNAL_FUNC(follow_print_stream),
306 GTK_OBJECT(streamwindow));
307 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
308 gtk_widget_show( print_bt );
310 /* Tuck away the filename and textbox into streamwindow */
311 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
312 #define E_FOLLOW_TEXT_KEY "follow_text_key"
314 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
315 g_strdup(filename1));
316 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
318 follow_load_text(text, filename1, 0);
320 data_out_file = NULL;
322 /* Make sure this widget gets destroyed if we quit the main loop,
323 so that if we exit, we clean up any temporary files we have
324 for "Follow TCP Stream" windows. */
325 gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(streamwindow));
326 gtk_widget_show( streamwindow );
328 simple_dialog(ESD_TYPE_WARN, NULL,
329 "Error following stream. Please make\n"
330 "sure you have a TCP packet selected.");
334 /* The destroy call back has the responsibility of
335 * unlinking the temporary file */
337 follow_destroy_cb(GtkWidget *win, gpointer data)
341 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
342 E_FOLLOW_FILENAME_KEY);
346 gtk_widget_destroy(win);
349 #define E_FOLLOW_ASCII_TYPE 0
350 #define E_FOLLOW_EBCDIC_TYPE 1
351 #define E_FOLLOW_HEXDUMP_TYPE 2
353 /* Handles the ASCII/EBCDIC toggling */
355 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
357 guint8 show_type = E_FOLLOW_ASCII_TYPE;
358 GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
361 b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
363 b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
364 E_FOLLOW_EBCDIC_KEY);
365 b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
366 E_FOLLOW_HEXDUMP_KEY);
367 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
369 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
370 E_FOLLOW_FILENAME_KEY);
378 if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
379 show_type = E_FOLLOW_EBCDIC_TYPE;
380 else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
381 show_type = E_FOLLOW_HEXDUMP_TYPE;
383 follow_load_text(text, filename, show_type);
386 #define FLT_BUF_SIZE 1024
388 follow_read_stream(char *filename, guint8 show_type,
389 void (*print_line)(char *, int, gboolean, void *), void *arg)
393 guint32 client_addr = 0;
394 guint16 client_port = 0;
396 guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
399 data_out_file = fopen( filename, "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 = cf.pd + finfo_selected->start;
696 buf = g_malloc0(32 + finfo_selected->length * 3);
699 sprintf(ptr, "frame[%d] == ", finfo_selected->start);
700 ptr = buf+strlen(buf);
702 if (finfo_selected->length == 1) {
703 sprintf(ptr, "0x%02x", *c++);
706 for (i=0;i<finfo_selected->length; i++) {
708 sprintf(ptr, "%02x", *c++);
711 sprintf(ptr, ":%02x", *c++);
713 ptr = buf+strlen(buf);
719 /* create a new one and set the display filter entry accordingly */
720 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
722 /* Run the display filter so it goes in effect. */
723 filter_packets(&cf, buf);
725 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
729 hfinfo_numeric_format(header_field_info *hfinfo)
733 /* Pick the proper format string */
734 switch(hfinfo->display) {
737 case BASE_OCT: /* I'm lazy */
738 case BASE_BIN: /* I'm lazy */
739 switch(hfinfo->type) {
753 g_assert_not_reached();
758 switch(hfinfo->type) {
760 format = "%s == 0x%02x";
763 format = "%s == 0x%04x";
766 format = "%s == 0x%06x";
769 format = "%s == 0x%08x";
772 g_assert_not_reached();
777 g_assert_not_reached();
784 /* Run the current display filter on the current packet set, and
787 filter_activate_cb(GtkWidget *w, gpointer data)
789 GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
790 GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
791 GList *li, *nl = NULL;
792 gboolean add_filter = TRUE;
794 char *s = gtk_entry_get_text(GTK_ENTRY(w));
796 /* GtkCombos don't let us get at their list contents easily, so we maintain
797 our own filter list, and feed it to gtk_combo_set_popdown_strings when
798 a new filter is added. */
799 if (filter_packets(&cf, g_strdup(s))) {
800 li = g_list_first(filter_list);
802 if (li->data && strcmp(s, li->data) == 0)
808 filter_list = g_list_append(filter_list, g_strdup(s));
809 li = g_list_first(filter_list);
811 nl = g_list_append(nl, strdup(li->data));
814 gtk_combo_set_popdown_strings(filter_cm, nl);
815 gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
820 /* redisplay with no display filter */
822 filter_reset_cb(GtkWidget *w, gpointer data)
824 GtkWidget *filter_te = NULL;
826 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
827 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
830 filter_packets(&cf, NULL);
833 /* 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 = cf.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(&cf, row);
905 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
906 unselect_packet(&cf);
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), cf.pd, cf.current_frame->cap_len,
921 finfo->start, finfo->length, cf.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), cf.pd, cf.current_frame->cap_len,
929 -1, -1, cf.current_frame->flags.encoding);
932 void collapse_all_cb(GtkWidget *widget, gpointer data) {
933 if (cf.protocol_tree)
934 collapse_all_tree(cf.protocol_tree, tree_view);
937 void expand_all_cb(GtkWidget *widget, gpointer data) {
938 if (cf.protocol_tree)
939 expand_all_tree(cf.protocol_tree, tree_view);
942 void resolve_name_cb(GtkWidget *widget, gpointer data) {
943 if (cf.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(cf.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(&cf);
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(&cf, info_bar);
1121 /* Exit by leaving the main loop, so that any quit functions
1122 we registered get called. */
1129 fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1132 fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1134 fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1135 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1136 fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1137 fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1139 fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1141 fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1142 fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1143 fprintf(stderr, "\t[ -T <tree view height> ]\n");
1147 /* And now our feature presentation... [ fade to music ] */
1149 main(int argc, char *argv[])
1157 extern char *optarg;
1158 gboolean arg_error = FALSE;
1161 char pcap_version[] = "0.4a6";
1163 extern char pcap_version[];
1167 int pf_open_errno = 0;
1170 gboolean start_capture = FALSE;
1171 gchar *save_file = NULL;
1173 gchar err_str[PCAP_ERRBUF_SIZE];
1175 gboolean capture_option_specified = FALSE;
1177 gint pl_size = 280, tv_size = 95, bv_size = 75;
1178 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
1179 dfilter *rfcode = NULL;
1180 gboolean rfilter_parse_failed = FALSE;
1183 ethereal_path = argv[0];
1186 command_name = get_basename(ethereal_path);
1187 /* Set "capture_child" to indicate whether this is going to be a child
1188 process for a "-S" capture. */
1189 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1192 /* If invoked with the "-G" flag, we dump out a glossary of
1193 display filter symbols.
1195 We must do this before calling "gtk_init()", because "gtk_init()"
1196 tries to open an X display, and we don't want to have to do any X
1197 stuff just to do a build.
1199 Given that we call "gtk_init()" before doing the regular argument
1200 list processing, so that it can handle X and GTK+ arguments and
1201 remove them from the list at which we look, this means we must do
1202 this before doing the regular argument list processing, as well.
1206 you must give the "-G" flag as the first flag on the command line;
1208 you must give it as "-G", nothing more, nothing less;
1210 any arguments after the "-G" flag will not be used. */
1211 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1213 proto_registrar_dump();
1217 /* Set the current locale according to the program environment.
1218 * We haven't localized anything, but some GTK widgets are localized
1219 * (the file selection dialogue, for example) */
1222 /* Let GTK get its args */
1223 gtk_init (&argc, &argv);
1225 prefs = read_prefs(&pf_path);
1226 if (pf_path != NULL) {
1227 /* The preferences file exists, but couldn't be opened; "pf_path" is
1228 its pathname. Remember "errno", as that says why the attempt
1230 pf_open_errno = errno;
1233 /* Initialize the capture file struct */
1235 cf.plist_end = NULL;
1238 cf.user_saved = FALSE;
1239 cf.is_tempfile = FALSE;
1244 cf.cfilter = g_strdup(EMPTY_FILTER);
1247 cf.save_file = NULL;
1248 cf.save_file_fd = -1;
1249 cf.snap = WTAP_MAX_PACKET_SIZE;
1251 cf.cinfo.num_cols = prefs->num_cols;
1252 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1253 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1254 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1255 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1256 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1258 /* Assemble the compile-time options */
1259 snprintf(comp_info_str, 256,
1260 #ifdef GTK_MAJOR_VERSION
1261 "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1264 "GTK+ (version unknown), %s%s, %s%s, %s%s",
1268 "with libpcap ", pcap_version,
1270 "without libpcap", "",
1275 "with libz ", ZLIB_VERSION,
1276 #else /* ZLIB_VERSION */
1277 "with libz ", "(version unknown)",
1278 #endif /* ZLIB_VERSION */
1279 #else /* HAVE_LIBZ */
1281 #endif /* HAVE_LIBZ */
1283 /* Oh, this is pretty */
1284 #if defined(HAVE_UCD_SNMP_SNMP_H)
1285 #ifdef HAVE_UCD_SNMP_VERSION_H
1286 "with UCD SNMP ", VersionInfo
1287 #else /* HAVE_UCD_SNMP_VERSION_H */
1288 "with UCD SNMP ", "(version unknown)"
1289 #endif /* HAVE_UCD_SNMP_VERSION_H */
1290 #elif defined(HAVE_SNMP_SNMP_H)
1291 #ifdef HAVE_SNMP_VERSION_H
1292 "with CMU SNMP ", snmp_Version()
1293 #else /* HAVE_SNMP_VERSION_H */
1294 "with CMU SNMP ", "(version unknown)"
1295 #endif /* HAVE_SNMP_VERSION_H */
1301 /* Now get our args */
1302 while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
1304 case 'b': /* Bold font */
1305 bold_font = g_strdup(optarg);
1307 case 'B': /* Byte view pane height */
1308 bv_size = atoi(optarg);
1310 case 'c': /* Capture xxx packets */
1312 cf.count = atoi(optarg);
1314 capture_option_specified = TRUE;
1318 case 'D': /* Turn off DSCP printing */
1319 g_ip_dscp_actif = FALSE;
1325 cf.cfilter = g_strdup(optarg);
1327 capture_option_specified = TRUE;
1331 case 'h': /* Print help and exit */
1335 case 'i': /* Use interface xxx */
1337 cf.iface = g_strdup(optarg);
1339 capture_option_specified = TRUE;
1343 case 'k': /* Start capture immediately */
1345 start_capture = TRUE;
1347 capture_option_specified = TRUE;
1351 case 'm': /* Medium font */
1352 medium_font = g_strdup(optarg);
1354 case 'n': /* No name resolution */
1355 g_resolving_actif = 0;
1357 case 'P': /* Packet list pane height */
1358 pl_size = atoi(optarg);
1360 case 'Q': /* Quit after capture (just capture to file) */
1363 start_capture = TRUE; /*** -Q implies -k !! ***/
1365 capture_option_specified = TRUE;
1369 case 'r': /* Read capture file xxx */
1370 /* We may set "last_open_dir" to "cf_name", and if we change
1371 "last_open_dir" later, we free the old value, so we have to
1372 set "cf_name" to something that's been allocated. */
1373 cf_name = g_strdup(optarg);
1375 case 'R': /* Read file filter */
1378 case 's': /* Set the snapshot (capture) length */
1380 cf.snap = atoi(optarg);
1382 capture_option_specified = TRUE;
1386 case 'S': /* "Sync" mode: used for following file ala tail -f */
1390 capture_option_specified = TRUE;
1394 case 't': /* Time stamp type */
1395 if (strcmp(optarg, "r") == 0)
1396 timestamp_type = RELATIVE;
1397 else if (strcmp(optarg, "a") == 0)
1398 timestamp_type = ABSOLUTE;
1399 else if (strcmp(optarg, "d") == 0)
1400 timestamp_type = DELTA;
1402 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1404 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1405 fprintf(stderr, "or \"d\" for delta.\n");
1409 case 'T': /* Tree view pane height */
1410 tv_size = atoi(optarg);
1412 case 'v': /* Show version and exit */
1413 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1416 case 'w': /* Write to capture file xxx */
1418 save_file = g_strdup(optarg);
1420 capture_option_specified = TRUE;
1424 case 'W': /* Write to capture file FD xxx */
1426 cf.save_file_fd = atoi(optarg);
1428 capture_option_specified = TRUE;
1434 case 'Z': /* Write to pipe FD XXX */
1436 /* associate stdout with pipe */
1438 if (dup2(i, 1) < 0) {
1439 fprintf(stderr, "Unable to dup pipe handle\n");
1443 capture_option_specified = TRUE;
1445 #endif /* HAVE_LIBPCAP */
1450 case '?': /* Bad flag - print usage message */
1456 #ifndef HAVE_LIBPCAP
1457 if (capture_option_specified)
1458 fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1463 if (start_capture) {
1464 /* We're supposed to do a live capture; did the user specify an interface
1466 if (cf.iface == NULL) {
1467 /* No - pick the first one from the list of interfaces. */
1468 if_list = get_interface_list(&err, err_str);
1469 if (if_list == NULL) {
1472 case CANT_GET_INTERFACE_LIST:
1473 fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1477 case NO_INTERFACES_FOUND:
1478 fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1483 cf.iface = g_strdup(if_list->data); /* first interface */
1484 free_interface_list(if_list);
1487 if (capture_child) {
1488 if (cf.save_file_fd == -1) {
1489 /* XXX - send this to the standard output as something our parent
1490 should put in an error message box? */
1491 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1497 /* Build the column format array */
1498 for (i = 0; i < cf.cinfo.num_cols; i++) {
1499 cf.cinfo.col_fmt[i] = get_column_format(i);
1500 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1501 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1503 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1504 if (cf.cinfo.col_fmt[i] == COL_INFO)
1505 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1507 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1511 cf.snap = WTAP_MAX_PACKET_SIZE;
1512 else if (cf.snap < MIN_PACKET_SIZE)
1513 cf.snap = MIN_PACKET_SIZE;
1515 rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1516 sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1517 gtk_rc_parse(rc_file);
1519 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1520 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1524 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1525 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1529 create_main_window(pl_size, tv_size, bv_size, prefs);
1532 Hmmm should we do it here
1535 dissect_init(); /* Init anything that needs initializing */
1538 /* Is this a "child" ethereal, which is only supposed to pop up a
1539 capture box to let us stop the capture, and run a capture
1540 to a file that our parent will read? */
1541 if (!capture_child) {
1543 /* No. Pop up the main window, and read in a capture file if
1546 gtk_widget_show(top_level);
1547 set_menus_for_capture_file(FALSE);
1549 cf.colors = colfilter_new();
1551 /* If we were given the name of a capture file, read it in now;
1552 we defer it until now, so that, if we can't open it, and pop
1553 up an alert box, the alert box is more likely to come up on
1554 top of the main window - but before the preference-file-error
1555 alert box, so, if we get one of those, it's more likely to come
1558 if (rfilter != NULL) {
1559 if (dfilter_compile(rfilter, &rfcode) != 0) {
1560 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1561 rfilter_parse_failed = TRUE;
1564 if (!rfilter_parse_failed) {
1565 if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1566 /* "open_cap_file()" succeeded, so it closed the previous
1567 capture file, and thus destroyed any previous read filter
1568 attached to "cf". */
1570 err = read_cap_file(&cf);
1571 /* Save the name of the containing directory specified in the
1572 path name, if any; we can write over cf_name, which is a
1573 good thing, given that "get_dirname()" does write over its
1575 s = get_dirname(cf_name);
1579 dfilter_destroy(rfcode);
1588 /* If we failed to open the preferences file, pop up an alert box;
1589 we defer it until now, so that the alert box is more likely to
1590 come up on top of the main window. */
1591 if (pf_path != NULL) {
1592 simple_dialog(ESD_TYPE_WARN, NULL,
1593 "Could not open preferences file\n\"%s\": %s.", pf_path,
1594 strerror(pf_open_errno));
1598 if (capture_child) {
1599 /* This is the child process for a sync mode or fork mode capture,
1600 so just do the low-level work of a capture - don't create
1601 a temporary file and fork off *another* child process (so don't
1602 call "do_capture()"). */
1606 /* The capture is done; there's nothing more for us to do. */
1609 if (start_capture) {
1610 /* "-k" was specified; start a capture. */
1611 do_capture(save_file);
1614 set_menus_for_capture_in_progress(FALSE);
1618 set_menus_for_capture_in_progress(FALSE);
1628 /* This isn't reached, but we need it to keep GCC from complaining
1629 that "main()" returns without returning a value - it knows that
1630 "exit()" never returns, but it doesn't know that "gtk_exit()"
1631 doesn't, as GTK+ doesn't declare it with the attribute
1633 return 0; /* not reached */
1638 /* We build this as a GUI subsystem application on Win32, so
1639 "WinMain()", not "main()", gets called.
1641 Hack shamelessly stolen from the Win32 port of the GIMP. */
1643 #define _stdcall __attribute__((stdcall))
1647 WinMain (struct HINSTANCE__ *hInstance,
1648 struct HINSTANCE__ *hPrevInstance,
1652 return main (__argc, __argv);
1658 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1660 GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
1662 *filter_bt, *filter_cm, *filter_te,
1664 GList *filter_list = NULL;
1666 GtkAccelGroup *accel;
1670 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1671 gtk_widget_set_name(top_level, "main window");
1672 gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1673 GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1674 gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1675 gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1676 gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1678 /* Container for menu bar, paned windows and progress/info box */
1679 main_vbox = gtk_vbox_new(FALSE, 1);
1680 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1681 gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1682 gtk_widget_show(main_vbox);
1685 get_main_menu(&menubar, &accel);
1686 gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1687 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1688 gtk_widget_show(menubar);
1690 /* Panes for the packet list, tree, and byte view */
1691 u_pane = gtk_vpaned_new();
1692 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1693 l_pane = gtk_vpaned_new();
1694 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1695 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1696 gtk_widget_show(l_pane);
1697 gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1698 gtk_widget_show(u_pane);
1701 pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1702 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1703 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1704 set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1705 remember_scrolled_window(pkt_scrollw);
1706 gtk_widget_show(pkt_scrollw);
1707 gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1709 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1710 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1712 set_plist_sel_browse(prefs->gui_plist_sel_browse);
1713 pl_style = gtk_style_new();
1714 gdk_font_unref(pl_style->font);
1715 pl_style->font = m_r_font;
1716 gtk_widget_set_style(packet_list, pl_style);
1717 gtk_widget_set_name(packet_list, "packet list");
1718 gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1719 GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1720 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1721 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1722 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1723 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1724 for (i = 0; i < cf.cinfo.num_cols; i++) {
1725 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1726 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1728 /* Right-justify the packet number column. */
1729 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1730 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1733 /* Save static column sizes to use during a "-S" capture, so that
1734 the columns don't resize during a live capture. */
1735 cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1736 get_column_longest_string(get_column_format(i)));
1738 gtk_widget_set_usize(packet_list, -1, pl_size);
1739 gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1740 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1741 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1742 gtk_widget_show(packet_list);
1745 create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1746 prefs->gui_scrollbar_on_right);
1747 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1748 GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1749 gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1750 GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1751 gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1752 GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1753 gtk_widget_show(tree_view);
1755 item_style = gtk_style_new();
1756 gdk_font_unref(item_style->font);
1757 item_style->font = m_r_font;
1760 create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1761 prefs->gui_scrollbar_on_right);
1763 /* Progress/filter/info box */
1764 stat_hbox = gtk_hbox_new(FALSE, 1);
1765 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1766 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1767 gtk_widget_show(stat_hbox);
1769 prog_bar = gtk_progress_bar_new();
1770 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1771 gtk_widget_show(prog_bar);
1773 filter_bt = gtk_button_new_with_label("Filter:");
1774 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1775 GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1776 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1777 gtk_widget_show(filter_bt);
1779 filter_cm = gtk_combo_new();
1780 filter_list = g_list_append (filter_list, "");
1781 gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1782 gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1783 filter_te = GTK_COMBO(filter_cm)->entry;
1784 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1785 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1786 gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1787 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1788 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1789 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1790 gtk_widget_show(filter_cm);
1792 filter_reset = gtk_button_new_with_label("Reset");
1793 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1794 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1795 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1796 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1797 gtk_widget_show(filter_reset);
1799 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1800 * of any widget that ends up calling a callback which needs
1801 * that text entry pointer */
1802 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1803 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1804 set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1805 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1806 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1808 info_bar = gtk_statusbar_new();
1809 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1810 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1811 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1812 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1813 gtk_widget_show(info_bar);