Use the new split between protocol registration and protocol handoff
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.114 2000/04/04 06:46:41 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 /* call initialization routines at program startup time */
1072 static void
1073 ethereal_proto_init(void) {
1074   proto_init();
1075   dfilter_init();
1076 #ifdef HAVE_PLUGINS
1077   init_plugins();
1078 #endif
1079 }
1080
1081 static void
1082 ethereal_proto_cleanup(void) {
1083         proto_cleanup();
1084         dfilter_cleanup();
1085 }
1086
1087 static void 
1088 print_usage(void) {
1089
1090   fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1091           comp_info_str);
1092 #ifdef HAVE_LIBPCAP
1093   fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1094           PACKAGE);
1095   fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1096   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1097   fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1098   fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1099 #else
1100   fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1101           PACKAGE);
1102   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1103   fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1104   fprintf(stderr, "\t[ -T <tree view height> ]\n");
1105 #endif
1106 }
1107
1108 /* And now our feature presentation... [ fade to music ] */
1109 int
1110 main(int argc, char *argv[])
1111 {
1112 #ifdef HAVE_LIBPCAP
1113   char                *command_name;
1114 #endif
1115   char                *s;
1116   int                  i;
1117   int                  opt;
1118   extern char         *optarg;
1119   gboolean             arg_error = FALSE;
1120 #ifdef HAVE_LIBPCAP
1121 #ifdef WIN32
1122   char pcap_version[] = "0.4a6";
1123 #else
1124   extern char          pcap_version[];
1125 #endif
1126 #endif
1127   char                *pf_path;
1128   int                  pf_open_errno = 0;
1129   int                  err;
1130 #ifdef HAVE_LIBPCAP
1131   gboolean             start_capture = FALSE;
1132   gchar               *save_file = NULL;
1133   GList               *if_list;
1134   gchar                err_str[PCAP_ERRBUF_SIZE];
1135 #else
1136   gboolean             capture_option_specified = FALSE;
1137 #endif
1138   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1139   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1140   dfilter             *rfcode = NULL;
1141   gboolean             rfilter_parse_failed = FALSE;
1142   e_prefs             *prefs;
1143
1144   ethereal_path = argv[0];
1145
1146 #ifdef HAVE_LIBPCAP
1147   command_name = get_basename(ethereal_path);
1148   /* Set "capture_child" to indicate whether this is going to be a child
1149      process for a "-S" capture. */
1150   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1151 #endif
1152
1153   /* If invoked with the "-G" flag, we dump out a glossary of
1154      display filter symbols.
1155
1156      We must do this before calling "gtk_init()", because "gtk_init()"
1157      tries to open an X display, and we don't want to have to do any X
1158      stuff just to do a build.
1159
1160      Given that we call "gtk_init()" before doing the regular argument
1161      list processing, so that it can handle X and GTK+ arguments and
1162      remove them from the list at which we look, this means we must do
1163      this before doing the regular argument list processing, as well.
1164
1165      This means that:
1166
1167         you must give the "-G" flag as the first flag on the command line;
1168
1169         you must give it as "-G", nothing more, nothing less;
1170
1171         any arguments after the "-G" flag will not be used. */
1172   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1173     ethereal_proto_init();
1174     proto_registrar_dump();
1175     exit(0);
1176   }
1177
1178   /* Let GTK get its args */
1179   gtk_init (&argc, &argv);
1180   
1181   prefs = read_prefs(&pf_path);
1182   if (pf_path != NULL) {
1183     /* The preferences file exists, but couldn't be opened; "pf_path" is
1184        its pathname.  Remember "errno", as that says why the attempt
1185        failed. */
1186     pf_open_errno = errno;
1187   }
1188
1189   /* Initialize the capture file struct */
1190   cf.plist              = NULL;
1191   cf.plist_end          = NULL;
1192   cf.wth                = NULL;
1193   cf.fh                 = NULL;
1194   cf.filename           = NULL;
1195   cf.user_saved         = FALSE;
1196   cf.is_tempfile        = FALSE;
1197   cf.rfcode             = NULL;
1198   cf.dfilter            = NULL;
1199   cf.dfcode             = NULL;
1200 #ifdef HAVE_LIBPCAP
1201   cf.cfilter            = g_strdup(EMPTY_FILTER);
1202 #endif
1203   cf.iface              = NULL;
1204   cf.save_file          = NULL;
1205   cf.save_file_fd       = -1;
1206   cf.snap               = WTAP_MAX_PACKET_SIZE;
1207   cf.count              = 0;
1208   cf.cinfo.num_cols     = prefs->num_cols;
1209   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1210   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1211   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1212   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1213   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1214
1215   /* Assemble the compile-time options */
1216   snprintf(comp_info_str, 256,
1217 #ifdef GTK_MAJOR_VERSION
1218     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1219     GTK_MICRO_VERSION,
1220 #else
1221     "GTK+ (version unknown), %s%s, %s%s, %s%s",
1222 #endif
1223
1224 #ifdef HAVE_LIBPCAP
1225    "with libpcap ", pcap_version,
1226 #else
1227    "without libpcap", "",
1228 #endif
1229
1230 #ifdef HAVE_LIBZ
1231 #ifdef ZLIB_VERSION
1232    "with libz ", ZLIB_VERSION,
1233 #else /* ZLIB_VERSION */
1234    "with libz ", "(version unknown)",
1235 #endif /* ZLIB_VERSION */
1236 #else /* HAVE_LIBZ */
1237    "without libz", "",
1238 #endif /* HAVE_LIBZ */
1239
1240 /* Oh, this is pretty */
1241 #if defined(HAVE_UCD_SNMP_SNMP_H)
1242 #ifdef HAVE_UCD_SNMP_VERSION_H
1243    "with UCD SNMP ", VersionInfo
1244 #else /* HAVE_UCD_SNMP_VERSION_H */
1245    "with UCD SNMP ", "(version unknown)"
1246 #endif /* HAVE_UCD_SNMP_VERSION_H */
1247 #elif defined(HAVE_SNMP_SNMP_H)
1248 #ifdef HAVE_SNMP_VERSION_H
1249    "with CMU SNMP ", snmp_Version()
1250 #else /* HAVE_SNMP_VERSION_H */
1251    "with CMU SNMP ", "(version unknown)"
1252 #endif /* HAVE_SNMP_VERSION_H */
1253 #else /* no SNMP */
1254    "without SNMP", ""
1255 #endif
1256    );
1257
1258   /* Now get our args */
1259   while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1260     switch (opt) {
1261       case 'b':        /* Bold font */
1262         bold_font = g_strdup(optarg);
1263         break;
1264       case 'B':        /* Byte view pane height */
1265         bv_size = atoi(optarg);
1266         break;
1267       case 'c':        /* Capture xxx packets */
1268 #ifdef HAVE_LIBPCAP
1269         cf.count = atoi(optarg);
1270 #else
1271         capture_option_specified = TRUE;
1272         arg_error = TRUE;
1273 #endif
1274         break;
1275       case 'D':        /* Turn off DSCP printing */
1276         g_ip_dscp_actif = FALSE;
1277         break;
1278       case 'f':
1279 #ifdef HAVE_LIBPCAP
1280         if (cf.cfilter)
1281                 g_free(cf.cfilter);
1282         cf.cfilter = g_strdup(optarg);
1283 #else
1284         capture_option_specified = TRUE;
1285         arg_error = TRUE;
1286 #endif
1287         break;
1288       case 'h':        /* Print help and exit */
1289         print_usage();
1290         exit(0);
1291         break;
1292       case 'i':        /* Use interface xxx */
1293 #ifdef HAVE_LIBPCAP
1294         cf.iface = g_strdup(optarg);
1295 #else
1296         capture_option_specified = TRUE;
1297         arg_error = TRUE;
1298 #endif
1299         break;
1300       case 'k':        /* Start capture immediately */
1301 #ifdef HAVE_LIBPCAP
1302         start_capture = TRUE;
1303 #else
1304         capture_option_specified = TRUE;
1305         arg_error = TRUE;
1306 #endif
1307         break;
1308       case 'm':        /* Medium font */
1309         medium_font = g_strdup(optarg);
1310         break;
1311       case 'n':        /* No name resolution */
1312         g_resolving_actif = 0;
1313         break;
1314       case 'P':        /* Packet list pane height */
1315         pl_size = atoi(optarg);
1316         break;
1317       case 'Q':        /* Quit after capture (just capture to file) */
1318 #ifdef HAVE_LIBPCAP
1319         quit_after_cap = 1;
1320         start_capture = TRUE;  /*** -Q implies -k !! ***/
1321 #else
1322         capture_option_specified = TRUE;
1323         arg_error = TRUE;
1324 #endif
1325         break;
1326       case 'r':        /* Read capture file xxx */
1327         /* We may set "last_open_dir" to "cf_name", and if we change
1328            "last_open_dir" later, we free the old value, so we have to
1329            set "cf_name" to something that's been allocated. */
1330         cf_name = g_strdup(optarg);
1331         break;
1332       case 'R':        /* Read file filter */
1333         rfilter = optarg;
1334         break;
1335       case 's':        /* Set the snapshot (capture) length */
1336 #ifdef HAVE_LIBPCAP
1337         cf.snap = atoi(optarg);
1338 #else
1339         capture_option_specified = TRUE;
1340         arg_error = TRUE;
1341 #endif
1342         break;
1343       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1344 #ifdef HAVE_LIBPCAP
1345         sync_mode = TRUE;
1346 #else
1347         capture_option_specified = TRUE;
1348         arg_error = TRUE;
1349 #endif
1350         break;
1351       case 't':        /* Time stamp type */
1352         if (strcmp(optarg, "r") == 0)
1353           timestamp_type = RELATIVE;
1354         else if (strcmp(optarg, "a") == 0)
1355           timestamp_type = ABSOLUTE;
1356         else if (strcmp(optarg, "d") == 0)
1357           timestamp_type = DELTA;
1358         else {
1359           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1360             optarg);
1361           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1362           fprintf(stderr, "or \"d\" for delta.\n");
1363           exit(1);
1364         }
1365         break;
1366       case 'T':        /* Tree view pane height */
1367         tv_size = atoi(optarg);
1368         break;
1369       case 'v':        /* Show version and exit */
1370         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1371         exit(0);
1372         break;
1373       case 'w':        /* Write to capture file xxx */
1374 #ifdef HAVE_LIBPCAP
1375         save_file = g_strdup(optarg);
1376 #else
1377         capture_option_specified = TRUE;
1378         arg_error = TRUE;
1379 #endif
1380         break;
1381       case 'W':        /* Write to capture file FD xxx */
1382 #ifdef HAVE_LIBPCAP
1383         cf.save_file_fd = atoi(optarg);
1384 #else
1385         capture_option_specified = TRUE;
1386         arg_error = TRUE;
1387 #endif
1388         break;
1389       default:
1390       case '?':        /* Bad flag - print usage message */
1391         arg_error = TRUE;
1392         break;
1393     }
1394   }
1395
1396 #ifndef HAVE_LIBPCAP
1397   if (capture_option_specified)
1398     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1399 #endif
1400   if (arg_error)
1401     print_usage();
1402 #ifdef HAVE_LIBPCAP
1403   if (start_capture) {
1404     /* We're supposed to do a live capture; did the user specify an interface
1405        to use? */
1406     if (cf.iface == NULL) {
1407       /* No - pick the first one from the list of interfaces. */
1408       if_list = get_interface_list(&err, err_str);
1409       if (if_list == NULL) {
1410         switch (err) {
1411
1412         case CANT_GET_INTERFACE_LIST:
1413             fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1414                         err_str);
1415             break;
1416
1417         case NO_INTERFACES_FOUND:
1418             fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1419             break;
1420         }
1421         exit(2);
1422       }
1423       cf.iface = g_strdup(if_list->data);       /* first interface */
1424       free_interface_list(if_list);
1425     }
1426   }
1427   if (capture_child) {
1428     if (cf.save_file_fd == -1) {
1429       /* XXX - send this to the standard output as something our parent
1430          should put in an error message box? */
1431       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1432       exit(1);
1433     }
1434   }
1435 #endif
1436
1437   /* Build the column format array */  
1438   for (i = 0; i < cf.cinfo.num_cols; i++) {
1439     cf.cinfo.col_fmt[i] = get_column_format(i);
1440     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1441     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1442       NUM_COL_FMTS);
1443     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1444     if (cf.cinfo.col_fmt[i] == COL_INFO)
1445       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1446     else
1447       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1448   }
1449
1450   if (cf.snap < 1)
1451     cf.snap = WTAP_MAX_PACKET_SIZE;
1452   else if (cf.snap < MIN_PACKET_SIZE)
1453     cf.snap = MIN_PACKET_SIZE;
1454   
1455   rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1456   sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1457   gtk_rc_parse(rc_file);
1458
1459   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1460     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1461     exit(1);
1462   }
1463
1464   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1465     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1466     exit(1);
1467   }
1468
1469   create_main_window(pl_size, tv_size, bv_size, prefs);
1470
1471 /* 
1472    Hmmm should we do it here
1473 */
1474
1475   ethereal_proto_init();   /* Init anything that needs initializing */
1476
1477 #ifdef HAVE_LIBPCAP
1478   /* Is this a "child" ethereal, which is only supposed to pop up a
1479      capture box to let us stop the capture, and run a capture
1480      to a file that our parent will read? */
1481   if (!capture_child) {
1482 #endif
1483     /* No.  Pop up the main window, and read in a capture file if
1484        we were told to. */
1485
1486     gtk_widget_show(top_level);
1487     set_menus_for_capture_file(FALSE);
1488
1489     cf.colors = colfilter_new();
1490
1491     /* If we were given the name of a capture file, read it in now;
1492        we defer it until now, so that, if we can't open it, and pop
1493        up an alert box, the alert box is more likely to come up on
1494        top of the main window - but before the preference-file-error
1495        alert box, so, if we get one of those, it's more likely to come
1496        up on top of us. */
1497     if (cf_name) {
1498       if (rfilter != NULL) {
1499         if (dfilter_compile(rfilter, &rfcode) != 0) {
1500           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1501           rfilter_parse_failed = TRUE;
1502         }
1503       }
1504       if (!rfilter_parse_failed) {
1505         if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1506           /* "open_cap_file()" succeeded, so it closed the previous
1507              capture file, and thus destroyed any previous read filter
1508              attached to "cf". */
1509           cf.rfcode = rfcode;
1510           err = read_cap_file(&cf);
1511           /* Save the name of the containing directory specified in the
1512              path name, if any; we can write over cf_name, which is a
1513              good thing, given that "get_dirname()" does write over its
1514              argument. */
1515           s = get_dirname(cf_name);
1516           if (s != NULL)
1517             last_open_dir = s;
1518         } else {
1519           dfilter_destroy(rfcode);
1520           cf.rfcode = NULL;
1521         }
1522       }
1523     }
1524 #ifdef HAVE_LIBPCAP
1525   }
1526 #endif
1527
1528   /* If we failed to open the preferences file, pop up an alert box;
1529      we defer it until now, so that the alert box is more likely to
1530      come up on top of the main window. */
1531   if (pf_path != NULL) {
1532       simple_dialog(ESD_TYPE_WARN, NULL,
1533         "Could not open preferences file\n\"%s\": %s.", pf_path,
1534         strerror(pf_open_errno));
1535   }
1536
1537 #ifdef HAVE_LIBPCAP
1538   if (capture_child) {
1539     /* This is the child process for a sync mode or fork mode capture,
1540        so just do the low-level work of a capture - don't create
1541        a temporary file and fork off *another* child process (so don't
1542        call "do_capture()"). */
1543
1544        capture();
1545
1546        /* The capture is done; there's nothing more for us to do. */
1547        gtk_exit(0);
1548   } else {
1549     if (start_capture) {
1550       /* "-k" was specified; start a capture. */
1551       do_capture(save_file);
1552     }
1553     else {
1554       set_menus_for_capture_in_progress(FALSE);
1555     }
1556   }
1557 #else
1558   set_menus_for_capture_in_progress(FALSE);
1559 #endif
1560
1561   gtk_main();
1562
1563   ethereal_proto_cleanup();
1564   g_free(rc_file);
1565
1566   gtk_exit(0);
1567
1568   /* This isn't reached, but we need it to keep GCC from complaining
1569      that "main()" returns without returning a value - it knows that
1570      "exit()" never returns, but it doesn't know that "gtk_exit()"
1571      doesn't, as GTK+ doesn't declare it with the attribute
1572      "noreturn". */
1573   return 0;     /* not reached */
1574 }
1575
1576 static void
1577 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1578 {
1579   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
1580                       *stat_hbox,
1581                       *filter_bt, *filter_cm, *filter_te,
1582                       *filter_reset;
1583   GList               *filter_list = NULL;
1584   GtkStyle            *pl_style;
1585   GtkAccelGroup       *accel;
1586   int                   i;
1587
1588   /* Main window */  
1589   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1590   gtk_widget_set_name(top_level, "main window");
1591   gtk_signal_connect(GTK_OBJECT(top_level), "delete_event", 
1592     GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1593   gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1594   gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1595   gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1596
1597   /* Container for menu bar, paned windows and progress/info box */
1598   main_vbox = gtk_vbox_new(FALSE, 1);
1599   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1600   gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1601   gtk_widget_show(main_vbox);
1602
1603   /* Menu bar */
1604   get_main_menu(&menubar, &accel);
1605   gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1606   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1607   gtk_widget_show(menubar);
1608
1609   /* Panes for the packet list, tree, and byte view */
1610   u_pane = gtk_vpaned_new();
1611   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1612   l_pane = gtk_vpaned_new();
1613   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1614   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1615   gtk_widget_show(l_pane);
1616   gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1617   gtk_widget_show(u_pane);
1618
1619   /* Packet list */
1620   pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1621   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1622     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1623   set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1624   remember_scrolled_window(pkt_scrollw);
1625   gtk_widget_show(pkt_scrollw);
1626   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1627
1628   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1629   gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1630   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1631   set_plist_sel_browse(prefs->gui_plist_sel_browse);
1632   pl_style = gtk_style_new();
1633   gdk_font_unref(pl_style->font);
1634   pl_style->font = m_r_font;
1635   gtk_widget_set_style(packet_list, pl_style);
1636   gtk_widget_set_name(packet_list, "packet list");
1637   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1638     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1639   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1640     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1641   for (i = 0; i < cf.cinfo.num_cols; i++) {
1642     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1643       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1644
1645     /* Right-justify the packet number column. */
1646     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1647       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1648         GTK_JUSTIFY_RIGHT);
1649
1650     /* Save static column sizes to use during a "-S" capture, so that
1651        the columns don't resize during a live capture. */
1652     cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1653                                 get_column_longest_string(get_column_format(i)));
1654   }
1655   gtk_widget_set_usize(packet_list, -1, pl_size);
1656   gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1657     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1658   gtk_widget_show(packet_list);
1659
1660   /* Tree view */
1661   create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1662                         prefs->gui_scrollbar_on_right);
1663   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1664     GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1665   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1666     GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1667   gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1668     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1669   gtk_widget_show(tree_view);
1670
1671   item_style = gtk_style_new();
1672   gdk_font_unref(item_style->font);
1673   item_style->font = m_r_font;
1674
1675   /* Byte view. */
1676   create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1677                         prefs->gui_scrollbar_on_right);
1678
1679   /* Progress/filter/info box */
1680   stat_hbox = gtk_hbox_new(FALSE, 1);
1681   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1682   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1683   gtk_widget_show(stat_hbox);
1684
1685   prog_bar = gtk_progress_bar_new();
1686   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1687   gtk_widget_show(prog_bar);
1688
1689   filter_bt = gtk_button_new_with_label("Filter:");
1690   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1691     GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1692   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1693   gtk_widget_show(filter_bt);
1694   
1695   filter_cm = gtk_combo_new();
1696   filter_list = g_list_append (filter_list, "");
1697   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1698   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1699   filter_te = GTK_COMBO(filter_cm)->entry;
1700   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1701   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1702   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1703   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1704   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1705     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1706   gtk_widget_show(filter_cm);
1707
1708   filter_reset = gtk_button_new_with_label("Reset");
1709   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1710   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1711                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1712   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1713   gtk_widget_show(filter_reset);
1714
1715   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1716    * of any widget that ends up calling a callback which needs
1717    * that text entry pointer */
1718   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1719   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1720   set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1721   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1722   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1723
1724   info_bar = gtk_statusbar_new();
1725   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1726   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1727   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1728   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1729   gtk_widget_show(info_bar);
1730 }