* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *
- * To do:
- * - Graphs
- * - Playback window
- * - Multiple window support
- * - Add cut/copy/paste
- * - Create header parsing routines
- * - Make byte view selections more fancy?
*/
#ifdef HAVE_CONFIG_H
#include "main.h"
#include "menu.h"
+#include "../main_window.h"
#include "../menu.h"
#include "file_dlg.h"
#include <epan/column.h>
#include "help_dlg.h"
#include "decode_as_dlg.h"
#include "webbrowser.h"
+#include "capture_dlg.h"
+#if 0
+#include "../image/eicon3d64.xpm"
+#endif
+#include "capture_ui_utils.h"
+
/*
static GtkWidget *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
static GtkWidget *info_bar;
static GtkWidget *packets_bar = NULL;
+static GtkWidget *welcome_pane;
static guint main_ctx, file_ctx, help_ctx;
static guint packets_ctx;
static gchar *packets_str = NULL;
static void create_main_window(gint, gint, gint, e_prefs*);
-static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_);
+static void show_main_window(gboolean);
+static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
static void main_save_window_geometry(GtkWidget *widget);
#define E_DFILTER_CM_KEY "display_filter_combo"
return number;
}
-#ifdef HAVE_LIBPCAP
-/*
- * Given a string of the form "<autostop criterion>:<value>", as might appear
- * as an argument to a "-a" option, parse it and set the criterion in
- * question. Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-set_autostop_criterion(const char *autostoparg)
-{
- gchar *p, *colonp;
-
- colonp = strchr(autostoparg, ':');
- if (colonp == NULL)
- return FALSE;
-
- p = colonp;
- *p++ = '\0';
-
- /*
- * Skip over any white space (there probably won't be any, but
- * as we allow it in the preferences file, we might as well
- * allow it here).
- */
- while (isspace((guchar)*p))
- p++;
- if (*p == '\0') {
- /*
- * Put the colon back, so if our caller uses, in an
- * error message, the string they passed us, the message
- * looks correct.
- */
- *colonp = ':';
- return FALSE;
- }
- if (strcmp(autostoparg,"duration") == 0) {
- capture_opts->has_autostop_duration = TRUE;
- capture_opts->autostop_duration = get_positive_int(p,"autostop duration");
- } else if (strcmp(autostoparg,"filesize") == 0) {
- capture_opts->has_autostop_filesize = TRUE;
- capture_opts->autostop_filesize = get_positive_int(p,"autostop filesize");
- } else {
- return FALSE;
- }
- *colonp = ':'; /* put the colon back */
- return TRUE;
-}
-
-/*
- * Given a string of the form "<ring buffer file>:<duration>", as might appear
- * as an argument to a "-b" option, parse it and set the arguments in
- * question. Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-get_ring_arguments(const char *arg)
-{
- gchar *p = NULL, *colonp;
-
- colonp = strchr(arg, ':');
-
- if (colonp != NULL) {
- p = colonp;
- *p++ = '\0';
- }
-
- capture_opts->ring_num_files =
- get_natural_int(arg, "number of ring buffer files");
-
- if (colonp == NULL)
- return TRUE;
-
- /*
- * Skip over any white space (there probably won't be any, but
- * as we allow it in the preferences file, we might as well
- * allow it here).
- */
- while (isspace((guchar)*p))
- p++;
- if (*p == '\0') {
- /*
- * Put the colon back, so if our caller uses, in an
- * error message, the string they passed us, the message
- * looks correct.
- */
- *colonp = ':';
- return FALSE;
- }
-
- capture_opts->has_file_duration = TRUE;
- capture_opts->file_duration = get_positive_int(p,
- "ring buffer duration");
-
- *colonp = ':'; /* put the colon back */
- return TRUE;
-}
-#endif
-
#if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
/*
Once every 3 seconds we get a callback here which we use to update
}
+/* Set the file name in the status line, in the name for the main window,
+ and in the name for the main window's icon. */
+static void
+set_display_filename(capture_file *cf)
+{
+ const gchar *name_ptr;
+ size_t msg_len;
+ static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
+ static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
+ gchar *done_msg;
+ gchar *win_name_fmt = "%s - Ethereal";
+ gchar *win_name;
+ gchar *size_str;
+
+ name_ptr = cf_get_display_name(cf);
+
+ if (!cf->is_tempfile) {
+ /* Add this filename to the list of recent files in the "Recent Files" submenu */
+ add_menu_recent_capture_file(cf->filename);
+ }
+
+ if (cf->f_len/1024/1024 > 10) {
+ size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
+ } else if (cf->f_len/1024 > 10) {
+ size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
+ } else {
+ size_str = g_strdup_printf("%ld bytes", cf->f_len);
+ }
+
+ if (cf->drops_known) {
+ done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str,
+ cf->esec/3600, cf->esec%3600/60, cf->esec%60, cf->drops);
+ } else {
+ done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
+ cf->esec/3600, cf->esec%3600/60, cf->esec%60);
+ }
+ statusbar_push_file_msg(done_msg);
+ g_free(done_msg);
+
+ msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
+ win_name = g_malloc(msg_len);
+ snprintf(win_name, msg_len, win_name_fmt, name_ptr);
+ set_main_window_name(win_name);
+ g_free(win_name);
+}
+
+
+static void
+main_cf_cb_file_closed(capture_file *cf)
+{
+ /* Destroy all windows, which refer to the
+ capture file we're closing. */
+ destroy_cfile_wins();
+
+ /* Clear any file-related status bar messages.
+ XXX - should be "clear *ALL* file-related status bar messages;
+ will there ever be more than one on the stack? */
+ statusbar_pop_file_msg();
+
+ /* Restore the standard title bar message. */
+ set_main_window_name("The Ethereal Network Analyzer");
+
+ /* Disable all menu items that make sense only if you have a capture. */
+ set_menus_for_capture_file(FALSE);
+ set_menus_for_unsaved_capture_file(FALSE);
+ set_menus_for_captured_packets(FALSE);
+ set_menus_for_selected_packet(cf);
+ set_menus_for_capture_in_progress(FALSE);
+ set_menus_for_selected_tree_row(cf);
+
+ /* Set up main window for no capture file. */
+ main_set_for_capture_file(FALSE);
+}
+
+static void
+main_cf_cb_file_read_start(capture_file *cf)
+{
+ const gchar *name_ptr;
+ gchar *load_msg;
+
+ name_ptr = get_basename(cf->filename);
+
+ load_msg = g_strdup_printf(" Loading: %s", name_ptr);
+ statusbar_push_file_msg(load_msg);
+ g_free(load_msg);
+}
+
+static void
+main_cf_cb_file_read_finished(capture_file *cf)
+{
+ statusbar_pop_file_msg();
+ set_display_filename(cf);
+
+ /* Enable menu items that make sense if you have a capture file you've
+ finished reading. */
+ set_menus_for_capture_file(TRUE);
+ set_menus_for_unsaved_capture_file(!cf->user_saved);
+
+ /* Enable menu items that make sense if you have some captured packets. */
+ set_menus_for_captured_packets(TRUE);
+
+ /* Set up main window for a capture file. */
+ main_set_for_capture_file(TRUE);
+}
+
+#ifdef HAVE_LIBPCAP
+static void
+main_cf_cb_live_capture_prepare(capture_options *capture_opts)
+{
+ gchar *title;
+
+
+ title = g_strdup_printf("%s: Capturing - Ethereal",
+ get_interface_descriptive_name(capture_opts->iface));
+ set_main_window_name(title);
+ g_free(title);
+}
+
+static void
+main_cf_cb_live_capture_started(capture_options *capture_opts)
+{
+ gchar *capture_msg;
+
+ /* Disable menu items that make no sense if you're currently running
+ a capture. */
+ set_menus_for_capture_in_progress(TRUE);
+
+ /* Enable menu items that make sense if you have some captured
+ packets (yes, I know, we don't have any *yet*). */
+ set_menus_for_captured_packets(TRUE);
+
+ capture_msg = g_strdup_printf(" %s: <live capture in progress>", get_interface_descriptive_name(capture_opts->iface));
+
+ statusbar_push_file_msg(capture_msg);
+
+ g_free(capture_msg);
+
+ /* Set up main window for a capture file. */
+ main_set_for_capture_file(TRUE);
+}
+
+static void
+main_cf_cb_live_capture_finished(capture_file *cf)
+{
+ /* Pop the "<live capture in progress>" message off the status bar. */
+ statusbar_pop_file_msg();
+
+ set_display_filename(cf);
+
+ /* Enable menu items that make sense if you're not currently running
+ a capture. */
+ set_menus_for_capture_in_progress(FALSE);
+
+ /* Enable menu items that make sense if you have a capture file
+ you've finished reading. */
+ set_menus_for_capture_file(TRUE);
+ set_menus_for_unsaved_capture_file(!cf->user_saved);
+
+ /* Set up main window for a capture file. */
+ main_set_for_capture_file(TRUE);
+}
+#endif
+
+static void
+main_cf_cb_packet_selected(gpointer data)
+{
+ capture_file *cf = data;
+
+ /* Display the GUI protocol tree and hex dump.
+ XXX - why do we dump core if we call "proto_tree_draw()"
+ before calling "add_byte_views()"? */
+ add_main_byte_views(cf->edt);
+ main_proto_tree_draw(cf->edt->tree);
+
+ /* A packet is selected. */
+ set_menus_for_selected_packet(cf);
+}
+
+static void
+main_cf_cb_packet_unselected(capture_file *cf)
+{
+ /* Clear out the display of that packet. */
+ clear_tree_and_hex_views();
+
+ /* No packet is selected. */
+ set_menus_for_selected_packet(cf);
+}
+
+static void
+main_cf_cb_field_unselected(capture_file *cf)
+{
+ statusbar_pop_field_msg();
+ set_menus_for_selected_tree_row(cf);
+}
+
+static void
+main_cf_cb_file_safe_started(gchar * filename)
+{
+ const gchar *name_ptr;
+ gchar *save_msg;
+
+ name_ptr = get_basename(filename);
+
+ save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
+
+ statusbar_push_file_msg(save_msg);
+ g_free(save_msg);
+}
+
+static void
+main_cf_cb_file_safe_finished(gpointer data _U_)
+{
+ /* Pop the "Saving:" message off the status bar. */
+ statusbar_pop_file_msg();
+}
+
+static void
+main_cf_cb_file_safe_failed(gpointer data _U_)
+{
+ /* Pop the "Saving:" message off the status bar. */
+ statusbar_pop_file_msg();
+}
+
+static void
+main_cf_cb_file_safe_reload_finished(gpointer data _U_)
+{
+ set_menus_for_unsaved_capture_file(FALSE);
+}
+
+void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
+{
+ switch(event) {
+ case(cf_cb_file_closed):
+ main_cf_cb_file_closed(data);
+ break;
+ case(cf_cb_file_read_start):
+ main_cf_cb_file_read_start(data);
+ break;
+ case(cf_cb_file_read_finished):
+ main_cf_cb_file_read_finished(data);
+ break;
+#ifdef HAVE_LIBPCAP
+ case(cf_cb_live_capture_prepare):
+ main_cf_cb_live_capture_prepare(data);
+ break;
+ case(cf_cb_live_capture_started):
+ main_cf_cb_live_capture_started(data);
+ break;
+ case(cf_cb_live_capture_finished):
+ main_cf_cb_live_capture_finished(data);
+ break;
+#endif
+ case(cf_cb_packet_selected):
+ main_cf_cb_packet_selected(data);
+ break;
+ case(cf_cb_packet_unselected):
+ main_cf_cb_packet_unselected(data);
+ break;
+ case(cf_cb_field_unselected):
+ main_cf_cb_field_unselected(data);
+ break;
+ case(cf_cb_file_safe_started):
+ main_cf_cb_file_safe_started(data);
+ break;
+ case(cf_cb_file_safe_finished):
+ main_cf_cb_file_safe_finished(data);
+ break;
+ case(cf_cb_file_safe_reload_finished):
+ main_cf_cb_file_safe_reload_finished(data);
+ break;
+ case(cf_cb_file_safe_failed):
+ main_cf_cb_file_safe_failed(data);
+ break;
+ default:
+ g_warning("main_cf_callback: event %u unknown", event);
+ g_assert_not_reached();
+ }
+}
/* And now our feature presentation... [ fade to music ] */
int
int err;
#ifdef HAVE_LIBPCAP
gboolean start_capture = FALSE;
- gchar *save_file = NULL;
GList *if_list;
if_info_t *if_info;
GList *lt_list, *lt_entry;
/* Let GTK get its args */
gtk_init (&argc, &argv);
+ cf_callback_add(main_cf_callback, NULL);
+
#if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
/* initialize our GTK eth_clist_type */
init_eth_clist_type();
#endif
#ifdef HAVE_LIBPCAP
+ /* Set the initial values in the capture_opts. This might be overwritten
+ by preference settings and then again by the command line parameters. */
+ capture_opts_init(capture_opts, &cfile);
+
+ capture_opts->snaplen = MIN_PACKET_SIZE;
+ capture_opts->has_ring_num_files = TRUE;
+
command_name = get_basename(ethereal_path);
/* Set "capture_child" to indicate whether this is going to be a child
process for a "-S" capture. */
capture_opts->capture_child = (strcmp(command_name, CHILD_NAME) == 0);
- /* We want a splash screen only if we're not a child process */
if (capture_opts->capture_child) {
strcat(optstring, OPTSTRING_CHILD);
- } else
+ }
#endif
- {
+
+ /* We want a splash screen only if we're not a child process */
/* We also want it only if we're not being run with "-G".
XXX - we also don't want it if we're being run with
"-h" or "-v", as those are options to run Ethereal and just
that means we'd have to queue up, for example, "-o" options,
so that we apply them *after* reading the preferences, as
they're supposed to override saved preferences. */
- if (argc < 2 || strcmp(argv[1], "-G") != 0) {
- splash_win = splash_new("Loading Ethereal ...");
- }
+ if ((argc < 2 || strcmp(argv[1], "-G") != 0)
+#ifdef HAVE_LIBPCAP
+ && !capture_opts->capture_child
+#endif
+ ) {
+ splash_win = splash_new("Loading Ethereal ...");
}
splash_update(splash_win, "Registering dissectors ...");
}
#ifdef _WIN32
+ /* if the user wants a console to be always there, well, we should open one for him */
if (prefs->gui_console_open == console_open_always) {
create_console();
}
#endif
- capture_opts->cf = &cfile;
#ifdef HAVE_LIBPCAP
- capture_opts->has_snaplen = FALSE;
- capture_opts->snaplen = MIN_PACKET_SIZE;
- capture_opts->linktype = -1;
-#ifdef _WIN32
- capture_opts->buffer_size = 1;
-#endif
- capture_opts->save_file_fd = -1;
- capture_opts->quit_after_cap = FALSE;
-
- capture_opts->has_autostop_packets = FALSE;
- capture_opts->autostop_packets = 1;
- capture_opts->has_autostop_duration = FALSE;
- capture_opts->autostop_duration = 60 /* 1 min */;
- capture_opts->has_autostop_filesize = FALSE;
- capture_opts->autostop_filesize = 1024 * 1024 /* 1 MB */;
- capture_opts->has_autostop_files = FALSE;
- capture_opts->autostop_files = 1;
-
- capture_opts->multi_files_on = FALSE;
- capture_opts->has_ring_num_files = TRUE;
- capture_opts->ring_num_files = 2;
- capture_opts->has_file_duration = FALSE;
- capture_opts->file_duration = 60 /* 1 min */;
-
/* If this is a capture child process, it should pay no attention
to the "prefs.capture_prom_mode" setting in the preferences file;
it should do what the parent process tells it to do, and if
Otherwise, set promiscuous mode from the preferences setting. */
/* the same applies to other preferences settings as well. */
if (capture_opts->capture_child) {
- capture_opts->promisc_mode = TRUE; /* maybe changed by command line below */
- capture_opts->show_info = TRUE; /* maybe changed by command line below */
- capture_opts->sync_mode = TRUE; /* always true in child process */
- auto_scroll_live = FALSE; /* doesn't matter in child process */
-
+ auto_scroll_live = FALSE;
} else {
capture_opts->promisc_mode = prefs->capture_prom_mode;
capture_opts->show_info = prefs->capture_show_info;
capture_opts->sync_mode = prefs->capture_real_time;
- auto_scroll_live = prefs->capture_auto_scroll;
+ auto_scroll_live = prefs->capture_auto_scroll;
}
#endif /* HAVE_LIBPCAP */
/* Now get our args */
while ((opt = getopt(argc, argv, optstring)) != -1) {
switch (opt) {
+ /*** capture option specific ***/
case 'a': /* autostop criteria */
+ case 'b': /* Ringbuffer option */
+ case 'c': /* Capture xxx packets */
+ case 'f': /* capture filter */
+ case 'k': /* Start capture immediately */
+ case 'H': /* Hide capture info dialog box */
+ case 'i': /* Use interface xxx */
+ case 'p': /* Don't capture in promiscuous mode */
+ case 'Q': /* Quit after capture (just capture to file) */
+ case 's': /* Set the snapshot (capture) length */
+ case 'S': /* "Sync" mode: used for following file ala tail -f */
+ case 'w': /* Write to capture file xxx */
+ case 'y': /* Set the pcap data link type */
+#ifdef _WIN32
+ /* Hidden option supporting Sync mode */
+ case 'Z': /* Write to pipe FD XXX */
+#endif /* _WIN32 */
#ifdef HAVE_LIBPCAP
- if (set_autostop_criterion(optarg) == FALSE) {
- fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
- exit(1);
- }
+ capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
#else
capture_option_specified = TRUE;
arg_error = TRUE;
#endif
break;
- case 'b': /* Ringbuffer option */
#ifdef HAVE_LIBPCAP
- capture_opts->multi_files_on = TRUE;
- capture_opts->has_ring_num_files = TRUE;
- if (get_ring_arguments(optarg) == FALSE) {
- fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
- exit(1);
- }
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
+ /* This is a hidden option supporting Sync mode, so we don't set
+ * the error flags for the user in the non-libpcap case.
+ */
+ case 'W': /* Write to capture file FD xxx */
+ capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
+ break;
#endif
- break;
+
+ /*** all non capture option specific ***/
case 'B': /* Byte view pane height */
bv_size = get_positive_int(optarg, "byte view pane height");
break;
- case 'c': /* Capture xxx packets */
-#ifdef HAVE_LIBPCAP
- capture_opts->has_autostop_packets = TRUE;
- capture_opts->autostop_packets = get_positive_int(optarg, "packet count");
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
- case 'f':
-#ifdef HAVE_LIBPCAP
- if (cfile.cfilter)
- g_free(cfile.cfilter);
- cfile.cfilter = g_strdup(optarg);
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'h': /* Print help and exit */
print_usage(TRUE);
exit(0);
break;
- case 'i': /* Use interface xxx */
-#ifdef HAVE_LIBPCAP
- cfile.iface = g_strdup(optarg);
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
- case 'k': /* Start capture immediately */
-#ifdef HAVE_LIBPCAP
- start_capture = TRUE;
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'l': /* Automatic scrolling in live capture mode */
#ifdef HAVE_LIBPCAP
auto_scroll_live = TRUE;
#else
capture_option_specified = TRUE;
arg_error = TRUE;
-#endif
- break;
- case 'H': /* Hide capture info dialog box */
-#ifdef HAVE_LIBPCAP
- capture_opts->show_info = FALSE;
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
#endif
break;
case 'L': /* Print list of link-layer types and exit */
break;
}
break;
- case 'p': /* Don't capture in promiscuous mode */
-#ifdef HAVE_LIBPCAP
- capture_opts->promisc_mode = FALSE;
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'P': /* Packet list pane height */
pl_size = get_positive_int(optarg, "packet list pane height");
break;
- case 'Q': /* Quit after capture (just capture to file) */
-#ifdef HAVE_LIBPCAP
- capture_opts->quit_after_cap = TRUE;
- start_capture = TRUE; /*** -Q implies -k !! ***/
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'r': /* Read capture file xxx */
/* We may set "last_open_dir" to "cf_name", and if we change
"last_open_dir" later, we free the old value, so we have to
case 'R': /* Read file filter */
rfilter = optarg;
break;
- case 's': /* Set the snapshot (capture) length */
-#ifdef HAVE_LIBPCAP
- capture_opts->has_snaplen = TRUE;
- capture_opts->snaplen = get_positive_int(optarg, "snapshot length");
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
- case 'S': /* "Sync" mode: used for following file ala tail -f */
-#ifdef HAVE_LIBPCAP
- capture_opts->sync_mode = TRUE;
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 't': /* Time stamp type */
if (strcmp(optarg, "r") == 0)
set_timestamp_setting(TS_RELATIVE);
#endif
exit(0);
break;
- case 'w': /* Write to capture file xxx */
-#ifdef HAVE_LIBPCAP
- save_file = g_strdup(optarg);
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
- case 'y': /* Set the pcap data link type */
-#ifdef HAVE_LIBPCAP
-#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
- capture_opts->linktype = pcap_datalink_name_to_val(optarg);
- if (capture_opts->linktype == -1) {
- fprintf(stderr, "ethereal: The specified data link type \"%s\" isn't valid\n",
- optarg);
- exit(1);
- }
-#else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
- /* XXX - just treat it as a number */
- capture_opts->linktype = get_natural_int(optarg, "data link type");
-#endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-#else /* HAVE_LIBPCAP */
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif /* HAVE_LIBPCAP */
- break;
-#ifdef HAVE_LIBPCAP
- /* This is a hidden option supporting Sync mode, so we don't set
- * the error flags for the user in the non-libpcap case.
- */
- case 'W': /* Write to capture file FD xxx */
- capture_opts->save_file_fd = atoi(optarg);
- break;
-#endif
case 'z':
for(tli=tap_list;tli;tli=tli->next){
if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
exit(1);
}
break;
-
-#ifdef _WIN32
-#ifdef HAVE_LIBPCAP
- /* Hidden option supporting Sync mode */
- case 'Z': /* Write to pipe FD XXX */
- /* associate stdout with pipe */
- i = atoi(optarg);
- if (dup2(i, 1) < 0) {
- fprintf(stderr, "Unable to dup pipe handle\n");
- exit(1);
- }
- break;
-#endif /* HAVE_LIBPCAP */
-#endif /* _WIN32 */
-
default:
case '?': /* Bad flag - print usage message */
arg_error = TRUE;
argv++;
}
+
+
if (argc != 0) {
/*
* Extra command line arguments were specified; complain.
arg_error = TRUE;
}
+ if (arg_error) {
#ifndef HAVE_LIBPCAP
- if (capture_option_specified)
- fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
+ if (capture_option_specified) {
+ fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
+ }
#endif
- if (arg_error) {
print_usage(FALSE);
exit(1);
}
sync_mode takes precedence;
c) it makes no sense to enable the ring buffer if the maximum
file size is set to "infinite". */
- if (save_file == NULL) {
+ if (capture_opts->save_file == NULL) {
fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
capture_opts->multi_files_on = FALSE;
}
if (start_capture || list_link_layer_types) {
/* Did the user specify an interface to use? */
- if (cfile.iface == NULL) {
+ if (capture_opts->iface == NULL) {
/* No - is a default specified in the preferences file? */
if (prefs->capture_device != NULL) {
/* Yes - use it. */
- cfile.iface = g_strdup(prefs->capture_device);
+ capture_opts->iface = g_strdup(prefs->capture_device);
} else {
/* No - pick the first one from the list of interfaces. */
if_list = get_interface_list(&err, err_str);
exit(2);
}
if_info = if_list->data; /* first interface */
- cfile.iface = g_strdup(if_info->name);
+ capture_opts->iface = g_strdup(if_info->name);
free_interface_list(if_list);
}
}
if (list_link_layer_types) {
/* Get the list of link-layer types for the capture device. */
- lt_list = get_pcap_linktype_list(cfile.iface, err_str);
+ lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
if (lt_list == NULL) {
if (err_str[0] != '\0') {
fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
exit(0);
}
+ if (capture_opts->has_snaplen) {
+ if (capture_opts->snaplen < 1)
+ capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
+ else if (capture_opts->snaplen < MIN_PACKET_SIZE)
+ capture_opts->snaplen = MIN_PACKET_SIZE;
+ }
+
+ /* Check the value range of the ringbuffer_num_files parameter */
+ if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
+ capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
+#if RINGBUFFER_MIN_NUM_FILES > 0
+ else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
+ capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
#endif
+#endif /* HAVE_LIBPCAP */
/* Notify all registered modules that have had any of their preferences
changed either from one of the preferences file or from the command
}
}
-#ifdef HAVE_LIBPCAP
- if (capture_opts->has_snaplen) {
- if (capture_opts->snaplen < 1)
- capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
- else if (capture_opts->snaplen < MIN_PACKET_SIZE)
- capture_opts->snaplen = MIN_PACKET_SIZE;
- }
-
- /* Check the value range of the ringbuffer_num_files parameter */
- if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
- capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
-#if RINGBUFFER_MIN_NUM_FILES > 0
- else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
- capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
-#endif
-#endif
-
/* read in rc file from global and personal configuration paths. */
/* XXX - is this a good idea? */
gtk_rc_parse(RC_FILE);
/* close the splash screen, as we are going to open the main window now */
splash_destroy(splash_win);
+
#ifdef HAVE_LIBPCAP
/* Is this a "child" ethereal, which is only supposed to pop up a
capture box to let us stop the capture, and run a capture
to a file that our parent will read? */
- if (!capture_opts->capture_child) {
-#endif
- /* No. Pop up the main window, and read in a capture file if
- we were told to. */
- create_main_window(pl_size, tv_size, bv_size, prefs);
-
- /* Read the recent file, as we have the gui now ready for it. */
- read_recent(&rf_path, &rf_open_errno);
+ if (capture_opts->capture_child) {
+ /* This is the child process for a sync mode or fork mode capture,
+ so just do the low-level work of a capture - don't create
+ a temporary file and fork off *another* child process (so don't
+ call "do_capture()"). */
- /* rearrange all the widgets as we now have the recent settings for this */
- main_widgets_rearrange();
+ /* Pop up any queued-up alert boxes. */
+ display_queued_messages();
- /* Fill in column titles. This must be done after the top level window
- is displayed.
+ /* XXX - hand these stats to the parent process */
+ capture_start(capture_opts, &stats_known, &stats);
- XXX - is that still true, with fixed-width columns? */
- packet_list_set_column_titles();
+ /* The capture is done; there's nothing more for us to do. */
+ gtk_exit(0);
+ }
+#endif
- menu_recent_read_finished();
+ /***********************************************************************/
+ /* Everything is prepared now, preferences and command line was read in,
+ we are NOT a child window for a synced capture. */
+
+ /* Pop up the main window, and read in a capture file if
+ we were told to. */
+ create_main_window(pl_size, tv_size, bv_size, prefs);
+
+ /* Read the recent file, as we have the gui now ready for it. */
+ read_recent(&rf_path, &rf_open_errno);
+
+ /* rearrange all the widgets as we now have the recent settings for this */
+ main_widgets_rearrange();
+
+ /* Fill in column titles. This must be done after the top level window
+ is displayed.
+
+ XXX - is that still true, with fixed-width columns? */
+ packet_list_set_column_titles();
+
+ menu_recent_read_finished();
+
+ switch (user_font_apply()) {
+ case FA_SUCCESS:
+ break;
+ case FA_FONT_NOT_RESIZEABLE:
+ /* "user_font_apply()" popped up an alert box. */
+ /* turn off zooming - font can't be resized */
+ case FA_FONT_NOT_AVAILABLE:
+ /* XXX - did we successfully load the un-zoomed version earlier?
+ If so, this *probably* means the font is available, but not at
+ this particular zoom level, but perhaps some other failure
+ occurred; I'm not sure you can determine which is the case,
+ however. */
+ /* turn off zooming - zoom level is unavailable */
+ default:
+ /* in any other case than FA_SUCCESS, turn off zooming */
+ recent.gui_zoom_level = 0;
+ /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
+ }
- switch (user_font_apply()) {
- case FA_SUCCESS:
- break;
- case FA_FONT_NOT_RESIZEABLE:
- /* "user_font_apply()" popped up an alert box. */
- /* turn off zooming - font can't be resized */
- case FA_FONT_NOT_AVAILABLE:
- /* XXX - did we successfully load the un-zoomed version earlier?
- If so, this *probably* means the font is available, but not at
- this particular zoom level, but perhaps some other failure
- occurred; I'm not sure you can determine which is the case,
- however. */
- /* turn off zooming - zoom level is unavailable */
- default:
- /* in any other case than FA_SUCCESS, turn off zooming */
- recent.gui_zoom_level = 0;
- /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
+ dnd_init(top_level);
+
+ colors_init();
+ colfilter_init();
+ decode_as_init();
+
+ /* the window can be sized only, if it's not already shown, so do it now! */
+ main_load_window_geometry(top_level);
+
+ /* If we were given the name of a capture file, read it in now;
+ we defer it until now, so that, if we can't open it, and pop
+ up an alert box, the alert box is more likely to come up on
+ top of the main window - but before the preference-file-error
+ alert box, so, if we get one of those, it's more likely to come
+ up on top of us. */
+ if (cf_name) {
+ show_main_window(TRUE);
+ if (rfilter != NULL) {
+ if (!dfilter_compile(rfilter, &rfcode)) {
+ bad_dfilter_alert_box(rfilter);
+ rfilter_parse_failed = TRUE;
+ }
}
-
- dnd_init(top_level);
-
- colors_init();
- colfilter_init();
- decode_as_init();
-
- /* the window can be sized only, if it's not already shown, so do it now! */
- main_load_window_geometry(top_level);
-
- /*** we have finished all init things, show the main window ***/
- gtk_widget_show(top_level);
-
- /* the window can be maximized only, if it's visible, so do it after show! */
- main_load_window_geometry(top_level);
-
- /* process all pending GUI events before continue */
- while (gtk_events_pending()) gtk_main_iteration();
-
- /* Pop up any queued-up alert boxes. */
- display_queued_messages();
-
- /* If we were given the name of a capture file, read it in now;
- we defer it until now, so that, if we can't open it, and pop
- up an alert box, the alert box is more likely to come up on
- top of the main window - but before the preference-file-error
- alert box, so, if we get one of those, it's more likely to come
- up on top of us. */
- if (cf_name) {
- if (rfilter != NULL) {
- if (!dfilter_compile(rfilter, &rfcode)) {
- bad_dfilter_alert_box(rfilter);
- rfilter_parse_failed = TRUE;
+ if (!rfilter_parse_failed) {
+ if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
+ /* "cf_open()" succeeded, so it closed the previous
+ capture file, and thus destroyed any previous read filter
+ attached to "cf". */
+
+ cfile.rfcode = rfcode;
+ /* Open tap windows; we do so after creating the main window,
+ to avoid GTK warnings, and after successfully opening the
+ capture file, so we know we have something to tap. */
+ if (tap_opt && tli) {
+ (*tli->func)(tap_opt);
+ g_free(tap_opt);
}
- }
- if (!rfilter_parse_failed) {
- if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
- /* "cf_open()" succeeded, so it closed the previous
- capture file, and thus destroyed any previous read filter
- attached to "cf". */
- cfile.rfcode = rfcode;
-
- /* Open tap windows; we do so after creating the main window,
- to avoid GTK warnings, and after successfully opening the
- capture file, so we know we have something to tap. */
- if (tap_opt && tli) {
- (*tli->func)(tap_opt);
- g_free(tap_opt);
- }
- /* Read the capture file. */
- switch (cf_read(&cfile)) {
+ /* Read the capture file. */
+ switch (cf_read(&cfile)) {
- case CF_READ_OK:
- case CF_READ_ERROR:
- /* Just because we got an error, that doesn't mean we were unable
- to read any of the file; we handle what we could get from the
- file. */
- break;
+ case CF_READ_OK:
+ case CF_READ_ERROR:
+ /* Just because we got an error, that doesn't mean we were unable
+ to read any of the file; we handle what we could get from the
+ file. */
+ break;
- case CF_READ_ABORTED:
- /* Exit now. */
- gtk_exit(0);
- break;
- }
- /* Save the name of the containing directory specified in the
- path name, if any; we can write over cf_name, which is a
- good thing, given that "get_dirname()" does write over its
- argument. */
- s = get_dirname(cf_name);
- /* we might already set this from the recent file, don't overwrite this */
- if(get_last_open_dir() == NULL)
- set_last_open_dir(s);
- g_free(cf_name);
- cf_name = NULL;
- } else {
- if (rfcode != NULL)
- dfilter_free(rfcode);
- cfile.rfcode = NULL;
+ case CF_READ_ABORTED:
+ /* Exit now. */
+ gtk_exit(0);
+ break;
}
+ /* Save the name of the containing directory specified in the
+ path name, if any; we can write over cf_name, which is a
+ good thing, given that "get_dirname()" does write over its
+ argument. */
+ s = get_dirname(cf_name);
+ /* we might already set this from the recent file, don't overwrite this */
+ if(get_last_open_dir() == NULL)
+ set_last_open_dir(s);
+ g_free(cf_name);
+ cf_name = NULL;
+ } else {
+ if (rfcode != NULL)
+ dfilter_free(rfcode);
+ cfile.rfcode = NULL;
}
}
+ } else {
#ifdef HAVE_LIBPCAP
if (start_capture) {
+ if (capture_opts->save_file != NULL) {
+ /* Save the directory name for future file dialogs. */
+ /* (get_dirname overwrites filename) */
+ s = get_dirname(g_strdup(capture_opts->save_file));
+ set_last_open_dir(s);
+ g_free(s);
+ }
/* "-k" was specified; start a capture. */
- if (do_capture(capture_opts, save_file)) {
+ show_main_window(TRUE);
+ if (do_capture(capture_opts)) {
/* The capture started. Open tap windows; we do so after creating
the main window, to avoid GTK warnings, and after starting the
capture, so we know we have something to tap. */
g_free(tap_opt);
}
}
- if (save_file != NULL) {
- /* Save the directory name for future file dialogs. */
- s = get_dirname(save_file); /* Overwrites save_file */
- set_last_open_dir(s);
- g_free(save_file);
- save_file = NULL;
- }
}
else {
+ show_main_window(FALSE);
set_menus_for_capture_in_progress(FALSE);
}
- } else {
- /* This is the child process for a sync mode or fork mode capture,
- so just do the low-level work of a capture - don't create
- a temporary file and fork off *another* child process (so don't
- call "do_capture()"). */
- /* Pop up any queued-up alert boxes. */
- display_queued_messages();
-
- /* XXX - hand these stats to the parent process */
- capture_start(capture_opts, &stats_known, &stats);
-
- /* The capture is done; there's nothing more for us to do. */
- gtk_exit(0);
- }
- if (!start_capture && (cfile.cfilter == NULL || strlen(cfile.cfilter) == 0)) {
- if (cfile.cfilter) {
- g_free(cfile.cfilter);
+ /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
+ if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
+ if (capture_opts->cfilter) {
+ g_free(capture_opts->cfilter);
+ }
+ capture_opts->cfilter = g_strdup(get_conn_cfilter());
}
- cfile.cfilter = g_strdup(get_conn_cfilter());
- }
#else /* HAVE_LIBPCAP */
- set_menus_for_capture_in_progress(FALSE);
+ show_main_window(FALSE);
+ set_menus_for_capture_in_progress(FALSE);
#endif /* HAVE_LIBPCAP */
+ }
gtk_main();
gtk_widget_ref(main_pane_v2);
gtk_widget_ref(main_pane_h1);
gtk_widget_ref(main_pane_h2);
+ gtk_widget_ref(welcome_pane);
/* empty all containers participating */
gtk_container_foreach(GTK_CONTAINER(main_vbox), foreach_remove_a_child, main_vbox);
gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
+ /* welcome pane */
+ gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
+
/* statusbar hbox */
gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
}
}
+
+#if 0
+/* XXX - There seems to be some disagreement about if and how this feature should be implemented.
+ As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
+GtkWidget *
+welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
+{
+ GtkWidget *w, *item_hb;
+#if GTK_MAJOR_VERSION >= 2
+ gchar *formatted_message;
+#endif
+
+
+ item_hb = gtk_hbox_new(FALSE, 1);
+
+ w = BUTTON_NEW_FROM_STOCK(stock_item);
+ WIDGET_SET_SIZE(w, 60, 60);
+#if GTK_MAJOR_VERSION >= 2
+ gtk_button_set_label(GTK_BUTTON(w), label);
+#endif
+ gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
+ SIGNAL_CONNECT(w, "clicked", callback, callback_data);
+
+ w = gtk_label_new(message);
+ gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
+#if GTK_MAJOR_VERSION >= 2
+ formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
+ gtk_label_set_markup(GTK_LABEL(w), formatted_message);
+ g_free(formatted_message);
+#endif
+
+ gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
+
+ return item_hb;
+}
+
+
+/* XXX - the layout has to be improved */
+GtkWidget *
+welcome_new(void)
+{
+ GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
+ GtkWidget *w, *icon;
+ gchar * message;
+
+
+ welcome_scrollw = scrolled_window_new(NULL, NULL);
+
+ welcome_hb = gtk_hbox_new(FALSE, 1);
+ /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
+
+ welcome_vb = gtk_vbox_new(FALSE, 1);
+
+ item_hb = gtk_hbox_new(FALSE, 1);
+
+ icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
+ gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
+
+#if GTK_MAJOR_VERSION < 2
+ message = "Welcome to Ethereal!";
+#else
+ message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
+#endif
+ w = gtk_label_new(message);
+#if GTK_MAJOR_VERSION >= 2
+ gtk_label_set_markup(GTK_LABEL(w), message);
+#endif
+ gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
+
+ gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+
+ w = gtk_label_new("What would you like to do?");
+ gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
+ gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
+
+#ifdef HAVE_LIBPCAP
+ item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START,
+ "Capture",
+ "Capture live data from your network",
+ GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
+ gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+#endif
+
+ item_hb = welcome_item(GTK_STOCK_OPEN,
+ "Open",
+ "Open a previously captured file",
+ GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
+ gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+
+#if (GLIB_MAJOR_VERSION >= 2)
+ item_hb = welcome_item(GTK_STOCK_HOME,
+ "Home",
+ "Visit the Ethereal homepage",
+ GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
+ gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+#endif
+
+ /* the end */
+ w = gtk_label_new("");
+ gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
+
+ w = gtk_label_new("");
+ gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
+
+ gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
+
+ w = gtk_label_new("");
+ gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
+
+ gtk_widget_show_all(welcome_hb);
+
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
+ welcome_hb);
+ gtk_widget_show_all(welcome_scrollw);
+
+ return welcome_scrollw;
+}
+#endif /* 0 */
+
+GtkWidget *
+welcome_new(void)
+{
+ /* this is just a dummy to fill up window space, simply showing nothing */
+ return scrolled_window_new(NULL, NULL);
+}
+
+
+
/*
* XXX - this doesn't appear to work with the paned widgets in
* GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
gtk_widget_hide(byte_nb_ptr);
}
+ if (have_capture_file) {
+ gtk_widget_show(main_first_pane);
+ } else {
+ gtk_widget_hide(main_first_pane);
+ }
+
/*
* Is anything in "main_second_pane" visible?
* If so, show it, otherwise hide it.
} else {
gtk_widget_hide(main_second_pane);
}
+
+ if (!have_capture_file) {
+ if(welcome_pane) {
+ gtk_widget_show(welcome_pane);
+ }
+ } else {
+ gtk_widget_hide(welcome_pane);
+ }
}
/* Pane for the statusbar */
status_pane = gtk_hpaned_new();
gtk_widget_show(status_pane);
+
+ /* Pane for the welcome screen */
+ welcome_pane = welcome_new();
+ gtk_widget_show(welcome_pane);
}
+static void
+show_main_window(gboolean doing_work)
+{
+ main_set_for_capture_file(doing_work);
+
+ /*** we have finished all init things, show the main window ***/
+ gtk_widget_show(top_level);
+
+ /* the window can be maximized only, if it's visible, so do it after show! */
+ main_load_window_geometry(top_level);
+
+ /* process all pending GUI events before continue */
+ while (gtk_events_pending()) gtk_main_iteration();
+
+ /* Pop up any queued-up alert boxes. */
+ display_queued_messages();
+}