3 * $Id: main.c,v 1.43 1999/11/23 03:50:40 gram 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 scrollbars automatic?
35 * - Make byte view selections more fancy?
54 #include <sys/types.h>
61 #ifdef HAVE_NETINET_IN_H
62 #include <netinet/in.h>
67 #ifdef NEED_SNPRINTF_H
73 # include "snprintf.h"
76 #ifdef NEED_STRERROR_H
81 #include "timestamp.h"
87 #include "prefs_dlg.h"
93 #include "proto_draw.h"
97 FILE *data_out_file = NULL;
100 GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
102 GdkFont *m_r_font, *m_b_font;
103 guint main_ctx, file_ctx;
104 gchar comp_info_str[256];
105 gchar *ethereal_path = NULL;
106 gchar *medium_font = MONO_MEDIUM_FONT;
107 gchar *bold_font = MONO_BOLD_FONT;
108 gchar *last_open_dir = NULL;
110 ts_type timestamp_type = RELATIVE;
112 GtkStyle *item_style;
114 /* Specifies the field currently selected in the GUI protocol tree */
115 field_info *finfo_selected = NULL;
117 static void follow_destroy_cb(GtkWidget *win, gpointer data);
118 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
119 static void follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii);
120 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
121 static char* hfinfo_numeric_format(header_field_info *hfinfo);
123 /* About Ethereal window */
125 about_ethereal( GtkWidget *w, gpointer data ) {
126 simple_dialog(ESD_TYPE_INFO, NULL,
127 "GNU Ethereal - network protocol analyzer\n"
128 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
129 "Compiled with %s\n\n"
132 "Gilbert Ramirez <gramirez@tivoli.com>\n"
133 "Hannes R. Boehm <hannes@boehm.org>\n"
134 "Mike Hall <mlh@io.com>\n"
135 "Bobo Rajec <bobo@bsp-consulting.sk>\n"
136 "Laurent Deniel <deniel@worldnet.fr>\n"
137 "Don Lafontaine <lafont02@cn.ca>\n"
138 "Guy Harris <guy@alum.mit.edu>\n"
139 "Simon Wilkinson <sxw@dcs.ed.ac.uk>\n"
140 "Joerg Mayer <jmayer@telemation.de>\n"
141 "Martin Maciaszek <fastjack@i-s-o.net>\n"
142 "Didier Jorand <Didier.Jorand@alcatel.fr>\n"
143 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
144 "Richard Sharpe <sharpe@ns.aus.com>\n"
145 "John McDermott <jjm@jkintl.com>\n"
146 "Jeff Jahr <jjahr@shastanets.com>\n"
147 "Brad Robel-Forrest <bradr@watchguard.com>\n"
148 "Ashok Narayanan <ashokn@cisco.com>\n"
149 "Aaron Hillegass <aaron@classmax.com>\n"
150 "Jason Lango <jal@netapp.com>\n"
151 "Johan Feyaerts <Johan.Feyaerts@siemens.atea.be>\n"
152 "Olivier Abad <abad@daba.dhis.org>\n"
153 "Thierry Andry <Thierry.Andry@advalvas.be>\n"
154 "Jeff Foster <jfoste@woodward.com>\n"
155 "Peter Torvals <petertv@xoommail.com>\n"
156 "Christophe Tronche <ch.tronche@computer.org>\n"
157 "Nathan Neulinger <nneul@umr.edu>\n"
158 "Tomislav Vujec <tvujec@carnet.hr>\n"
159 "Kojak <kojak@bigwig.net>\n"
160 "Uwe Girlich <Uwe.Girlich@philosys.de>\n"
161 "Warren Young <tangent@mail.com>\n"
162 "Heikki Vatiainen <hessu@cs.tut.fi>\n"
164 "\nSee http://ethereal.zing.org for more information",
165 VERSION, comp_info_str);
168 /* Follow the TCP stream, if any, to which the last packet that we called
169 a dissection routine on belongs (this might be the most recently
170 selected packet, or it might be the last packet in the file). */
172 follow_stream_cb( GtkWidget *w, gpointer data ) {
173 char filename1[128+1];
174 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
175 GtkWidget *hbox, *close_bt, *print_bt, *button;
177 gchar *follow_filter;
179 if( pi.ipproto == 6 ) {
180 /* we got tcp so we can follow */
181 /* Create a temporary file into which to dump the reassembled data
182 from the TCP stream, and set "data_out_file" to refer to it, so
183 that the TCP code will write to it.
185 XXX - it might be nicer to just have the TCP code directly
186 append stuff to the text widget for the TCP stream window,
187 if we can arrange that said window not pop up until we're
189 tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
191 simple_dialog(ESD_TYPE_WARN, NULL,
192 "Could not create temporary file %s: %s", filename1, strerror(errno));
195 data_out_file = fdopen( tmp_fd, "w" );
196 if( data_out_file == NULL ) {
197 simple_dialog(ESD_TYPE_WARN, NULL,
198 "Could not create temporary file %s: %s", filename1, strerror(errno));
204 /* Create a new filter that matches all packets in the TCP stream,
205 and set the display filter entry accordingly */
206 reset_tcp_reassembly();
207 follow_filter = build_follow_filter( &pi );
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" );
218 /* gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
219 NULL, "WM destroy" );
220 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
221 NULL, "WM destroy" );*/
222 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
223 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
224 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
225 GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
227 if( incomplete_tcp_stream ) {
228 gtk_window_set_title( GTK_WINDOW(streamwindow),
229 "Contents of TCP stream (incomplete)" );
231 gtk_window_set_title( GTK_WINDOW(streamwindow),
232 "Contents of TCP stream" );
234 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
235 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
237 /* setup the container */
238 box = gtk_vbox_new( FALSE, 0 );
239 gtk_container_add( GTK_CONTAINER(streamwindow), box );
240 gtk_widget_show( box );
242 /* set up the table we attach to */
243 table = gtk_table_new( 1, 2, FALSE );
244 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
245 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
246 gtk_widget_show( table );
248 /* create a text box */
249 text = gtk_text_new( NULL, NULL );
250 gtk_text_set_editable( GTK_TEXT(text), FALSE);
251 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
252 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
253 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
254 gtk_widget_show(text);
257 hbox = gtk_hbox_new( FALSE, 1 );
258 gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
259 gtk_widget_show(hbox);
261 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
263 /* Create Radio Buttons */
264 button = gtk_radio_button_new_with_label(NULL, "ASCII");
265 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
266 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, button);
267 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
268 gtk_signal_connect(GTK_OBJECT(button), "toggled",
269 GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
270 GTK_OBJECT(streamwindow));
271 gtk_widget_show(button);
273 button = gtk_radio_button_new_with_label(
274 gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
276 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
277 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
278 gtk_widget_show(button);
280 /* Create Close Button */
281 close_bt = gtk_button_new_with_label("Close");
282 gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
283 GTK_SIGNAL_FUNC(gtk_widget_destroy),
284 GTK_OBJECT(streamwindow));
285 gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
286 gtk_widget_show( close_bt );
288 /* Create Print Button */
289 print_bt = gtk_button_new_with_label("Print");
290 gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
291 GTK_SIGNAL_FUNC(follow_print_stream),
292 GTK_OBJECT(streamwindow));
293 gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
294 gtk_widget_show( print_bt );
296 /* create the scrollbar */
297 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
298 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
299 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
300 gtk_widget_show( vscrollbar );
301 gtk_widget_realize( text );
303 /* Tuck away the filename and textbox into streamwindow */
304 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
305 #define E_FOLLOW_TEXT_KEY "follow_text_key"
307 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
308 g_strdup(filename1));
309 gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
311 follow_load_text(text, filename1, TRUE);
313 data_out_file = NULL;
314 gtk_widget_show( streamwindow );
316 simple_dialog(ESD_TYPE_WARN, NULL,
317 "Error following stream. Please make\n"
318 "sure you have a TCP packet selected.");
322 /* The destroy call back has the responsibility of
323 * unlinking the temporary file */
325 follow_destroy_cb(GtkWidget *win, gpointer data)
329 filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
330 E_FOLLOW_FILENAME_KEY);
334 gtk_widget_destroy(win);
337 /* Handles the ASCII/EBCDIC toggling */
339 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
341 gboolean show_ascii = FALSE;
342 GtkWidget *button, *text;
346 button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
348 text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
350 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
351 E_FOLLOW_FILENAME_KEY);
357 if (GTK_TOGGLE_BUTTON(button)->active)
360 follow_load_text(text, filename, show_ascii);
363 static void follow_print_stream(GtkWidget *w, gpointer parent_w)
367 char* print_dest = NULL;
370 switch (prefs.pr_dest) {
372 print_dest = prefs.pr_cmd;
377 print_dest = prefs.pr_file;
382 if (print_dest != NULL) {
383 fh = open_print_dest(to_file, print_dest);
389 simple_dialog(ESD_TYPE_WARN, NULL,
390 "Couldn't figure out where to send the print "
391 "job. Check your preferences.");
395 simple_dialog(ESD_TYPE_WARN, NULL,
396 "Couldn't run print command %s.", prefs.pr_cmd);
400 simple_dialog(ESD_TYPE_WARN, NULL,
401 file_write_error_message(errno),
408 filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
409 E_FOLLOW_FILENAME_KEY);
411 if (filename != NULL) {
413 print_file(fh, filename);
415 close_print_dest(to_file, fh);
418 simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
423 follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii)
427 /* Delete any info already in text box */
428 bytes_already = gtk_text_get_length(GTK_TEXT(text));
429 if (bytes_already > 0) {
430 gtk_text_set_point(GTK_TEXT(text), 0);
431 gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
434 /* stop the updates while we fill the text box */
435 gtk_text_freeze( GTK_TEXT(text) );
436 data_out_file = fopen( filename, "r" );
437 if( data_out_file ) {
441 nchars = fread( buffer, 1, 1024, data_out_file );
443 /* If our native arch is EBCDIC, call:
444 * ASCII_TO_EBCDIC(buffer, nchars);
448 /* If our native arch is ASCII, call: */
449 EBCDIC_to_ASCII(buffer, nchars);
451 gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
452 if( nchars < 1024 ) {
456 if( ferror( data_out_file ) ) {
457 simple_dialog(ESD_TYPE_WARN, NULL,
458 "Error reading temporary file %s: %s", filename, strerror(errno));
460 fclose( data_out_file );
462 simple_dialog(ESD_TYPE_WARN, NULL,
463 "Could not open temporary file %s: %s", filename, strerror(errno));
465 gtk_text_thaw( GTK_TEXT(text) );
468 /* Match selected byte pattern */
470 match_selected_cb(GtkWidget *w, gpointer data)
473 GtkWidget *filter_te = NULL;
474 char *ptr, *format, *stringified;
475 int i, dfilter_len, abbrev_len;
477 header_field_info *hfinfo;
479 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
481 if (!finfo_selected) {
482 simple_dialog(ESD_TYPE_WARN, NULL,
483 "Error determining selected bytes. Please make\n"
484 "sure you have selected a field within the tree\n"
485 "view to be matched.");
489 hfinfo = finfo_selected->hfinfo;
491 abbrev_len = strlen(hfinfo->abbrev);
493 switch(hfinfo->type) {
496 dfilter_len = abbrev_len + 2;
497 buf = g_malloc0(dfilter_len);
498 snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
510 dfilter_len = abbrev_len + 20;
511 buf = g_malloc0(dfilter_len);
512 format = hfinfo_numeric_format(hfinfo);
513 snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
517 dfilter_len = abbrev_len + 4 + 15 + 1;
518 buf = g_malloc0(dfilter_len);
519 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
520 ipv4_addr_str(&(finfo_selected->value.ipv4)));
524 dfilter_len = abbrev_len + 15;
525 buf = g_malloc0(dfilter_len);
526 snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
527 finfo_selected->value.numeric);
531 stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
532 dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
533 buf = g_malloc0(dfilter_len);
534 snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
539 dfilter_len = abbrev_len + 30;
540 buf = g_malloc0(dfilter_len);
541 snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
542 finfo_selected->value.floating);
546 dfilter_len = abbrev_len + 22;
547 buf = g_malloc0(dfilter_len);
548 snprintf(buf, dfilter_len, "%s == %02x:%02x:%02x:%02x:%02x:%02x",
550 finfo_selected->value.ether[0],
551 finfo_selected->value.ether[1],
552 finfo_selected->value.ether[2],
553 finfo_selected->value.ether[3],
554 finfo_selected->value.ether[4],
555 finfo_selected->value.ether[5]);
559 case FT_ABSOLUTE_TIME:
560 case FT_RELATIVE_TIME:
561 memcpy(&fi->value.time, va_arg(ap, struct timeval*),
562 sizeof(struct timeval));
566 /* This g_strdup'ed memory is freed in proto_tree_free_node() */
567 fi->value.string = g_strdup(va_arg(ap, char*));
575 c = cf.pd + finfo_selected->start;
576 buf = g_malloc0(32 + finfo_selected->length * 3);
579 sprintf(ptr, "frame[%d : %d] == ", finfo_selected->start, finfo_selected->length);
580 ptr = buf+strlen(buf);
582 if (finfo_selected->length == 1) {
583 sprintf(ptr, "0x%02x", *c++);
586 for (i=0;i<finfo_selected->length; i++) {
588 sprintf(ptr, "%02x", *c++);
591 sprintf(ptr, ":%02x", *c++);
593 ptr = buf+strlen(buf);
599 /* create a new one and set the display filter entry accordingly */
601 gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
603 /* Run the display filter so it goes in effect. */
604 filter_packets(&cf, buf);
606 /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
610 hfinfo_numeric_format(header_field_info *hfinfo)
614 /* Pick the proper format string */
615 switch(hfinfo->display) {
618 case BASE_OCT: /* I'm lazy */
619 case BASE_BIN: /* I'm lazy */
620 switch(hfinfo->type) {
634 g_assert_not_reached();
639 switch(hfinfo->type) {
641 format = "%s == 0x%02x";
644 format = "%s == 0x%04x";
647 format = "%s == 0x%06x";
650 format = "%s == 0x%08x";
653 g_assert_not_reached();
658 g_assert_not_reached();
665 /* Run the current display filter on the current packet set, and
668 filter_activate_cb(GtkWidget *w, gpointer data)
670 char *s = gtk_entry_get_text(GTK_ENTRY(w));
672 filter_packets(&cf, g_strdup(s));
675 /* redisplay with no display filter */
677 filter_reset_cb(GtkWidget *w, gpointer data)
679 GtkWidget *filter_te = NULL;
681 if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
682 gtk_entry_set_text(GTK_ENTRY(filter_te), "");
685 filter_packets(&cf, NULL);
688 /* What to do when a list item is selected/unselected */
690 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
701 select_packet(&cf, row);
705 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
706 unselect_packet(&cf);
710 tree_view_cb(GtkWidget *w, gpointer data) {
713 int tree_selected_start = -1;
714 int tree_selected_len = -1;
716 if (GTK_TREE(w)->selection) {
718 gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
719 E_TREEINFO_FIELD_INFO_KEY);
721 finfo_selected = finfo;
722 tree_selected_start = finfo->start;
723 tree_selected_len = finfo->length;
726 gtk_text_freeze(GTK_TEXT(byte_view));
727 gtk_text_set_point(GTK_TEXT(byte_view), 0);
728 gtk_text_forward_delete(GTK_TEXT(byte_view),
729 gtk_text_get_length(GTK_TEXT(byte_view)));
730 packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
731 tree_selected_start, tree_selected_len,
732 cf.current_frame->encoding);
734 gtk_text_thaw(GTK_TEXT(byte_view));
737 void collapse_all_cb(GtkWidget *widget, gpointer data) {
738 if (cf.protocol_tree)
739 collapse_all_tree(cf.protocol_tree, tree_view);
742 void expand_all_cb(GtkWidget *widget, gpointer data) {
743 if (cf.protocol_tree)
744 expand_all_tree(cf.protocol_tree, tree_view);
748 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
749 if (cf.save_file && !cf.user_saved) {
750 unlink(cf.save_file);
755 /* call initialization routines at program startup time */
757 ethereal_proto_init(void) {
765 ethereal_proto_cleanup(void) {
773 fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
774 VERSION, comp_info_str);
775 fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
777 fprintf(stderr, " [-f <filter expression>] [-i interface] [-m <medium font>] [-n]\n");
778 fprintf(stderr, " [-P <packet list height>] [-r infile] [-s snaplen]\n");
779 fprintf(stderr, " [-t <time stamp format>] [-T <tree view height>] [-w savefile] \n");
782 /* And now our feature presentation... [ fade to music ] */
784 main(int argc, char *argv[])
796 extern char pcap_version[];
799 int pf_open_errno = 0;
802 gboolean start_capture = FALSE;
803 gchar *save_file = NULL;
805 GtkWidget *window, *main_vbox, *menubar, *u_pane, *l_pane,
806 *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox,
807 *tv_scrollw, *filter_bt, *filter_te, *filter_reset;
809 GtkAccelGroup *accel;
810 GtkWidget *packet_sw;
811 gint pl_size = 280, tv_size = 95, bv_size = 75;
812 gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
813 dfilter *rfcode = NULL;
814 gboolean rfilter_parse_failed = FALSE;
817 ethereal_path = argv[0];
820 command_name = strrchr(ethereal_path, '/');
821 if (command_name == NULL)
822 command_name = ethereal_path;
825 /* Set "capture_child" to indicate whether this is going to be a child
826 process for a "-S" capture. */
827 capture_child = (strcmp(command_name, CHILD_NAME) == 0);
830 /* If invoked with the "-G" flag, we dump out a glossary of
831 display filter symbols.
833 We must do this before calling "gtk_init()", because "gtk_init()"
834 tries to open an X display, and we don't want to have to do any X
835 stuff just to do a build.
837 Given that we call "gtk_init()" before doing the regular argument
838 list processing, so that it can handle X and GTK+ arguments and
839 remove them from the list at which we look, this means we must do
840 this before doing the regular argument list processing, as well.
844 you must give the "-G" flag as the first flag on the command line;
846 you must give it as "-G", nothing more, nothing less;
848 any arguments after the "-G" flag will not be used. */
849 if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
850 ethereal_proto_init();
851 proto_registrar_dump();
855 /* Let GTK get its args */
856 gtk_init (&argc, &argv);
858 prefs = read_prefs(&pf_path);
859 if (pf_path != NULL) {
860 /* The preferences file exists, but couldn't be opened; "pf_path" is
861 its pathname. Remember "errno", as that says why the attempt
863 pf_open_errno = errno;
866 /* Initialize the capture file struct */
879 cf.save_file_fd = -1;
881 cf.snap = WTAP_MAX_PACKET_SIZE;
883 cf.cinfo.num_cols = prefs->num_cols;
884 cf.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
885 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
886 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
887 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
888 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
890 /* Assemble the compile-time options */
891 snprintf(comp_info_str, 256,
892 #ifdef GTK_MAJOR_VERSION
893 "GTK+ %d.%d.%d, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
896 "GTK+ (version unknown), %s%s",
900 "with libpcap ", pcap_version
902 "without libpcap", ""
907 /* Now get our args */
908 while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
910 case 'b': /* Bold font */
911 bold_font = g_strdup(optarg);
913 case 'B': /* Byte view pane height */
914 bv_size = atoi(optarg);
916 case 'c': /* Capture xxx packets */
917 cf.count = atoi(optarg);
921 cf.cfilter = g_strdup(optarg);
924 case 'h': /* Print help and exit */
928 case 'i': /* Use interface xxx */
929 cf.iface = g_strdup(optarg);
931 case 'm': /* Medium font */
932 medium_font = g_strdup(optarg);
934 case 'n': /* No name resolution */
935 g_resolving_actif = 0;
938 case 'k': /* Start capture immediately */
939 start_capture = TRUE;
942 case 'P': /* Packet list pane height */
943 pl_size = atoi(optarg);
946 case 'Q': /* Quit after capture (just capture to file) */
948 start_capture = TRUE; /*** -Q implies -k !! ***/
951 case 'r': /* Read capture file xxx */
952 cf_name = g_strdup(optarg);
954 case 'R': /* Read file filter */
958 case 's': /* Set the snapshot (capture) length */
959 cf.snap = atoi(optarg);
961 case 'S': /* "Sync" mode: used for following file ala tail -f */
965 case 't': /* Time stamp type */
966 if (strcmp(optarg, "r") == 0)
967 timestamp_type = RELATIVE;
968 else if (strcmp(optarg, "a") == 0)
969 timestamp_type = ABSOLUTE;
970 else if (strcmp(optarg, "d") == 0)
971 timestamp_type = DELTA;
973 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
975 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
976 fprintf(stderr, "or \"d\" for delta.\n");
980 case 'T': /* Tree view pane height */
981 tv_size = atoi(optarg);
983 case 'v': /* Show version and exit */
984 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
988 case 'w': /* Write to capture file xxx */
989 save_file = g_strdup(optarg);
991 case 'W': /* Write to capture file FD xxx */
992 cf.save_file_fd = atoi(optarg);
995 case '?': /* Bad flag - print usage message */
1003 if (start_capture) {
1004 if (cf.iface == NULL) {
1005 fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1009 if (capture_child) {
1010 if (cf.save_file_fd == -1) {
1011 /* XXX - send this to the standard output as something our parent
1012 should put in an error message box? */
1013 fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1019 /* Build the column format array */
1020 for (i = 0; i < cf.cinfo.num_cols; i++) {
1021 cf.cinfo.col_fmt[i] = get_column_format(i);
1022 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1023 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1025 get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1026 if (cf.cinfo.col_fmt[i] == COL_INFO)
1027 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1029 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1033 cf.snap = WTAP_MAX_PACKET_SIZE;
1034 else if (cf.snap < MIN_PACKET_SIZE)
1035 cf.snap = MIN_PACKET_SIZE;
1037 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1038 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1039 gtk_rc_parse(rc_file);
1041 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1042 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1046 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1047 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1052 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1053 gtk_widget_set_name(window, "main window");
1054 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
1055 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1056 gtk_signal_connect(GTK_OBJECT(window), "destroy",
1057 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1058 gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
1059 gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
1060 gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
1062 /* Container for menu bar, paned windows and progress/info box */
1063 main_vbox = gtk_vbox_new(FALSE, 1);
1064 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1065 gtk_container_add(GTK_CONTAINER(window), main_vbox);
1066 gtk_widget_show(main_vbox);
1069 get_main_menu(&menubar, &accel);
1070 gtk_window_add_accel_group(GTK_WINDOW(window), accel);
1071 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1072 gtk_widget_show(menubar);
1074 /* Panes for the packet list, tree, and byte view */
1075 u_pane = gtk_vpaned_new();
1076 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1077 l_pane = gtk_vpaned_new();
1078 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1079 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1080 gtk_widget_show(u_pane);
1081 gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
1082 gtk_widget_show(l_pane);
1085 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1086 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1087 packet_sw = gtk_scrolled_window_new(NULL, NULL);
1088 gtk_widget_show(packet_sw);
1089 gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
1090 pl_style = gtk_style_new();
1091 gdk_font_unref(pl_style->font);
1092 pl_style->font = m_r_font;
1093 gtk_widget_set_style(packet_list, pl_style);
1094 gtk_widget_set_name(packet_list, "packet list");
1095 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1096 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1097 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1098 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1099 for (i = 0; i < cf.cinfo.num_cols; i++) {
1100 if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1101 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1103 /* Right-justify the packet number column. */
1104 if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1105 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
1108 /* Save static column sizes to use during a "-S" capture, so that
1109 the columns don't resize during a live capture. */
1110 cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1113 gtk_widget_set_usize(packet_list, -1, pl_size);
1114 gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
1115 gtk_widget_show(packet_list);
1118 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1119 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1120 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1121 gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
1122 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1123 gtk_widget_show(tv_scrollw);
1125 tree_view = gtk_tree_new();
1126 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
1128 gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
1130 /* XXX - what's the difference between the next two lines? */
1131 gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
1132 gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
1134 gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
1135 GTK_SIGNAL_FUNC(tree_view_cb), NULL);
1136 gtk_widget_show(tree_view);
1138 item_style = gtk_style_new();
1139 gdk_font_unref(item_style->font);
1140 item_style->font = m_r_font;
1143 bv_table = gtk_table_new (2, 2, FALSE);
1144 gtk_paned_add2(GTK_PANED(l_pane), bv_table);
1145 gtk_widget_set_usize(bv_table, -1, bv_size);
1146 gtk_widget_show(bv_table);
1148 byte_view = gtk_text_new(NULL, NULL);
1149 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1150 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1151 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
1152 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1153 gtk_widget_show(byte_view);
1155 bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
1156 gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
1157 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1158 gtk_widget_show (bv_hscroll);
1160 bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1161 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
1162 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1163 gtk_widget_show(bv_vscroll);
1165 /* Progress/filter/info box */
1166 stat_hbox = gtk_hbox_new(FALSE, 1);
1167 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1168 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1169 gtk_widget_show(stat_hbox);
1171 prog_bar = gtk_progress_bar_new();
1172 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1173 gtk_widget_show(prog_bar);
1175 filter_bt = gtk_button_new_with_label("Filter:");
1176 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1177 GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
1178 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1179 gtk_widget_show(filter_bt);
1181 filter_te = gtk_entry_new();
1182 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1183 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
1184 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1185 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1186 gtk_widget_show(filter_te);
1188 filter_reset = gtk_button_new_with_label("Reset");
1189 gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1190 gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1191 GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1192 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1193 gtk_widget_show(filter_reset);
1195 /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1196 * of any widget that ends up calling a callback which needs
1197 * that text entry pointer */
1198 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1199 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1200 set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY,
1203 info_bar = gtk_statusbar_new();
1204 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1205 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1206 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1207 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1208 gtk_widget_show(info_bar);
1211 Hmmm should we do it here
1214 ethereal_proto_init(); /* Init anything that needs initializing */
1217 /* Is this a "child" ethereal, which is only supposed to pop up a
1218 capture box to let us stop the capture, and run a capture
1219 to a file that our parent will read? */
1220 if (!capture_child) {
1222 /* No. Pop up the main window, and read in a capture file if
1225 gtk_widget_show(window);
1229 /* If we were given the name of a capture file, read it in now;
1230 we defer it until now, so that, if we can't open it, and pop
1231 up an alert box, the alert box is more likely to come up on
1232 top of the main window - but before the preference-file-error
1233 alert box, so, if we get one of those, it's more likely to come
1236 if (rfilter != NULL) {
1237 if (dfilter_compile(rfilter, &rfcode) != 0) {
1238 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1239 rfilter_parse_failed = TRUE;
1242 if (!rfilter_parse_failed) {
1243 if ((err = open_cap_file(cf_name, &cf)) == 0) {
1244 /* "open_cap_file()" succeeded, so it closed the previous
1245 capture file, and thus destroyed any previous read filter
1246 attached to "cf". */
1248 err = read_cap_file(&cf);
1249 s = strrchr(cf_name, '/');
1251 last_open_dir = cf_name;
1254 set_menu_sensitivity("/File/Save As...", TRUE);
1256 dfilter_destroy(rfcode);
1265 /* If we failed to open the preferences file, pop up an alert box;
1266 we defer it until now, so that the alert box is more likely to
1267 come up on top of the main window. */
1268 if (pf_path != NULL) {
1269 simple_dialog(ESD_TYPE_WARN, NULL,
1270 "Could not open preferences file\n\"%s\": %s.", pf_path,
1271 strerror(pf_open_errno));
1275 if (capture_child) {
1276 /* This is the child process for a sync mode or fork mode capture,
1277 so just do the low-level work of a capture - don't create
1278 a temporary file and fork off *another* child process (so don't
1279 call "do_capture()"). */
1283 /* The capture is done; there's nothing more for us to do. */
1286 if (start_capture) {
1287 /* "-k" was specified; start a capture. */
1288 do_capture(save_file);
1295 ethereal_proto_cleanup();