Turn "ethereal_proto_init()" and "ethereal_proto_cleanup()" into
[metze/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.115 2000/04/04 07:03:07 guy Exp $
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@zing.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10  *                              needed by dissect routines
11  * 
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.
16  * 
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.
21  * 
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.
25  *
26  *
27  * To do:
28  * - Graphs
29  * - Check for end of packet in dissect_* routines.
30  * - Playback window
31  * - Multiple window support
32  * - Add cut/copy/paste
33  * - Create header parsing routines
34  * - Make byte view selections more fancy?
35  *
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <gtk/gtk.h>
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51
52 #include <errno.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55
56 #ifdef HAVE_IO_H
57 #include <io.h> /* open/close on win32 */
58 #endif
59
60 #ifdef HAVE_DIRECT_H
61 #include <direct.h>
62 #endif
63
64 #ifdef HAVE_NETINET_IN_H
65 #include <netinet/in.h>
66 #endif
67
68 #include <signal.h>
69
70 #ifdef NEED_SNPRINTF_H
71 # ifdef HAVE_STDARG_H
72 #  include <stdarg.h>
73 # else
74 #  include <varargs.h>
75 # endif
76 # include "snprintf.h"
77 #endif
78
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 */
87 #endif /* SNMP */
88
89 #ifdef NEED_STRERROR_H
90 #include "strerror.h"
91 #endif
92
93 #ifdef NEED_GETOPT_H
94 #include "getopt.h"
95 #endif
96
97 #include "main.h"
98 #include "timestamp.h"
99 #include "packet.h"
100 #include "capture.h"
101 #include "summary.h"
102 #include "file.h"
103 #include "menu.h"
104 #include "../menu.h"
105 #include "filter_prefs.h"
106 #include "prefs_dlg.h"
107 #include "column.h"
108 #include "print.h"
109 #include "resolv.h"
110 #include "follow.h"
111 #include "util.h"
112 #include "simple_dialog.h"
113 #include "proto_draw.h"
114 #include "dfilter.h"
115 #include "keys.h"
116 #include "packet_win.h"
117 #include "gtkglobals.h"
118 #include "plugins.h"
119
120 FILE        *data_out_file = NULL;
121 packet_info  pi;
122 capture_file cf;
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;
133
134 ts_type timestamp_type = RELATIVE;
135
136 GtkStyle *item_style;
137
138 /* Specifies the field currently selected in the GUI protocol tree */
139 field_info *finfo_selected = NULL;
140
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*);
147
148 /* About Ethereal window */
149 void
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"
155
156                 "Check the man page for complete documentation and\n"
157                 "for the list of contributors.\n"
158
159                 "\nSee http://ethereal.zing.org/ for more information.",
160                  comp_info_str);
161 }
162
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). */
166 void
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;
172   int        tmp_fd;
173   gchar     *follow_filter;
174
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.
180
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
184        done. */
185     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
186     if (tmp_fd == -1) {
187       simple_dialog(ESD_TYPE_WARN, NULL,
188         "Could not create temporary file %s: %s", filename1, strerror(errno));
189       return;
190     }
191     data_out_file = fdopen( tmp_fd, "w" );
192     if( data_out_file == NULL ) {
193       simple_dialog(ESD_TYPE_WARN, NULL,
194         "Could not create temporary file %s: %s", filename1, strerror(errno));
195       close(tmp_fd);
196       unlink(filename1);
197       return;
198     }
199
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 );
204
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);
208
209     /* Run the display filter so it goes in effect. */
210     filter_packets(&cf, follow_filter);
211
212     /* the data_out_file should now be full of the streams information */
213     fclose( data_out_file );
214
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
219     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
220                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
221                         
222     if( incomplete_tcp_stream ) {
223       gtk_window_set_title( GTK_WINDOW(streamwindow), 
224                             "Contents of TCP stream (incomplete)" );
225     } else {
226       gtk_window_set_title( GTK_WINDOW(streamwindow),
227                             "Contents of TCP stream" );
228     }
229     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
230     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
231
232     /* setup the container */
233     box = gtk_vbox_new( FALSE, 0 );
234     gtk_container_add( GTK_CONTAINER(streamwindow), box );
235     gtk_widget_show( box );
236
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),
241                                         GTK_POLICY_NEVER,
242                                         GTK_POLICY_ALWAYS );
243     set_scrollbar_placement_scrollw(txt_scrollw, prefs.gui_scrollbar_on_right);
244     remember_scrolled_window(txt_scrollw);
245     gtk_widget_show( txt_scrollw );
246
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);
252
253     /* Create hbox */
254     hbox = gtk_hbox_new( FALSE, 1 );
255     gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
256     gtk_widget_show(hbox);
257
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"
261
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);
271
272     b_ebcdic = gtk_radio_button_new_with_label(
273                     gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
274                     "EBCDIC");
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);
282
283     b_hexdump = gtk_radio_button_new_with_label(
284                     gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
285                     "Hex. Dump");
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);
293
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 );
301
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 );
309
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"
313
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);
317
318     follow_load_text(text, filename1, 0);
319
320     data_out_file = NULL;
321
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 );
327   } else {
328     simple_dialog(ESD_TYPE_WARN, NULL,
329       "Error following stream.  Please make\n"
330       "sure you have a TCP packet selected.");
331   }
332 }
333
334 /* The destroy call back has the responsibility of
335  * unlinking the temporary file */
336 static void
337 follow_destroy_cb(GtkWidget *win, gpointer data)
338 {
339         char    *filename;
340
341         filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
342                                                 E_FOLLOW_FILENAME_KEY);
343         g_assert(filename);
344
345         unlink(filename);
346         gtk_widget_destroy(win);
347 }
348
349 #define E_FOLLOW_ASCII_TYPE     0
350 #define E_FOLLOW_EBCDIC_TYPE    1
351 #define E_FOLLOW_HEXDUMP_TYPE   2
352
353 /* Handles the ASCII/EBCDIC toggling */
354 static void
355 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
356 {
357         guint8          show_type = E_FOLLOW_ASCII_TYPE;
358         GtkWidget       *b_ascii, *b_ebcdic, *b_hexdump, *text;
359         char            *filename;
360
361         b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
362                                                    E_FOLLOW_ASCII_KEY);
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),
368                                                 E_FOLLOW_TEXT_KEY);
369         filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
370                                                 E_FOLLOW_FILENAME_KEY);
371
372         g_assert(b_ascii);
373         g_assert(b_ebcdic);
374         g_assert(b_hexdump);
375         g_assert(text);
376         g_assert(filename);
377
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;
382
383         follow_load_text(text, filename, show_type);
384 }
385
386 #define FLT_BUF_SIZE 1024
387 static void
388 follow_read_stream(char *filename, guint8 show_type,
389    void (*print_line)(char *, int, gboolean, void *), void *arg)
390 {
391   tcp_stream_chunk sc;
392   int bcount;
393   guint32 client_addr = 0;
394   guint16 client_port = 0;
395   gboolean is_server;
396   guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
397   guint16 *global_pos;
398
399   data_out_file = fopen( filename, "r" );
400   if( data_out_file ) {
401     char buffer[FLT_BUF_SIZE];
402     int nchars;
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;
407       }
408       if (client_addr == sc.src_addr && client_port == sc.src_port) {
409         is_server = FALSE;
410         global_pos = &global_client_pos;
411       }
412       else {
413         is_server = TRUE;
414         global_pos = &global_server_pos;
415       }
416         
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 );
420         if (nchars == 0)
421           break;
422         sc.dlen -= bcount;
423         switch (show_type) {
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);
430                  */
431                 (*print_line)( buffer, nchars, is_server, arg );
432                 break;
433         case E_FOLLOW_HEXDUMP_TYPE:
434                 current_pos = 0;
435                 while (current_pos < nchars)
436                 {
437                     gchar hexbuf[256];
438                     gchar hexchars[] = "0123456789abcdef";
439                     int i, cur;
440                     /* is_server indentation : put 63 spaces at the begenning
441                      * of the string */
442                     sprintf(hexbuf, is_server ?
443                             "                                 "
444                             "                              %08X  " :
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];
450                         if (i == 7) {
451                             hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
452                         }
453                         else if (i != 15)
454                             hexbuf[cur++] = ' ';
455                     }
456                     current_pos += i;
457                     (*global_pos) += i;
458                     hexbuf[cur++] = '\n';
459                     hexbuf[cur] = 0;
460                     (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
461                 }
462                 break;
463         }
464       }
465     }
466     if( ferror( data_out_file ) ) {
467       simple_dialog(ESD_TYPE_WARN, NULL,
468         "Error reading temporary file %s: %s", filename, strerror(errno));
469     }
470     fclose( data_out_file );
471     data_out_file = NULL;
472   } else {
473     simple_dialog(ESD_TYPE_WARN, NULL,
474       "Could not open temporary file %s: %s", filename, strerror(errno));
475   }
476 }
477
478 /*
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.
484  *
485  * For now, we support only text printing.
486  */
487 static void
488 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
489 {
490   FILE *fh = arg;
491
492   fwrite(buffer, nchars, 1, fh);
493 }
494
495 static void
496 follow_print_stream(GtkWidget *w, gpointer parent_w)
497 {
498        FILE *fh;
499        gboolean to_file;
500        char* print_dest;
501        char* filename;
502        guint8 show_type = E_FOLLOW_ASCII_TYPE;
503        GtkWidget *button;
504
505        switch (prefs.pr_dest) {
506                case PR_DEST_CMD:
507                        print_dest = prefs.pr_cmd;
508                        to_file = FALSE;
509                        break;
510
511                case PR_DEST_FILE:
512                        print_dest = prefs.pr_file;
513                        to_file = TRUE;
514                        break;
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.");
519                        return;
520        }
521
522        fh = open_print_dest(to_file, print_dest);
523        if (fh == NULL) {
524                switch (to_file) {
525                        case FALSE:
526                                simple_dialog(ESD_TYPE_WARN, NULL,
527                                                "Couldn't run print command %s.", prefs.pr_cmd);
528                                break;
529
530                        case TRUE:
531                                simple_dialog(ESD_TYPE_WARN, NULL, 
532                                                file_write_error_message(errno),
533                                                prefs.pr_file);
534                                break;
535                }
536                return;
537        }
538
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;
547
548        filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
549                        E_FOLLOW_FILENAME_KEY);
550
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);
556        }
557        else {
558                simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
559        }
560 }
561
562 static void
563 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
564 {
565   GtkWidget *text = arg;
566
567   if (is_server)
568     gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
569             &prefs.st_server_bg, buffer, nchars );
570   else
571     gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
572             &prefs.st_client_bg, buffer, nchars );
573 }
574
575 static void
576 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
577 {
578   int bytes_already;
579
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);
585   }
586
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) );
591 }
592
593 /* Match selected byte pattern */
594 void
595 match_selected_cb(GtkWidget *w, gpointer data)
596 {
597     char                *buf;
598     GtkWidget           *filter_te;
599     char                *ptr, *format, *stringified;
600     int                 i, dfilter_len, abbrev_len;
601     guint8              *c;
602     header_field_info   *hfinfo;
603
604     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
605
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.");
611         return;
612     }
613
614     hfinfo = finfo_selected->hfinfo;
615     g_assert(hfinfo);
616     abbrev_len = strlen(hfinfo->abbrev);
617
618         switch(hfinfo->type) {
619
620                 case FT_BOOLEAN:
621                         dfilter_len = abbrev_len + 2;
622                         buf = g_malloc0(dfilter_len);
623                         snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
624                                         hfinfo->abbrev);
625                         break;
626
627                 case FT_UINT8:
628                 case FT_UINT16:
629                 case FT_UINT24:
630                 case FT_UINT32:
631                 case FT_INT8:
632                 case FT_INT16:
633                 case FT_INT24:
634                 case FT_INT32:
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);
639                         break;
640
641                 case FT_IPv4:
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)));
646                         break;
647
648                 case FT_IPXNET:
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);
653                         break;
654
655                 case FT_IPv6:
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,
660                                         stringified);
661                         break;
662
663                 case FT_DOUBLE:
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);
668                         break;
669
670                 case FT_ETHER:
671                         dfilter_len = abbrev_len + 22;
672                         buf = g_malloc0(dfilter_len);
673                         snprintf(buf, dfilter_len, "%s == %s",
674                                         hfinfo->abbrev,
675                                         ether_to_str(finfo_selected->value.ether));
676                         break;
677 #if 0
678
679                 case FT_ABSOLUTE_TIME:
680                 case FT_RELATIVE_TIME:
681                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
682                                 sizeof(struct timeval));
683                         break;
684
685                 case FT_STRING:
686                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
687                         fi->value.string = g_strdup(va_arg(ap, char*));
688                         break;
689
690                 case FT_TEXT_ONLY:
691                         ; /* nothing */
692                         break;
693 #endif
694                 default:
695                     c = cf.pd + finfo_selected->start;
696                     buf = g_malloc0(32 + finfo_selected->length * 3);
697                     ptr = buf;
698
699                     sprintf(ptr, "frame[%d] == ", finfo_selected->start);
700                     ptr = buf+strlen(buf);
701
702                     if (finfo_selected->length == 1) {
703                         sprintf(ptr, "0x%02x", *c++);
704                     }
705                     else {
706                             for (i=0;i<finfo_selected->length; i++) {
707                                 if (i == 0 ) {
708                                         sprintf(ptr, "%02x", *c++);
709                                 }
710                                 else {
711                                         sprintf(ptr, ":%02x", *c++);
712                                 }
713                                 ptr = buf+strlen(buf);
714                             }
715                     }
716                     break;
717         }
718
719     /* create a new one and set the display filter entry accordingly */
720     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
721
722     /* Run the display filter so it goes in effect. */
723     filter_packets(&cf, buf);
724
725     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
726 }
727
728 static char*
729 hfinfo_numeric_format(header_field_info *hfinfo)
730 {
731         char *format = NULL;
732
733         /* Pick the proper format string */
734         switch(hfinfo->display) {
735                 case BASE_DEC:
736                 case BASE_NONE:
737                 case BASE_OCT: /* I'm lazy */
738                 case BASE_BIN: /* I'm lazy */
739                         switch(hfinfo->type) {
740                                 case FT_UINT8:
741                                 case FT_UINT16:
742                                 case FT_UINT24:
743                                 case FT_UINT32:
744                                         format = "%s == %u";
745                                         break;
746                                 case FT_INT8:
747                                 case FT_INT16:
748                                 case FT_INT24:
749                                 case FT_INT32:
750                                         format = "%s == %d";
751                                         break;
752                                 default:
753                                         g_assert_not_reached();
754                                         ;
755                         }
756                         break;
757                 case BASE_HEX:
758                         switch(hfinfo->type) {
759                                 case FT_UINT8:
760                                         format = "%s == 0x%02x";
761                                         break;
762                                 case FT_UINT16:
763                                         format = "%s == 0x%04x";
764                                         break;
765                                 case FT_UINT24:
766                                         format = "%s == 0x%06x";
767                                         break;
768                                 case FT_UINT32:
769                                         format = "%s == 0x%08x";
770                                         break;
771                                 default:
772                                         g_assert_not_reached();
773                                         ;
774                         }
775                         break;
776                 default:
777                         g_assert_not_reached();
778                         ;
779         }
780         return format;
781 }
782
783
784 /* Run the current display filter on the current packet set, and
785    redisplay. */
786 static void
787 filter_activate_cb(GtkWidget *w, gpointer data)
788 {
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;
793   
794   char *s = gtk_entry_get_text(GTK_ENTRY(w));
795   
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);
801     while (li) {
802       if (li->data && strcmp(s, li->data) == 0)
803         add_filter = FALSE;
804       li = li->next;
805     }
806
807     if (add_filter) {
808       filter_list = g_list_append(filter_list, g_strdup(s));
809       li = g_list_first(filter_list);
810       while (li) {
811         nl = g_list_append(nl, strdup(li->data));
812         li = li->next;
813       }
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);
816     }
817   }
818 }
819
820 /* redisplay with no display filter */
821 static void
822 filter_reset_cb(GtkWidget *w, gpointer data)
823 {
824   GtkWidget *filter_te = NULL;
825
826   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
827     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
828   }
829
830   filter_packets(&cf, NULL);
831 }
832
833 /* What to do when a list item is selected/unselected */
834 static void
835 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
836
837 #ifdef HAVE_LIBPCAP
838   if (!sync_mode) {
839 #endif
840     if (cf.wth)
841       return; 
842 #ifdef HAVE_LIBPCAP
843   }
844 #endif
845   blank_packetinfo();
846   select_packet(&cf, row);
847 }
848
849 static void
850 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
851   unselect_packet(&cf);
852 }
853
854 static void
855 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
856 {
857         field_info      *finfo;
858
859         g_assert(node);
860         finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
861         if (!finfo) return;
862
863         finfo_selected = finfo;
864
865         packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
866                 finfo->start, finfo->length, cf.current_frame->encoding);
867 }
868
869 static void
870 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
871 {
872         finfo_selected = NULL;
873         packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
874                 -1, -1, cf.current_frame->encoding);
875 }
876
877 void collapse_all_cb(GtkWidget *widget, gpointer data) {
878   if (cf.protocol_tree)
879     collapse_all_tree(cf.protocol_tree, tree_view);
880 }
881
882 void expand_all_cb(GtkWidget *widget, gpointer data) {
883   if (cf.protocol_tree)
884     expand_all_tree(cf.protocol_tree, tree_view);
885 }
886
887 void resolve_name_cb(GtkWidget *widget, gpointer data) {
888   if (cf.protocol_tree) {
889     int tmp = g_resolving_actif;
890     g_resolving_actif = 1;
891     gtk_clist_clear ( GTK_CLIST(tree_view) );
892     proto_tree_draw(cf.protocol_tree, tree_view);
893     g_resolving_actif = tmp;
894   }
895 }
896
897 /* Set the scrollbar placement of a scrolled window based upon pos value:
898    0 = left, 1 = right */
899 void
900 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
901 {
902         if (pos) {
903                 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
904                                 GTK_CORNER_TOP_LEFT);
905         } else {
906                 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
907                                 GTK_CORNER_TOP_RIGHT);
908         }
909 }
910
911 /* List of all scrolled windows, so we can globally set the scrollbar
912    placement of them. */
913 static GList *scrolled_windows;
914
915 /* Add a scrolled window to the list of scrolled windows. */
916 void
917 remember_scrolled_window(GtkWidget *scrollw)
918 {
919   scrolled_windows = g_list_append(scrolled_windows, scrollw);
920 }
921
922 /* Remove a scrolled window from the list of scrolled windows. */
923 void
924 forget_scrolled_window(GtkWidget *scrollw)
925 {
926   scrolled_windows = g_list_remove(scrolled_windows, scrollw);
927 }
928
929 static void
930 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
931 {
932         set_scrollbar_placement_scrollw((GtkWidget *)data,
933             *(int *)user_data);
934 }
935
936 /* Set the scrollbar placement of all scrolled windows based on pos value:
937    0 = left, 1 = right */
938 void
939 set_scrollbar_placement_all(int pos)
940 {
941         g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
942 }
943
944 /* Set the selection mode of the packet list window. */
945 void
946 set_plist_sel_browse(gboolean val)
947 {
948         if (finfo_selected)
949                 unselect_packet(&cf);
950
951         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
952          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
953         if (val) {
954                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
955         }
956         else {
957                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
958         }
959 }
960
961 /* Set the selection mode of a given packet tree window. */
962 void
963 set_ptree_sel_browse(GtkWidget *tv, gboolean val)
964 {
965         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
966          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
967         if (val) {
968                 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_SINGLE);
969         }
970         else {
971                 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_BROWSE);
972         }
973 }
974
975 /* Set the selection mode of all packet tree windows. */
976 void
977 set_ptree_sel_browse_all(gboolean val)
978 {
979         set_ptree_sel_browse(tree_view, val);
980         set_ptree_sel_browse_packet_wins(val);
981 }
982
983 /* Set the line style of a given packet tree window. */
984 void
985 set_ptree_line_style(GtkWidget *tv, gint style)
986 {
987         /* I'm using an assert here since the preferences code limits
988          * the user input, both in the GUI and when reading the preferences file.
989          * If the value is incorrect, it's a program error, not a user-initiated error.
990          */
991         g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
992         gtk_ctree_set_line_style( GTK_CTREE(tv), style );
993 }
994
995 /* Set the line style of all packet tree window. */
996 void
997 set_ptree_line_style_all(gint style)
998 {
999         set_ptree_line_style(tree_view, style);
1000         set_ptree_line_style_packet_wins(style);
1001 }
1002
1003 /* Set the expander style of a given packet tree window. */
1004 void
1005 set_ptree_expander_style(GtkWidget *tv, gint style)
1006 {
1007         /* I'm using an assert here since the preferences code limits
1008          * the user input, both in the GUI and when reading the preferences file.
1009          * If the value is incorrect, it's a program error, not a user-initiated error.
1010          */
1011         g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
1012         gtk_ctree_set_expander_style( GTK_CTREE(tv), style );
1013 }
1014         
1015 void
1016 set_ptree_expander_style_all(gint style)
1017 {
1018         set_ptree_expander_style(tree_view, style);
1019         set_ptree_expander_style_packet_wins(style);
1020 }
1021
1022 static gboolean
1023 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
1024 {
1025         file_quit_cmd_cb(widget, data);
1026
1027         /* Say that the window should be deleted. */
1028         return FALSE;
1029 }
1030
1031 void
1032 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
1033 {
1034         /* XXX - should we check whether the capture file is an
1035            unsaved temporary file for a live capture and, if so,
1036            pop up a "do you want to exit without saving the capture
1037            file?" dialog, and then just return, leaving said dialog
1038            box to forcibly quit if the user clicks "OK"?
1039
1040            If so, note that this should be done in a subroutine that
1041            returns TRUE if we do so, and FALSE otherwise, and that
1042            "main_window_delete_event_cb()" should return its
1043            return value. */
1044
1045         /* Close any capture file we have open; on some OSes, you can't
1046            unlink a temporary capture file if you have it open.
1047            "close_cap_file()" will unlink it after closing it if
1048            it's a temporary file.
1049
1050            We do this here, rather than after the main loop returns,
1051            as, after the main loop returns, the main window may have
1052            been destroyed (if this is called due to a "destroy"
1053            even on the main window rather than due to the user
1054            selecting a menu item), and there may be a crash
1055            or other problem when "close_cap_file()" tries to
1056            clean up stuff in the main window.
1057
1058            XXX - is there a better place to put this?
1059            Or should we have a routine that *just* closes the
1060            capture file, and doesn't do anything with the UI,
1061            which we'd call here, and another routine that
1062            calls that routine and also cleans up the UI, which
1063            we'd call elsewhere? */
1064         close_cap_file(&cf, info_bar);
1065
1066         /* Exit by leaving the main loop, so that any quit functions
1067            we registered get called. */
1068         gtk_main_quit();
1069 }
1070
1071 static void 
1072 print_usage(void) {
1073
1074   fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1075           comp_info_str);
1076 #ifdef HAVE_LIBPCAP
1077   fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1078           PACKAGE);
1079   fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1080   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1081   fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1082   fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1083 #else
1084   fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1085           PACKAGE);
1086   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1087   fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1088   fprintf(stderr, "\t[ -T <tree view height> ]\n");
1089 #endif
1090 }
1091
1092 /* And now our feature presentation... [ fade to music ] */
1093 int
1094 main(int argc, char *argv[])
1095 {
1096 #ifdef HAVE_LIBPCAP
1097   char                *command_name;
1098 #endif
1099   char                *s;
1100   int                  i;
1101   int                  opt;
1102   extern char         *optarg;
1103   gboolean             arg_error = FALSE;
1104 #ifdef HAVE_LIBPCAP
1105 #ifdef WIN32
1106   char pcap_version[] = "0.4a6";
1107 #else
1108   extern char          pcap_version[];
1109 #endif
1110 #endif
1111   char                *pf_path;
1112   int                  pf_open_errno = 0;
1113   int                  err;
1114 #ifdef HAVE_LIBPCAP
1115   gboolean             start_capture = FALSE;
1116   gchar               *save_file = NULL;
1117   GList               *if_list;
1118   gchar                err_str[PCAP_ERRBUF_SIZE];
1119 #else
1120   gboolean             capture_option_specified = FALSE;
1121 #endif
1122   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1123   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1124   dfilter             *rfcode = NULL;
1125   gboolean             rfilter_parse_failed = FALSE;
1126   e_prefs             *prefs;
1127
1128   ethereal_path = argv[0];
1129
1130 #ifdef HAVE_LIBPCAP
1131   command_name = get_basename(ethereal_path);
1132   /* Set "capture_child" to indicate whether this is going to be a child
1133      process for a "-S" capture. */
1134   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1135 #endif
1136
1137   /* If invoked with the "-G" flag, we dump out a glossary of
1138      display filter symbols.
1139
1140      We must do this before calling "gtk_init()", because "gtk_init()"
1141      tries to open an X display, and we don't want to have to do any X
1142      stuff just to do a build.
1143
1144      Given that we call "gtk_init()" before doing the regular argument
1145      list processing, so that it can handle X and GTK+ arguments and
1146      remove them from the list at which we look, this means we must do
1147      this before doing the regular argument list processing, as well.
1148
1149      This means that:
1150
1151         you must give the "-G" flag as the first flag on the command line;
1152
1153         you must give it as "-G", nothing more, nothing less;
1154
1155         any arguments after the "-G" flag will not be used. */
1156   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1157     dissect_init();
1158     proto_registrar_dump();
1159     exit(0);
1160   }
1161
1162   /* Let GTK get its args */
1163   gtk_init (&argc, &argv);
1164   
1165   prefs = read_prefs(&pf_path);
1166   if (pf_path != NULL) {
1167     /* The preferences file exists, but couldn't be opened; "pf_path" is
1168        its pathname.  Remember "errno", as that says why the attempt
1169        failed. */
1170     pf_open_errno = errno;
1171   }
1172
1173   /* Initialize the capture file struct */
1174   cf.plist              = NULL;
1175   cf.plist_end          = NULL;
1176   cf.wth                = NULL;
1177   cf.fh                 = NULL;
1178   cf.filename           = NULL;
1179   cf.user_saved         = FALSE;
1180   cf.is_tempfile        = FALSE;
1181   cf.rfcode             = NULL;
1182   cf.dfilter            = NULL;
1183   cf.dfcode             = NULL;
1184 #ifdef HAVE_LIBPCAP
1185   cf.cfilter            = g_strdup(EMPTY_FILTER);
1186 #endif
1187   cf.iface              = NULL;
1188   cf.save_file          = NULL;
1189   cf.save_file_fd       = -1;
1190   cf.snap               = WTAP_MAX_PACKET_SIZE;
1191   cf.count              = 0;
1192   cf.cinfo.num_cols     = prefs->num_cols;
1193   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1194   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1195   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1196   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1197   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1198
1199   /* Assemble the compile-time options */
1200   snprintf(comp_info_str, 256,
1201 #ifdef GTK_MAJOR_VERSION
1202     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1203     GTK_MICRO_VERSION,
1204 #else
1205     "GTK+ (version unknown), %s%s, %s%s, %s%s",
1206 #endif
1207
1208 #ifdef HAVE_LIBPCAP
1209    "with libpcap ", pcap_version,
1210 #else
1211    "without libpcap", "",
1212 #endif
1213
1214 #ifdef HAVE_LIBZ
1215 #ifdef ZLIB_VERSION
1216    "with libz ", ZLIB_VERSION,
1217 #else /* ZLIB_VERSION */
1218    "with libz ", "(version unknown)",
1219 #endif /* ZLIB_VERSION */
1220 #else /* HAVE_LIBZ */
1221    "without libz", "",
1222 #endif /* HAVE_LIBZ */
1223
1224 /* Oh, this is pretty */
1225 #if defined(HAVE_UCD_SNMP_SNMP_H)
1226 #ifdef HAVE_UCD_SNMP_VERSION_H
1227    "with UCD SNMP ", VersionInfo
1228 #else /* HAVE_UCD_SNMP_VERSION_H */
1229    "with UCD SNMP ", "(version unknown)"
1230 #endif /* HAVE_UCD_SNMP_VERSION_H */
1231 #elif defined(HAVE_SNMP_SNMP_H)
1232 #ifdef HAVE_SNMP_VERSION_H
1233    "with CMU SNMP ", snmp_Version()
1234 #else /* HAVE_SNMP_VERSION_H */
1235    "with CMU SNMP ", "(version unknown)"
1236 #endif /* HAVE_SNMP_VERSION_H */
1237 #else /* no SNMP */
1238    "without SNMP", ""
1239 #endif
1240    );
1241
1242   /* Now get our args */
1243   while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1244     switch (opt) {
1245       case 'b':        /* Bold font */
1246         bold_font = g_strdup(optarg);
1247         break;
1248       case 'B':        /* Byte view pane height */
1249         bv_size = atoi(optarg);
1250         break;
1251       case 'c':        /* Capture xxx packets */
1252 #ifdef HAVE_LIBPCAP
1253         cf.count = atoi(optarg);
1254 #else
1255         capture_option_specified = TRUE;
1256         arg_error = TRUE;
1257 #endif
1258         break;
1259       case 'D':        /* Turn off DSCP printing */
1260         g_ip_dscp_actif = FALSE;
1261         break;
1262       case 'f':
1263 #ifdef HAVE_LIBPCAP
1264         if (cf.cfilter)
1265                 g_free(cf.cfilter);
1266         cf.cfilter = g_strdup(optarg);
1267 #else
1268         capture_option_specified = TRUE;
1269         arg_error = TRUE;
1270 #endif
1271         break;
1272       case 'h':        /* Print help and exit */
1273         print_usage();
1274         exit(0);
1275         break;
1276       case 'i':        /* Use interface xxx */
1277 #ifdef HAVE_LIBPCAP
1278         cf.iface = g_strdup(optarg);
1279 #else
1280         capture_option_specified = TRUE;
1281         arg_error = TRUE;
1282 #endif
1283         break;
1284       case 'k':        /* Start capture immediately */
1285 #ifdef HAVE_LIBPCAP
1286         start_capture = TRUE;
1287 #else
1288         capture_option_specified = TRUE;
1289         arg_error = TRUE;
1290 #endif
1291         break;
1292       case 'm':        /* Medium font */
1293         medium_font = g_strdup(optarg);
1294         break;
1295       case 'n':        /* No name resolution */
1296         g_resolving_actif = 0;
1297         break;
1298       case 'P':        /* Packet list pane height */
1299         pl_size = atoi(optarg);
1300         break;
1301       case 'Q':        /* Quit after capture (just capture to file) */
1302 #ifdef HAVE_LIBPCAP
1303         quit_after_cap = 1;
1304         start_capture = TRUE;  /*** -Q implies -k !! ***/
1305 #else
1306         capture_option_specified = TRUE;
1307         arg_error = TRUE;
1308 #endif
1309         break;
1310       case 'r':        /* Read capture file xxx */
1311         /* We may set "last_open_dir" to "cf_name", and if we change
1312            "last_open_dir" later, we free the old value, so we have to
1313            set "cf_name" to something that's been allocated. */
1314         cf_name = g_strdup(optarg);
1315         break;
1316       case 'R':        /* Read file filter */
1317         rfilter = optarg;
1318         break;
1319       case 's':        /* Set the snapshot (capture) length */
1320 #ifdef HAVE_LIBPCAP
1321         cf.snap = atoi(optarg);
1322 #else
1323         capture_option_specified = TRUE;
1324         arg_error = TRUE;
1325 #endif
1326         break;
1327       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1328 #ifdef HAVE_LIBPCAP
1329         sync_mode = TRUE;
1330 #else
1331         capture_option_specified = TRUE;
1332         arg_error = TRUE;
1333 #endif
1334         break;
1335       case 't':        /* Time stamp type */
1336         if (strcmp(optarg, "r") == 0)
1337           timestamp_type = RELATIVE;
1338         else if (strcmp(optarg, "a") == 0)
1339           timestamp_type = ABSOLUTE;
1340         else if (strcmp(optarg, "d") == 0)
1341           timestamp_type = DELTA;
1342         else {
1343           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1344             optarg);
1345           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1346           fprintf(stderr, "or \"d\" for delta.\n");
1347           exit(1);
1348         }
1349         break;
1350       case 'T':        /* Tree view pane height */
1351         tv_size = atoi(optarg);
1352         break;
1353       case 'v':        /* Show version and exit */
1354         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1355         exit(0);
1356         break;
1357       case 'w':        /* Write to capture file xxx */
1358 #ifdef HAVE_LIBPCAP
1359         save_file = g_strdup(optarg);
1360 #else
1361         capture_option_specified = TRUE;
1362         arg_error = TRUE;
1363 #endif
1364         break;
1365       case 'W':        /* Write to capture file FD xxx */
1366 #ifdef HAVE_LIBPCAP
1367         cf.save_file_fd = atoi(optarg);
1368 #else
1369         capture_option_specified = TRUE;
1370         arg_error = TRUE;
1371 #endif
1372         break;
1373       default:
1374       case '?':        /* Bad flag - print usage message */
1375         arg_error = TRUE;
1376         break;
1377     }
1378   }
1379
1380 #ifndef HAVE_LIBPCAP
1381   if (capture_option_specified)
1382     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1383 #endif
1384   if (arg_error)
1385     print_usage();
1386 #ifdef HAVE_LIBPCAP
1387   if (start_capture) {
1388     /* We're supposed to do a live capture; did the user specify an interface
1389        to use? */
1390     if (cf.iface == NULL) {
1391       /* No - pick the first one from the list of interfaces. */
1392       if_list = get_interface_list(&err, err_str);
1393       if (if_list == NULL) {
1394         switch (err) {
1395
1396         case CANT_GET_INTERFACE_LIST:
1397             fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1398                         err_str);
1399             break;
1400
1401         case NO_INTERFACES_FOUND:
1402             fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1403             break;
1404         }
1405         exit(2);
1406       }
1407       cf.iface = g_strdup(if_list->data);       /* first interface */
1408       free_interface_list(if_list);
1409     }
1410   }
1411   if (capture_child) {
1412     if (cf.save_file_fd == -1) {
1413       /* XXX - send this to the standard output as something our parent
1414          should put in an error message box? */
1415       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1416       exit(1);
1417     }
1418   }
1419 #endif
1420
1421   /* Build the column format array */  
1422   for (i = 0; i < cf.cinfo.num_cols; i++) {
1423     cf.cinfo.col_fmt[i] = get_column_format(i);
1424     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1425     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1426       NUM_COL_FMTS);
1427     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1428     if (cf.cinfo.col_fmt[i] == COL_INFO)
1429       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1430     else
1431       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1432   }
1433
1434   if (cf.snap < 1)
1435     cf.snap = WTAP_MAX_PACKET_SIZE;
1436   else if (cf.snap < MIN_PACKET_SIZE)
1437     cf.snap = MIN_PACKET_SIZE;
1438   
1439   rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1440   sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1441   gtk_rc_parse(rc_file);
1442
1443   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1444     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1445     exit(1);
1446   }
1447
1448   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1449     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1450     exit(1);
1451   }
1452
1453   create_main_window(pl_size, tv_size, bv_size, prefs);
1454
1455 /* 
1456    Hmmm should we do it here
1457 */
1458
1459   dissect_init();   /* Init anything that needs initializing */
1460
1461 #ifdef HAVE_LIBPCAP
1462   /* Is this a "child" ethereal, which is only supposed to pop up a
1463      capture box to let us stop the capture, and run a capture
1464      to a file that our parent will read? */
1465   if (!capture_child) {
1466 #endif
1467     /* No.  Pop up the main window, and read in a capture file if
1468        we were told to. */
1469
1470     gtk_widget_show(top_level);
1471     set_menus_for_capture_file(FALSE);
1472
1473     cf.colors = colfilter_new();
1474
1475     /* If we were given the name of a capture file, read it in now;
1476        we defer it until now, so that, if we can't open it, and pop
1477        up an alert box, the alert box is more likely to come up on
1478        top of the main window - but before the preference-file-error
1479        alert box, so, if we get one of those, it's more likely to come
1480        up on top of us. */
1481     if (cf_name) {
1482       if (rfilter != NULL) {
1483         if (dfilter_compile(rfilter, &rfcode) != 0) {
1484           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1485           rfilter_parse_failed = TRUE;
1486         }
1487       }
1488       if (!rfilter_parse_failed) {
1489         if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1490           /* "open_cap_file()" succeeded, so it closed the previous
1491              capture file, and thus destroyed any previous read filter
1492              attached to "cf". */
1493           cf.rfcode = rfcode;
1494           err = read_cap_file(&cf);
1495           /* Save the name of the containing directory specified in the
1496              path name, if any; we can write over cf_name, which is a
1497              good thing, given that "get_dirname()" does write over its
1498              argument. */
1499           s = get_dirname(cf_name);
1500           if (s != NULL)
1501             last_open_dir = s;
1502         } else {
1503           dfilter_destroy(rfcode);
1504           cf.rfcode = NULL;
1505         }
1506       }
1507     }
1508 #ifdef HAVE_LIBPCAP
1509   }
1510 #endif
1511
1512   /* If we failed to open the preferences file, pop up an alert box;
1513      we defer it until now, so that the alert box is more likely to
1514      come up on top of the main window. */
1515   if (pf_path != NULL) {
1516       simple_dialog(ESD_TYPE_WARN, NULL,
1517         "Could not open preferences file\n\"%s\": %s.", pf_path,
1518         strerror(pf_open_errno));
1519   }
1520
1521 #ifdef HAVE_LIBPCAP
1522   if (capture_child) {
1523     /* This is the child process for a sync mode or fork mode capture,
1524        so just do the low-level work of a capture - don't create
1525        a temporary file and fork off *another* child process (so don't
1526        call "do_capture()"). */
1527
1528        capture();
1529
1530        /* The capture is done; there's nothing more for us to do. */
1531        gtk_exit(0);
1532   } else {
1533     if (start_capture) {
1534       /* "-k" was specified; start a capture. */
1535       do_capture(save_file);
1536     }
1537     else {
1538       set_menus_for_capture_in_progress(FALSE);
1539     }
1540   }
1541 #else
1542   set_menus_for_capture_in_progress(FALSE);
1543 #endif
1544
1545   gtk_main();
1546
1547   dissect_cleanup();
1548   g_free(rc_file);
1549
1550   gtk_exit(0);
1551
1552   /* This isn't reached, but we need it to keep GCC from complaining
1553      that "main()" returns without returning a value - it knows that
1554      "exit()" never returns, but it doesn't know that "gtk_exit()"
1555      doesn't, as GTK+ doesn't declare it with the attribute
1556      "noreturn". */
1557   return 0;     /* not reached */
1558 }
1559
1560 static void
1561 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1562 {
1563   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
1564                       *stat_hbox,
1565                       *filter_bt, *filter_cm, *filter_te,
1566                       *filter_reset;
1567   GList               *filter_list = NULL;
1568   GtkStyle            *pl_style;
1569   GtkAccelGroup       *accel;
1570   int                   i;
1571
1572   /* Main window */  
1573   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1574   gtk_widget_set_name(top_level, "main window");
1575   gtk_signal_connect(GTK_OBJECT(top_level), "delete_event", 
1576     GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1577   gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1578   gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1579   gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1580
1581   /* Container for menu bar, paned windows and progress/info box */
1582   main_vbox = gtk_vbox_new(FALSE, 1);
1583   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1584   gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1585   gtk_widget_show(main_vbox);
1586
1587   /* Menu bar */
1588   get_main_menu(&menubar, &accel);
1589   gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1590   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1591   gtk_widget_show(menubar);
1592
1593   /* Panes for the packet list, tree, and byte view */
1594   u_pane = gtk_vpaned_new();
1595   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1596   l_pane = gtk_vpaned_new();
1597   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1598   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1599   gtk_widget_show(l_pane);
1600   gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1601   gtk_widget_show(u_pane);
1602
1603   /* Packet list */
1604   pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1605   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1606     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1607   set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1608   remember_scrolled_window(pkt_scrollw);
1609   gtk_widget_show(pkt_scrollw);
1610   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1611
1612   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1613   gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1614   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1615   set_plist_sel_browse(prefs->gui_plist_sel_browse);
1616   pl_style = gtk_style_new();
1617   gdk_font_unref(pl_style->font);
1618   pl_style->font = m_r_font;
1619   gtk_widget_set_style(packet_list, pl_style);
1620   gtk_widget_set_name(packet_list, "packet list");
1621   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1622     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1623   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1624     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1625   for (i = 0; i < cf.cinfo.num_cols; i++) {
1626     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1627       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1628
1629     /* Right-justify the packet number column. */
1630     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1631       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1632         GTK_JUSTIFY_RIGHT);
1633
1634     /* Save static column sizes to use during a "-S" capture, so that
1635        the columns don't resize during a live capture. */
1636     cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1637                                 get_column_longest_string(get_column_format(i)));
1638   }
1639   gtk_widget_set_usize(packet_list, -1, pl_size);
1640   gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1641     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1642   gtk_widget_show(packet_list);
1643
1644   /* Tree view */
1645   create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1646                         prefs->gui_scrollbar_on_right);
1647   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1648     GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1649   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1650     GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1651   gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1652     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1653   gtk_widget_show(tree_view);
1654
1655   item_style = gtk_style_new();
1656   gdk_font_unref(item_style->font);
1657   item_style->font = m_r_font;
1658
1659   /* Byte view. */
1660   create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1661                         prefs->gui_scrollbar_on_right);
1662
1663   /* Progress/filter/info box */
1664   stat_hbox = gtk_hbox_new(FALSE, 1);
1665   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1666   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1667   gtk_widget_show(stat_hbox);
1668
1669   prog_bar = gtk_progress_bar_new();
1670   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1671   gtk_widget_show(prog_bar);
1672
1673   filter_bt = gtk_button_new_with_label("Filter:");
1674   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1675     GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1676   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1677   gtk_widget_show(filter_bt);
1678   
1679   filter_cm = gtk_combo_new();
1680   filter_list = g_list_append (filter_list, "");
1681   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1682   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1683   filter_te = GTK_COMBO(filter_cm)->entry;
1684   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1685   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1686   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1687   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1688   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1689     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1690   gtk_widget_show(filter_cm);
1691
1692   filter_reset = gtk_button_new_with_label("Reset");
1693   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1694   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1695                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1696   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1697   gtk_widget_show(filter_reset);
1698
1699   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1700    * of any widget that ends up calling a callback which needs
1701    * that text entry pointer */
1702   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1703   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1704   set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1705   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1706   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1707
1708   info_bar = gtk_statusbar_new();
1709   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1710   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1711   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1712   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1713   gtk_widget_show(info_bar);
1714 }