/* file_dlg.c
* Dialog boxes for handling files
*
- * $Id: file_dlg.c,v 1.111 2004/06/17 22:42:40 guy Exp $
+ * $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include <gtk/gtk.h>
-#include "range.h"
+#include "packet-range.h"
#include <epan/filesystem.h>
#include "globals.h"
#include "gtkglobals.h"
-#include <epan/resolv.h>
+#include <epan/addr_resolv.h>
#include "keys.h"
-#include "filter_prefs.h"
+#include "filter_dlg.h"
#include "ui_util.h"
#include "alert_box.h"
#include "simple_dialog.h"
#include "file_dlg.h"
#include "main.h"
#include "compat_macros.h"
-#include "prefs.h"
+#include <epan/prefs.h>
#include "recent.h"
#include "color.h"
#include "../ui_util.h"
-#include "gtk/color_filters.h"
+#include "color_filters.h"
#include "gtk/color_dlg.h"
#ifdef HAVE_LIBPCAP
#include "capture_dlg.h"
+#endif
#include "range_utils.h"
+#include "merge.h"
+#include "util.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
+#ifdef HAVE_IO_H
+#include <io.h> /* open/close on win32 */
+#endif
static void file_open_ok_cb(GtkWidget *w, gpointer fs);
static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
static void file_color_export_ok_cb(GtkWidget *w, gpointer fs);
static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
+static void set_file_type_list(GtkWidget *option_menu);
#define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
#define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
#define ARGUMENT_CL "argument_cl"
+
+#define PREVIEW_TABLE_KEY "preview_table_key"
+#define PREVIEW_FILENAME_KEY "preview_filename_key"
+#define PREVIEW_FORMAT_KEY "preview_format_key"
+#define PREVIEW_SIZE_KEY "preview_size_key"
+#define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
+#define PREVIEW_PACKETS_KEY "preview_packets_key"
+#define PREVIEW_FIRST_KEY "preview_first_key"
+
+
/*
* Keep a static pointer to the current "Save Capture File As" window, if
* any, so that if somebody tries to do "File:Save" or "File:Save As"
*/
static GtkWidget *file_save_as_w;
+/* XXX - can we make these not be static? */
+static packet_range_t range;
+static gboolean color_marked;
+static int filetype;
+static GtkWidget *cfmark_cb;
+static GtkWidget *ft_om;
+static GtkWidget *range_tb;
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#define PREVIEW_STR_MAX 200
+
+static double
+secs_usecs( guint32 s, guint32 us)
+{
+ return (us / 1000000.0) + (double)s;
+}
+
+
+/* set a new filename for the preview widget */
+static wtap *
+preview_set_filename(GtkWidget *prev, const gchar *cf_name)
+{
+ GtkWidget *label;
+ wtap *wth;
+ int err = 0;
+ gchar *err_info;
+ struct stat cf_stat;
+ gchar string_buff[PREVIEW_STR_MAX];
+ guint64 filesize;
+
+
+ /* init preview labels */
+ label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "-");
+ label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "-");
+ label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "-");
+ label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "-");
+ label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "-");
+ label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "-");
+
+ if(!cf_name) {
+ return NULL;
+ }
+
+ label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
+ gtk_label_set_text(GTK_LABEL(label), get_basename(cf_name));
+
+ if (test_for_directory(cf_name) == EISDIR) {
+ label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
+ gtk_label_set_text(GTK_LABEL(label), "directory");
+ return NULL;
+ }
+
+ wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
+ if (wth == NULL) {
+ label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
+ if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
+ gtk_label_set_text(GTK_LABEL(label), "unknown file format");
+ } else {
+ gtk_label_set_text(GTK_LABEL(label), "error opening file");
+ }
+ return NULL;
+ }
+
+ /* Find the size of the file. */
+ if (fstat(wtap_fd(wth), &cf_stat) < 0) {
+ wtap_close(wth);
+ return NULL;
+ }
+
+ /* size */
+ filesize = cf_stat.st_size;
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "%" PRIu64 " bytes", filesize);
+ label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
+ gtk_label_set_text(GTK_LABEL(label), string_buff);
+
+ /* type */
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "%s", wtap_file_type_string(wtap_file_type(wth)));
+ label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
+ gtk_label_set_text(GTK_LABEL(label), string_buff);
+
+ return wth;
+}
+
+
+/* do a preview run on the currently selected capture file */
+static void
+preview_do(GtkWidget *prev, wtap *wth)
+{
+ GtkWidget *label;
+ unsigned int elapsed_time;
+ time_t time_preview;
+ time_t time_current;
+ int err = 0;
+ gchar *err_info;
+ long data_offset;
+ const struct wtap_pkthdr *phdr;
+ double start_time = 0; /* seconds, with msec resolution */
+ double stop_time = 0; /* seconds, with msec resolution */
+ double cur_time;
+ unsigned int packets = 0;
+ gboolean is_breaked = FALSE;
+ gchar string_buff[PREVIEW_STR_MAX];
+ time_t ti_time;
+ struct tm *ti_tm;
+
+
+ time(&time_preview);
+ while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
+ phdr = wtap_phdr(wth);
+ cur_time = secs_usecs(phdr->ts.tv_sec, phdr->ts.tv_usec);
+ if(packets == 0) {
+ start_time = cur_time;
+ stop_time = cur_time;
+ }
+ if (cur_time < start_time) {
+ start_time = cur_time;
+ }
+ if (cur_time > stop_time){
+ stop_time = cur_time;
+ }
+
+ packets++;
+ if(packets%1000) {
+ /* do we have a timeout? */
+ time(&time_current);
+ if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
+ is_breaked = TRUE;
+ break;
+ }
+ }
+ }
+
+ if(err != 0) {
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
+ label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
+ gtk_label_set_text(GTK_LABEL(label), string_buff);
+ wtap_close(wth);
+ return;
+ }
+
+ /* packet count */
+ if(is_breaked) {
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
+ } else {
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
+ }
+ label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
+ gtk_label_set_text(GTK_LABEL(label), string_buff);
+
+ /* first packet */
+ ti_time = (long)start_time;
+ ti_tm = localtime( &ti_time );
+ g_snprintf(string_buff, PREVIEW_STR_MAX,
+ "%04d-%02d-%02d %02d:%02d:%02d",
+ ti_tm->tm_year + 1900,
+ ti_tm->tm_mon + 1,
+ ti_tm->tm_mday,
+ ti_tm->tm_hour,
+ ti_tm->tm_min,
+ ti_tm->tm_sec);
+ label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
+ gtk_label_set_text(GTK_LABEL(label), string_buff);
+
+ /* elapsed time */
+ elapsed_time = (unsigned int)(stop_time-start_time);
+ if(elapsed_time/86400) {
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
+ elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
+ } else {
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
+ elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
+ }
+ if(is_breaked) {
+ g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
+ }
+ label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
+ gtk_label_set_text(GTK_LABEL(label), string_buff);
+
+ wtap_close(wth);
+}
+
+#if 0
+/* as the dialog layout will look very ugly when using the file chooser preview mechanism,
+ simply use the same layout as in GTK1 */
+/* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
+static void
+update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
+{
+ GtkWidget *prev = GTK_WIDGET (data);
+ char *cf_name;
+ gboolean have_preview;
+
+ cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
+
+ have_preview = preview_set_filename(prev, cf_name);
+
+ g_free (cf_name);
+
+ have_preview = TRUE;
+ gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
+}
+#endif
+
+
+/* the filename text entry changed */
+static void
+file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
+{
+ GtkWidget *prev = OBJECT_GET_DATA(file_sel, PREVIEW_TABLE_KEY);
+ const gchar* cf_name;
+ gboolean have_preview;
+ wtap *wth;
+
+ /* get the filename */
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
+#else
+ cf_name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_sel));
+#endif
+
+ /* set the filename to the preview */
+ wth = preview_set_filename(prev, cf_name);
+ have_preview = (wth != NULL);
+
+ /* make the preview widget sensitive */
+ gtk_widget_set_sensitive(prev, have_preview);
+
+ /* make the open/save/... dialog button sensitive */
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
+#else
+ gtk_widget_set_sensitive(GTK_FILE_SELECTION(file_sel)->ok_button, have_preview);
+#endif
+
+ /* do the actual preview */
+ if(have_preview)
+ preview_do(prev, wth);
+}
+
+
+/* copied from summary_dlg.c */
+static GtkWidget *
+add_string_to_table_sensitive(GtkWidget *list, guint *row, gchar *title, gchar *value, gboolean sensitive)
+{
+ GtkWidget *label;
+ gchar *indent;
+
+ if(strlen(value) != 0) {
+ indent = g_strdup_printf(" %s", title);
+ } else {
+ indent = g_strdup(title);
+ }
+ label = gtk_label_new(indent);
+ g_free(indent);
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+ gtk_widget_set_sensitive(label, sensitive);
+ gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
+
+ label = gtk_label_new(value);
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+ gtk_widget_set_sensitive(label, sensitive);
+ gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
+
+ *row = *row + 1;
+
+ return label;
+}
+
+static GtkWidget *
+add_string_to_table(GtkWidget *list, guint *row, gchar *title, gchar *value)
+{
+ return add_string_to_table_sensitive(list, row, title, value, TRUE);
+}
+
+static GtkWidget *
+preview_new(void)
+{
+ GtkWidget *table, *label;
+ guint row;
+
+ table = gtk_table_new(1, 2, FALSE);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 3);
+ row = 0;
+
+ label = add_string_to_table(table, &row, "Filename:", "-");
+ WIDGET_SET_SIZE(label, DEF_WIDTH/3, -1);
+ OBJECT_SET_DATA(table, PREVIEW_FILENAME_KEY, label);
+ label = add_string_to_table(table, &row, "Format:", "-");
+ OBJECT_SET_DATA(table, PREVIEW_FORMAT_KEY, label);
+ label = add_string_to_table(table, &row, "Size:", "-");
+ OBJECT_SET_DATA(table, PREVIEW_SIZE_KEY, label);
+ label = add_string_to_table(table, &row, "Packets:", "-");
+ OBJECT_SET_DATA(table, PREVIEW_PACKETS_KEY, label);
+ label = add_string_to_table(table, &row, "First Packet:", "-");
+ OBJECT_SET_DATA(table, PREVIEW_FIRST_KEY, label);
+ label = add_string_to_table(table, &row, "Elapsed time:", "-");
+ OBJECT_SET_DATA(table, PREVIEW_ELAPSED_KEY, label);
+
+ return table;
+}
+
/*
* Keep a static pointer to the current "Open Capture File" window, if
* any, so that if somebody tries to do "File:Open" while there's already
void
file_open_cmd(GtkWidget *w)
{
- GtkWidget *main_vb, *filter_hbox, *filter_bt, *filter_te,
- *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
+ GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
+ *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
#if GTK_MAJOR_VERSION < 2
GtkAccelGroup *accel_group;
#endif
file_open_w = file_selection_new("Ethereal: Open Capture File",
FILE_SELECTION_OPEN);
- /* window is already shown here, gtk_window_set_default_size() will not work */
- WIDGET_SET_SIZE(file_open_w, DEF_WIDTH, DEF_HEIGHT);
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ /* it's annoying, that the file chooser dialog is already shown here,
+ so we cannot use the correct gtk_window_set_default_size() to resize it */
+ WIDGET_SET_SIZE(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
+#else
+ gtk_window_set_default_size(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
+#endif
#if GTK_MAJOR_VERSION < 2
/* Accelerator group for the accelerators (or, as they're called in
file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
break;
}
-
+
+
+ main_hb = gtk_hbox_new(FALSE, 3);
+ file_selection_set_extra_widget(file_open_w, main_hb);
+ gtk_widget_show(main_hb);
+
/* Container for each row of widgets */
main_vb = gtk_vbox_new(FALSE, 3);
gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- file_selection_set_extra_widget(file_open_w, main_vb);
+ gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
gtk_widget_show(main_vb);
+ /* filter row */
filter_hbox = gtk_hbox_new(FALSE, 1);
gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
E_RFILTER_TE_KEY, filter_te);
#endif
+ /* resolve buttons */
m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
g_resolv_flags & RESOLV_MAC);
SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
+ /* preview widget */
+ prev = preview_new();
+ OBJECT_SET_DATA(file_open_w, PREVIEW_TABLE_KEY, prev);
+ gtk_widget_show_all(prev);
+ gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
+
#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
+ file_open_entry_changed, file_open_w);
+ file_open_entry_changed(file_open_w, file_open_w);
+
OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
}
else window_destroy(file_open_w);
#else
+ SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->selection_entry, "changed",
+ file_open_entry_changed, file_open_w);
+
/* Connect the ok_button to file_open_ok_cb function and pass along a
pointer to the file selection box widget */
SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
{
switch(btn) {
- case(ESD_BTN_YES):
+ case(ESD_BTN_SAVE):
/* save file first */
file_save_as_cmd(after_save_open_dialog, data);
break;
- case(ESD_BTN_NO):
+ case(ESD_BTN_DONT_SAVE):
cf_close(&cfile);
file_open_cmd(data);
break;
file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
gpointer dialog;
- if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
+ if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
/* user didn't saved his current file, ask him */
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
"If you open a new capture file without saving, your capture data will be discarded.");
simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
}
}
+/* user pressed "open" button */
static void
file_open_ok_cb(GtkWidget *w, gpointer fs) {
- gchar *cf_name, *rfilter, *s;
- GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
- dfilter_t *rfcode = NULL;
- int err;
+ gchar *cf_name, *s;
+ const gchar *rfilter;
+ GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
+ dfilter_t *rfcode = NULL;
+ int err;
#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
#endif
filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
- rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
+ rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
if (!dfilter_compile(rfilter, &rfcode)) {
bad_dfilter_alert_box(rfilter);
g_free(cf_name);
}
/* Try to open the capture file. */
- if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
+ if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
/* We couldn't open it; don't dismiss the open dialog box,
just leave it around so that the user can, after they
dismiss the alert box popped up for the open error,
cfile.rfcode = rfcode;
/* Set the global resolving variable */
- g_resolv_flags = prefs.name_resolve & RESOLV_CONCURRENT;
+ g_resolv_flags = prefs.name_resolve;
m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
- g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)) ? RESOLV_MAC : RESOLV_NONE;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
+ g_resolv_flags |= RESOLV_MAC;
+ else
+ g_resolv_flags &= ~RESOLV_MAC;
n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
- g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)) ? RESOLV_NETWORK : RESOLV_NONE;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
+ g_resolv_flags |= RESOLV_NETWORK;
+ else
+ g_resolv_flags &= ~RESOLV_NETWORK;
t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
- g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)) ? RESOLV_TRANSPORT : RESOLV_NONE;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
+ g_resolv_flags |= RESOLV_TRANSPORT;
+ else
+ g_resolv_flags &= ~RESOLV_TRANSPORT;
/* We've crossed the Rubicon; get rid of the file selection box. */
window_destroy(GTK_WIDGET (fs));
switch (cf_read(&cfile)) {
- case READ_SUCCESS:
- case READ_ERROR:
+ 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 READ_ABORTED:
+ case CF_READ_ABORTED:
/* The user bailed out of re-reading the capture file; the
capture file has been closed - just free the capture file name
string and return (without changing the last containing
}
/*
- * Keep a static pointer to the current "Marge Capture File" window, if
+ * Keep a static pointer to the current "Merge Capture File" window, if
* any, so that if somebody tries to do "File:Merge" while there's already
* an "Merge Capture File" window up, we just pop up the existing one,
* rather than creating a new one.
void
file_merge_cmd(GtkWidget *w)
{
- GtkWidget *main_vb, *filter_hbox, *filter_bt, *filter_te,
- *prepend_rb, *chrono_rb, *append_rb;
+ GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *filter_hbox,
+ *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
+ *append_rb, *prev;
#if GTK_MAJOR_VERSION < 2
GtkAccelGroup *accel_group;
#endif
+ GtkTooltips *tooltips = gtk_tooltips_new();
/* No Apply button, and "OK" just sets our text widget, it doesn't
activate it (i.e., it doesn't cause us to try to open the file). */
static construct_args_t args = {
return;
}
+ /* Default to saving all packets, in the file's current format. */
+ filetype = cfile.cd_t;
+
file_merge_w = file_selection_new("Ethereal: Merge with Capture File",
FILE_SELECTION_OPEN);
- /* window is already shown here, gtk_window_set_default_size() will not work */
- WIDGET_SET_SIZE(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ /* it's annoying, that the file chooser dialog is already shown here,
+ so we cannot use the correct gtk_window_set_default_size() to resize it */
+ WIDGET_SET_SIZE(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
+#else
+ gtk_window_set_default_size(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
+#endif
#if GTK_MAJOR_VERSION < 2
/* Accelerator group for the accelerators (or, as they're called in
break;
}
+ main_hb = gtk_hbox_new(FALSE, 3);
+ file_selection_set_extra_widget(file_merge_w, main_hb);
+ gtk_widget_show(main_hb);
+
/* Container for each row of widgets */
main_vb = gtk_vbox_new(FALSE, 3);
gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- file_selection_set_extra_widget(file_merge_w, main_vb);
+ gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
gtk_widget_show(main_vb);
+ /* File type row */
+ range_tb = NULL;
+ ft_hb = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
+ gtk_widget_show(ft_hb);
+
+ ft_lb = gtk_label_new("Merged output file type:");
+ gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
+ gtk_widget_show(ft_lb);
+
+ ft_om = gtk_option_menu_new();
+
+ /* Generate the list of file types we can save. */
+ set_file_type_list(ft_om);
+ gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
+ gtk_widget_show(ft_om);
+
filter_hbox = gtk_hbox_new(FALSE, 1);
gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
#endif
prepend_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Prepend packets to existing file", accel_group);
+ gtk_tooltips_set_tip(tooltips, prepend_rb,
+ "The resulting file contains the packets from the selected, followed by the packets from the currently loaded file,"
+ " the packet timestamps will be ignored.", NULL);
gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
OBJECT_SET_DATA(file_merge_w,
#endif
gtk_widget_show(prepend_rb);
- chrono_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Sort packets chronologically", accel_group);
+ chrono_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Merge packets chronologically", accel_group);
+ gtk_tooltips_set_tip(tooltips, chrono_rb,
+ "The resulting file contains all the packets from the currently loaded and the selected file,"
+ " sorted by the packet timestamps.", NULL);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
gtk_widget_show(chrono_rb);
#endif
append_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Append packets to existing file", accel_group);
+ gtk_tooltips_set_tip(tooltips, append_rb,
+ "The resulting file contains the packets from the currently loaded, followed by the packets from the selected file,"
+ " the packet timestamps will be ignored.", NULL);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(append_rb),
g_resolv_flags & RESOLV_TRANSPORT);
gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
SIGNAL_CONNECT(file_merge_w, "destroy", file_merge_destroy_cb, NULL);
+ /* preview widget */
+ prev = preview_new();
+ OBJECT_SET_DATA(file_merge_w, PREVIEW_TABLE_KEY, prev);
+ gtk_widget_show_all(prev);
+ gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
+
#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
+ file_open_entry_changed, file_merge_w);
+ file_open_entry_changed(file_merge_w, file_merge_w);
+
OBJECT_SET_DATA(file_merge_w, E_DFILTER_TE_KEY,
OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
}
else window_destroy(file_merge_w);
#else
+ SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->selection_entry, "changed",
+ file_open_entry_changed, file_merge_w);
+
/* Connect the ok_button to file_merge_ok_cb function and pass along a
pointer to the file selection box widget */
SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->ok_button, "clicked",
static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
{
switch(btn) {
- case(ESD_BTN_YES):
+ case(ESD_BTN_OK):
/* save file first */
file_save_as_cmd(after_save_merge_dialog, data);
break;
- case(ESD_BTN_NO):
+ case(ESD_BTN_CANCEL):
break;
default:
g_assert_not_reached();
file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
gpointer dialog;
- if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
+ if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
/* user didn't saved his current file, ask him */
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO,
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
PRIMARY_TEXT_START "Save the capture file before merging to another one?" PRIMARY_TEXT_END "\n\n"
- "A temporary capture file cannot be merged.");
+ "A temporary capture file can't be merged.");
simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
} else {
/* unchanged file, just start to merge */
}
-extern gboolean
-merge_two_files(char *out_filename, char *in_file0, char *in_file1, gboolean append);
-
static void
file_merge_ok_cb(GtkWidget *w, gpointer fs) {
- gchar *cf_name, *rfilter, *s;
- gchar *cf_current_name, *cf_merged_name;
- GtkWidget *filter_te, *rb;
- dfilter_t *rfcode = NULL;
- int err;
- gboolean merge_ok;
+ gchar *cf_name, *s;
+ const gchar *rfilter;
+ GtkWidget *filter_te, *rb;
+ dfilter_t *rfcode = NULL;
+ int err;
+ cf_status_t merge_status;
+ char *in_filenames[2];
+ int out_fd;
+ char tmpname[128+1];
#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
#endif
filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
- rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
+ rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
if (!dfilter_compile(rfilter, &rfcode)) {
bad_dfilter_alert_box(rfilter);
g_free(cf_name);
return;
}
- cf_current_name = strdup(cfile.filename);
- /*XXX should use temp file stuff in util routines */
- cf_merged_name = tmpnam(NULL);
+ out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
- /* merge or append the files */
+ /* merge or append the two files */
rb = OBJECT_GET_DATA(w, E_MERGE_CHRONO_KEY);
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
- /* chonological order */
- merge_ok = merge_two_files(cf_merged_name, cf_current_name, cf_name, FALSE);
+ /* chronological order */
+ in_filenames[0] = cfile.filename;
+ in_filenames[1] = cf_name;
+ merge_status = cf_merge_files(tmpname, out_fd, 2, in_filenames,
+ filetype, FALSE);
} else {
rb = OBJECT_GET_DATA(w, E_MERGE_PREPEND_KEY);
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
/* prepend file */
- merge_ok = merge_two_files(cf_merged_name, cf_current_name, cf_name, TRUE);
+ in_filenames[0] = cfile.filename;
+ in_filenames[1] = cf_name;
+ merge_status = cf_merge_files(tmpname, out_fd, 2, in_filenames,
+ filetype, TRUE);
} else {
/* append file */
- merge_ok = merge_two_files(cf_merged_name, cf_name, cf_current_name, TRUE);
+ in_filenames[0] = cf_name;
+ in_filenames[1] = cfile.filename;
+ merge_status = cf_merge_files(tmpname, out_fd, 2, in_filenames,
+ filetype, TRUE);
}
}
- cf_close(&cfile);
- g_free(cf_current_name);
- cf_name = cf_merged_name;
+ g_free(cf_name);
- if(!merge_ok) {
+ if (merge_status != CF_OK) {
+ close(out_fd); /* XXX - it's already closed, right? */
if (rfcode != NULL)
dfilter_free(rfcode);
- g_free(cf_name);
return;
}
- /* Try to open the capture file. */
- if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
+ cf_close(&cfile);
+
+ /* We've crossed the Rubicon; get rid of the file selection box. */
+ window_destroy(GTK_WIDGET (fs));
+
+ /* Try to open the merged capture file. */
+ if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
/* We couldn't open it; don't dismiss the open dialog box,
just leave it around so that the user can, after they
dismiss the alert box popped up for the open error,
try again. */
if (rfcode != NULL)
dfilter_free(rfcode);
- g_free(cf_name);
return;
}
it closed the previous capture file, and thus destroyed any
previous read filter attached to "cf"). */
cfile.rfcode = rfcode;
- cfile.is_tempfile = TRUE;
-
- /* We've crossed the Rubicon; get rid of the file selection box. */
- window_destroy(GTK_WIDGET (fs));
switch (cf_read(&cfile)) {
- case READ_SUCCESS:
- case READ_ERROR:
+ 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 READ_ABORTED:
+ case CF_READ_ABORTED:
/* The user bailed out of re-reading the capture file; the
capture file has been closed - just free the capture file name
string and return (without changing the last containing
directory). */
- g_free(cf_name);
return;
}
/* 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
+ if any; we can write over cf_merged_name, which is a good thing, given that
"get_dirname()" does write over its argument. */
- s = get_dirname(cf_name);
+ s = get_dirname(tmpname);
set_last_open_dir(s);
gtk_widget_grab_focus(packet_list);
-
- g_free(cf_name);
}
static void
void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
{
switch(btn) {
- case(ESD_BTN_YES):
+ case(ESD_BTN_SAVE):
/* save file first */
file_save_as_cmd(after_save_close_file, NULL);
break;
- case(ESD_BTN_NO):
+ case(ESD_BTN_DONT_SAVE):
cf_close(&cfile);
break;
case(ESD_BTN_CANCEL):
file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
gpointer dialog;
- if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
+ if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
/* user didn't saved his current file, ask him */
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
"If you close without saving, your capture data will be discarded.");
file_save_as_cmd_cb(w, data);
}
-/* XXX - can we make these not be static? */
-static packet_range_t range;
-static gboolean color_marked;
-static int filetype;
-static GtkWidget *cfmark_cb;
-static GtkWidget *ft_om;
-static GtkWidget *range_tb;
-
static gboolean
can_save_with_wiretap(int ft)
{
if (filetype != new_filetype) {
/* We can select only the filtered or marked packets to be saved if we can
use Wiretap to save the file. */
- range_set_displayed_sensitive(range_tb, can_save_with_wiretap(new_filetype));
+ if (range_tb != NULL)
+ range_set_displayed_sensitive(range_tb, can_save_with_wiretap(new_filetype));
filetype = new_filetype;
file_set_save_marked_sensitive();
}
/* We can request that only the marked packets be saved only if we
can use Wiretap to save the file and if there *are* marked packets. */
- if (can_save_with_wiretap(filetype) && cfile.marked_count != 0) {
+ if (can_save_with_wiretap(filetype) && cfile.marked_count > 0) {
range_set_marked_sensitive(range_tb, TRUE);
}
else {
return;
}
+ /* Check whether the range is valid. */
+ if (!range_check_validity(&range)) {
+ /* The range isn't valid; don't dismiss the open dialog box,
+ just leave it around so that the user can, after they
+ dismiss the alert box popped up for the error, try again. */
+ g_free(cf_name);
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
+ * as this will prevent the user from closing the now existing error
+ * message, simply close the dialog (this is the best we can do here). */
+ if (file_save_as_w)
+ window_destroy(GTK_WIDGET (fs));
+#else
+ gtk_widget_show(GTK_WIDGET (fs));
+#endif
+ return;
+ }
+
/* don't show the dialog while saving */
gtk_widget_hide(GTK_WIDGET (fs));
/* Write out the packets (all, or only the ones from the current
range) to the file with the specified name. */
- if (! cf_save(cf_name, &cfile, &range, filetype)) {
+ if (cf_save(&cfile, cf_name, &range, filetype) != CF_OK) {
/* The write failed; don't dismiss the open dialog box,
just leave it around so that the user can, after they
dismiss the alert box popped up for the error, try again. */
g_free(cf_name);
+#if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
+ /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
+ * as this will prevent the user from closing the now existing error
+ * message, simply close the dialog (this is the best we can do here). */
+ if (file_save_as_w)
+ window_destroy(GTK_WIDGET (fs));
+#else
gtk_widget_show(GTK_WIDGET (fs));
+#endif
return;
}
/* The write succeeded; get rid of the file selection box. */
- /* cf_save might already closed our dialog! */
+ /* cf_save() might already closed our dialog! */
if (file_save_as_w)
window_destroy(GTK_WIDGET (fs));
/* Reload a file using the current read and display filters */
void
file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
- gchar *filename;
- gboolean is_tempfile;
-
- /* If the file could be opened, "cf_open()" calls "cf_close()"
- to get rid of state for the old capture file before filling in state
- for the new capture file. "cf_close()" will remove the file if
- it's a temporary file; we don't want that to happen (for one thing,
- it'd prevent subsequent reopens from working). Remember whether it's
- a temporary file, mark it as not being a temporary file, and then
- reopen it as the type of file it was.
-
- Also, "cf_close()" will free "cfile.filename", so we must make
- a copy of it first. */
- filename = g_strdup(cfile.filename);
- is_tempfile = cfile.is_tempfile;
- cfile.is_tempfile = FALSE;
- if (cf_open(filename, is_tempfile, &cfile) == 0) {
- switch (cf_read(&cfile)) {
-
- case READ_SUCCESS:
- case 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 READ_ABORTED:
- /* The user bailed out of re-reading the capture file; the
- capture file has been closed - just free the capture file name
- string and return (without changing the last containing
- directory). */
- g_free(filename);
- return;
- }
- } else {
- /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
- Instead, the file was left open, so we should restore "cfile.is_tempfile"
- ourselves.
-
- XXX - change the menu? Presumably "cf_open()" will do that;
- make sure it does! */
- cfile.is_tempfile = is_tempfile;
- }
- /* "cf_open()" made a copy of the file name we handed it, so
- we should free up our copy. */
- g_free(filename);
+ cf_reload(&cfile);
}
/******************** Color Filters *********************************/