/* capture_file_dlg.c * Dialog boxes for handling capture files * * $Id$ * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #include "packet-range.h" #include #include #include #include "../globals.h" #include "../alert_box.h" #include "../simple_dialog.h" #include "../color.h" #include "../ui_util.h" #include "../color_filters.h" #include "../merge.h" #include "../util.h" #include #include "gtk/gtkglobals.h" #include "gtk/keys.h" #include "gtk/filter_dlg.h" #include "gtk/gui_utils.h" #include "gtk/dlg_utils.h" #include "gtk/file_dlg.h" #include "gtk/capture_file_dlg.h" #include "gtk/drag_and_drop.h" #include "gtk/main.h" #include "gtk/main_menu.h" #include "gtk/recent.h" #include "gtk/color_dlg.h" #ifdef HAVE_LIBPCAP #include "gtk/capture_dlg.h" #endif #include "gtk/stock_icons.h" #include "gtk/range_utils.h" #include "gtk/filter_autocomplete.h" #if _WIN32 #include #include #include "gtk/file_dlg_win32.h" #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_merge_ok_cb(GtkWidget *w, gpointer fs); static void file_merge_destroy_cb(GtkWidget *win, gpointer user_data); static void select_file_type_cb(GtkWidget *w, gpointer data); static void file_save_as_ok_cb(GtkWidget *w, gpointer fs); static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data); static void file_color_import_ok_cb(GtkWidget *w, gpointer filter_list); static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data); static void file_color_export_ok_cb(GtkWidget *w, gpointer filter_list); 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 E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key" #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key" #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key" #define E_MERGE_APPEND_KEY "merge_dlg_append_key" #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" * while there's already a "Save Capture File As" window up, we just pop * up the existing one, rather than creating a new one. */ static GtkWidget *file_save_as_w; /* XXX - can we make these not be static? */ static packet_range_t range; static gboolean color_selected; static int filetype; static GtkWidget *cfselect_cb; static GtkWidget *ft_om; static GtkWidget *range_tb; #define PREVIEW_STR_MAX 200 /* 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; gchar string_buff[PREVIEW_STR_MAX]; gint64 filesize; /* init preview labels */ label = g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY); gtk_label_set_text(GTK_LABEL(label), "-"); label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY); gtk_label_set_text(GTK_LABEL(label), "-"); label = g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY); gtk_label_set_text(GTK_LABEL(label), "-"); label = g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY); gtk_label_set_text(GTK_LABEL(label), "-"); label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY); gtk_label_set_text(GTK_LABEL(label), "-"); label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY); gtk_label_set_text(GTK_LABEL(label), "-"); if(!cf_name) { return NULL; } label = g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY); gtk_label_set_text(GTK_LABEL(label), get_basename(cf_name)); if (test_for_directory(cf_name) == EISDIR) { label = g_object_get_data(G_OBJECT(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 = g_object_get_data(G_OBJECT(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. */ filesize = wtap_file_size(wth, &err); if (filesize == -1) { gtk_label_set_text(GTK_LABEL(label), "error getting file size"); wtap_close(wth); return NULL; } g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize); label = g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY); gtk_label_set_text(GTK_LABEL(label), string_buff); /* type */ g_strlcpy(string_buff, wtap_file_type_string(wtap_file_type(wth)), PREVIEW_STR_MAX); label = g_object_get_data(G_OBJECT(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; gint64 data_offset; const struct wtap_pkthdr *phdr; double start_time = 0; /* seconds, with nsec resolution */ double stop_time = 0; /* seconds, with nsec 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 = wtap_nstime_to_sec(&phdr->ts); 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 == 0) { /* 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 = g_object_get_data(G_OBJECT(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 = g_object_get_data(G_OBJECT(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 ); if(ti_tm) { 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); } else { g_snprintf(string_buff, PREVIEW_STR_MAX, "?"); } label = g_object_get_data(G_OBJECT(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 = g_object_get_data(G_OBJECT(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 GTK2.0 */ 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 = g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY); const gchar* cf_name; gboolean have_preview; wtap *wth; /* get the filename */ cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel)); /* 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 */ gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview); /* 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, const gchar *title, const 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.0f, 0.5f); 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.0f, 0.5f); 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, const gchar *title, const 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:", "-"); gtk_widget_set_size_request(label, DEF_WIDTH/3, -1); g_object_set_data(G_OBJECT(table), PREVIEW_FILENAME_KEY, label); label = add_string_to_table(table, &row, "Format:", "-"); g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label); label = add_string_to_table(table, &row, "Size:", "-"); g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label); label = add_string_to_table(table, &row, "Packets:", "-"); g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label); label = add_string_to_table(table, &row, "First Packet:", "-"); g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label); label = add_string_to_table(table, &row, "Elapsed time:", "-"); g_object_set_data(G_OBJECT(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 * an "Open Capture File" window up, we just pop up the existing one, * rather than creating a new one. */ static GtkWidget *file_open_w; /* Open a file */ static void file_open_cmd(GtkWidget *w) { #if _WIN32 win32_open_file(GDK_WINDOW_HWND(top_level->window)); #else /* _WIN32 */ GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev; 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 = { "Wireshark: Read Filter", FALSE, FALSE, TRUE }; if (file_open_w != NULL) { /* There's already an "Open Capture File" dialog box; reactivate it. */ reactivate_window(file_open_w); return; } file_open_w = file_selection_new("Wireshark: Open Capture File", FILE_SELECTION_OPEN); /* 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 */ gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT); switch (prefs.gui_fileopen_style) { case FO_STYLE_LAST_OPENED: /* The user has specified that we should start out in the last directory we looked in. If we've already opened a file, use its containing directory, if we could determine it, as the directory, otherwise use the "last opened" directory saved in the preferences file if there was one. */ /* This is now the default behaviour in file_selection_new() */ break; case FO_STYLE_SPECIFIED: /* The user has specified that we should always start out in a specified directory; if they've specified that directory, start out by showing the files in that dir. */ if (prefs.gui_fileopen_dir[0] != '\0') 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_set_border_width(GTK_CONTAINER(main_vb), 5); 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_set_border_width(GTK_CONTAINER(filter_hbox), 0); gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0); gtk_widget_show(filter_hbox); filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY); g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &args); g_signal_connect(filter_bt, "destroy", G_CALLBACK(filter_button_destroy_cb), NULL); gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0); gtk_widget_show(filter_bt); gtk_tooltips_set_tip(tooltips, filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters", NULL); filter_te = gtk_entry_new(); g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te); gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3); g_signal_connect(filter_te, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL); g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL); g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL); g_signal_connect(file_open_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL); colorize_filter_te_as_empty(filter_te); gtk_widget_show(filter_te); gtk_tooltips_set_tip(tooltips, filter_te, "Enter a display filter.", NULL); g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te); /* resolve buttons */ m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb), g_resolv_flags & RESOLV_MAC); gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(file_open_w), E_FILE_M_RESOLVE_KEY, m_resolv_cb); gtk_widget_show(m_resolv_cb); n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb), g_resolv_flags & RESOLV_NETWORK); gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0); gtk_widget_show(n_resolv_cb); g_object_set_data(G_OBJECT(file_open_w), E_FILE_N_RESOLVE_KEY, n_resolv_cb); t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb), g_resolv_flags & RESOLV_TRANSPORT); gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0); gtk_widget_show(t_resolv_cb); g_object_set_data(G_OBJECT(file_open_w), E_FILE_T_RESOLVE_KEY, t_resolv_cb); g_signal_connect(file_open_w, "destroy", G_CALLBACK(file_open_destroy_cb), NULL); /* preview widget */ prev = preview_new(); g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev); gtk_widget_show_all(prev); gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0); g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed", G_CALLBACK(file_open_entry_changed), file_open_w); file_open_entry_changed(file_open_w, file_open_w); g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY, g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY)); if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT) { file_open_ok_cb(file_open_w, file_open_w); } else window_destroy(file_open_w); #endif /* _WIN32 */ } static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data) { switch(btn) { case(ESD_BTN_SAVE): /* save file first */ file_save_as_cmd(after_save_open_dialog, data); break; case(ESD_BTN_DONT_SAVE): cf_close(&cfile); file_open_cmd(data); break; case(ESD_BTN_CANCEL): break; default: g_assert_not_reached(); } } void file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) { gpointer dialog; if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) { /* user didn't save his current file, ask him */ dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL, "%sSave capture file before opening a new one?%s\n\n" "If you open a new capture file without saving, your capture data will be discarded.", simple_dialog_primary_start(), simple_dialog_primary_end()); simple_dialog_set_cb(dialog, file_open_answered_cb, widget); } else { /* unchanged file, just open a new one */ file_open_cmd(widget); } } /* user pressed "open" button */ static void file_open_ok_cb(GtkWidget *w, gpointer fs) { 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; cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs))); filter_te = g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY); rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te)); if (!dfilter_compile(rfilter, &rfcode)) { bad_dfilter_alert_box(rfilter); g_free(cf_name); return; } /* Perhaps the user specified a directory instead of a file. Check whether they did. */ if (test_for_directory(cf_name) == EISDIR) { /* It's a directory - set the file selection box to display that directory, don't try to open the directory as a capture file. */ set_last_open_dir(cf_name); g_free(cf_name); file_selection_set_current_folder(fs, get_last_open_dir()); return; } /* Try to open the capture file. */ 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, try again. */ if (rfcode != NULL) dfilter_free(rfcode); g_free(cf_name); /* 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_open_w) window_destroy(file_open_w); return; } /* Attach the new read filter to "cf" ("cf_open()" succeeded, so it closed the previous capture file, and thus destroyed any previous read filter attached to "cf"). */ cfile.rfcode = rfcode; /* Set the global resolving variable */ g_resolv_flags = prefs.name_resolve; m_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_M_RESOLVE_KEY); 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 = g_object_get_data(G_OBJECT(w), E_FILE_N_RESOLVE_KEY); 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 = g_object_get_data(G_OBJECT(w), E_FILE_T_RESOLVE_KEY); 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 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: /* 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 "get_dirname()" does write over its argument. */ s = get_dirname(cf_name); set_last_open_dir(s); gtk_widget_grab_focus(packet_list); g_free(cf_name); } static void file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) { /* Note that we no longer have a "Open Capture File" dialog box. */ file_open_w = NULL; } /* * 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. */ static GtkWidget *file_merge_w; /* Merge existing with another file */ static void file_merge_cmd(GtkWidget *w) { #if _WIN32 win32_merge_file(GDK_WINDOW_HWND(top_level->window)); packet_list_freeze(); packet_list_thaw(); #else /* _WIN32 */ GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *filter_hbox, *filter_bt, *filter_te, *prepend_rb, *chrono_rb, *append_rb, *prev; 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 = { "Wireshark: Read Filter", FALSE, FALSE, TRUE }; if (file_merge_w != NULL) { /* There's already an "Merge Capture File" dialog box; reactivate it. */ reactivate_window(file_merge_w); return; } /* Default to saving all packets, in the file's current format. */ filetype = cfile.cd_t; file_merge_w = file_selection_new("Wireshark: Merge with Capture File", FILE_SELECTION_OPEN); /* 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 */ gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT); switch (prefs.gui_fileopen_style) { case FO_STYLE_LAST_OPENED: /* The user has specified that we should start out in the last directory we looked in. If we've already opened a file, use its containing directory, if we could determine it, as the directory, otherwise use the "last opened" directory saved in the preferences file if there was one. */ /* This is now the default behaviour in file_selection_new() */ break; case FO_STYLE_SPECIFIED: /* The user has specified that we should always start out in a specified directory; if they've specified that directory, start out by showing the files in that dir. */ if (prefs.gui_fileopen_dir[0] != '\0') file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir); 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_set_border_width(GTK_CONTAINER(main_vb), 5); 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_set_border_width(GTK_CONTAINER(filter_hbox), 0); gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0); gtk_widget_show(filter_hbox); filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY); g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &args); g_signal_connect(filter_bt, "destroy", G_CALLBACK(filter_button_destroy_cb), NULL); gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0); gtk_widget_show(filter_bt); gtk_tooltips_set_tip(tooltips, filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters", NULL); filter_te = gtk_entry_new(); g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te); gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3); g_signal_connect(filter_te, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL); g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL); g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL); g_signal_connect(file_merge_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL); colorize_filter_te_as_empty(filter_te); gtk_widget_show(filter_te); gtk_tooltips_set_tip(tooltips, filter_te, "Enter a display filter.", NULL); g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te); prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "Prepend packets to existing file"); 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); g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_PREPEND_KEY, prepend_rb); gtk_widget_show(prepend_rb); chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically"); 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); g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_CHRONO_KEY, chrono_rb); append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file"); 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_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0); gtk_widget_show(append_rb); g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_APPEND_KEY, append_rb); g_signal_connect(file_merge_w, "destroy", G_CALLBACK(file_merge_destroy_cb), NULL); /* preview widget */ prev = preview_new(); g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev); gtk_widget_show_all(prev); gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0); g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed", G_CALLBACK(file_open_entry_changed), file_merge_w); file_open_entry_changed(file_merge_w, file_merge_w); g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY, g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY)); if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT) { file_merge_ok_cb(file_merge_w, file_merge_w); } else window_destroy(file_merge_w); #endif /* _WIN32 */ } static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_) { switch(btn) { case(ESD_BTN_OK): /* save file first */ file_save_as_cmd(after_save_merge_dialog, data); break; case(ESD_BTN_CANCEL): break; default: g_assert_not_reached(); } } void file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) { gpointer dialog; 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_OK_CANCEL, "%sSave the capture file before merging to another one?%s\n\n" "A temporary capture file can't be merged.", simple_dialog_primary_start(), simple_dialog_primary_end()); simple_dialog_set_cb(dialog, file_merge_answered_cb, widget); } else { /* unchanged file, just start to merge */ file_merge_cmd(widget); } } static void file_merge_ok_cb(GtkWidget *w, gpointer fs) { 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]; char *tmpname; cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs))); filter_te = g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY); rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te)); if (!dfilter_compile(rfilter, &rfcode)) { bad_dfilter_alert_box(rfilter); g_free(cf_name); return; } /* Perhaps the user specified a directory instead of a file. Check whether they did. */ if (test_for_directory(cf_name) == EISDIR) { /* It's a directory - set the file selection box to display that directory, don't try to open the directory as a capture file. */ set_last_open_dir(cf_name); g_free(cf_name); file_selection_set_current_folder(fs, get_last_open_dir()); return; } /* merge or append the two files */ rb = g_object_get_data(G_OBJECT(w), E_MERGE_CHRONO_KEY); tmpname = NULL; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) { /* chronological order */ in_filenames[0] = cfile.filename; in_filenames[1] = cf_name; merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype, FALSE); } else { rb = g_object_get_data(G_OBJECT(w), E_MERGE_PREPEND_KEY); if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) { /* prepend file */ in_filenames[0] = cf_name; in_filenames[1] = cfile.filename; merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype, TRUE); } else { /* append file */ in_filenames[0] = cfile.filename; in_filenames[1] = cf_name; merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype, TRUE); } } g_free(cf_name); if (merge_status != CF_OK) { if (rfcode != NULL) dfilter_free(rfcode); g_free(tmpname); return; } 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(tmpname); /* 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_open_w) window_destroy(file_open_w); return; } g_free(tmpname); /* Attach the new read filter to "cf" ("cf_open()" succeeded, so it closed the previous capture file, and thus destroyed any previous read filter attached to "cf"). */ cfile.rfcode = rfcode; 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_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). */ return; } /* Save the name of the containing directory specified in the path name, 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(tmpname); set_last_open_dir(s); gtk_widget_grab_focus(packet_list); } static void file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) { /* Note that we no longer have a "Merge Capture File" dialog box. */ file_merge_w = NULL; } static void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_) { switch(btn) { case(ESD_BTN_SAVE): /* save file first */ file_save_as_cmd(after_save_close_file, NULL); break; case(ESD_BTN_DONT_SAVE): cf_close(&cfile); break; case(ESD_BTN_CANCEL): break; default: g_assert_not_reached(); } } /* Close a file */ void file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) { gpointer dialog; 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_SAVE_DONTSAVE_CANCEL, "%sSave capture file before closing it?%s\n\n" "If you close without saving, your capture data will be discarded.", simple_dialog_primary_start(), simple_dialog_primary_end()); simple_dialog_set_cb(dialog, file_close_answered_cb, NULL); } else { /* unchanged file, just close it */ cf_close(&cfile); } } void file_save_cmd_cb(GtkWidget *w, gpointer data) { /* If the file's already been saved, do nothing. */ if (cfile.user_saved) return; /* Do a "Save As". */ file_save_as_cmd_cb(w, data); } static gboolean can_save_with_wiretap(int ft) { /* To save a file with Wiretap, Wiretap has to handle that format, and its code to handle that format must be able to write a file with this file's encapsulation type. */ return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t); } /* Generate a list of the file types we can save this file as, by checking what Wiretap supports. */ static void set_file_type_list(GtkWidget *option_menu) { GtkWidget *ft_menu, *ft_menu_item; int ft; guint index; gint item_to_select; /* Default to the first supported file type, if the file's current type isn't supported. */ item_to_select = -1; ft_menu = gtk_menu_new(); /* Check all file types. */ index = 0; for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) { if (can_save_with_wiretap(ft)) { /* OK, we can write it out in this type. */ ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft)); if (ft == filetype) { /* Default to the same format as the file, if it's supported. */ item_to_select = index; } g_signal_connect(ft_menu_item, "activate", G_CALLBACK(select_file_type_cb), GINT_TO_POINTER(ft)); gtk_menu_shell_append(GTK_MENU_SHELL(ft_menu), ft_menu_item); gtk_widget_show(ft_menu_item); index++; } } gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu); if (item_to_select >= 0) { /* Select the current File format in the menu */ gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select); select_file_type_cb(NULL, GINT_TO_POINTER(filetype)); } else { /* * Manually call the signal handler to activate the first menu item * since gtk_option_menu_set_history() doesn't do it for us. The first two * entries in the wiretap file types are placeholders so we start at #2, which * is the normal libpcap format. */ gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), 0); select_file_type_cb(NULL, GINT_TO_POINTER(WTAP_FILE_PCAP)); } } static void select_file_type_cb(GtkWidget *w _U_, gpointer data) { int new_filetype = GPOINTER_TO_INT(data); GtkWidget *compressed_cb; if (filetype != new_filetype) { filetype = new_filetype; compressed_cb = g_object_get_data(G_OBJECT(file_save_as_w), "compressed"); if(compressed_cb) gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(new_filetype)); } } /* * Update various dynamic parts of the range controls; called from outside * the file dialog code whenever the packet counts change. */ void file_save_update_dynamics(void) { if (file_save_as_w == NULL) { /* We don't currently have a "Save As..." dialog box up. */ return; } range_update_dynamics(range_tb); } action_after_save_e action_after_save_g; gpointer action_after_save_data_g; void file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data) { #if _WIN32 win32_save_as_file(GDK_WINDOW_HWND(top_level->window), action_after_save, action_after_save_data); #else /* _WIN32 */ GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr, *compressed_cb; GtkTooltips *tooltips; if (file_save_as_w != NULL) { /* There's already an "Save Capture File As" dialog box; reactivate it. */ reactivate_window(file_save_as_w); return; } /* Default to saving all packets, in the file's current format. */ filetype = cfile.cd_t; /* init the packet range */ packet_range_init(&range); /* Enable tooltips */ tooltips = gtk_tooltips_new(); /* build the file selection */ file_save_as_w = file_selection_new ("Wireshark: Save Capture File As", FILE_SELECTION_SAVE); /* as the dialog might already be gone, when using this values, we cannot * set data to the dialog object, but keep global values */ action_after_save_g = action_after_save; action_after_save_data_g = action_after_save_data; /* Container for each row of widgets */ main_vb = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5); file_selection_set_extra_widget(file_save_as_w, main_vb); gtk_widget_show(main_vb); /*** Packet Range frame ***/ range_fr = gtk_frame_new("Packet Range"); gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0); gtk_widget_show(range_fr); /* range table */ range_tb = range_new(&range); gtk_container_add(GTK_CONTAINER(range_fr), range_tb); gtk_widget_show(range_tb); /* File type row */ 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("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); /* dynamic values in the range frame */ range_update_dynamics(range_tb); /* compressed */ compressed_cb = gtk_check_button_new_with_label("Compress with gzip"); gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb); /* XXX - disable output compression for now, as this doesn't work with the * current optimization to simply copy a capture file if it's using the same * encapsulation ... */ /* the rest of the implementation is just working fine :-( */ /*gtk_widget_show(compressed_cb);*/ g_object_set_data(G_OBJECT(file_save_as_w), "compressed", compressed_cb); gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(cfile.cd_t)); g_signal_connect(file_save_as_w, "destroy", G_CALLBACK(file_save_as_destroy_cb), NULL); if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) { file_save_as_ok_cb(file_save_as_w, file_save_as_w); } else { window_destroy(file_save_as_w); } #endif /* _WIN32 */ } void file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_) { file_save_as_cmd(after_save_no_action, NULL); } /* all tests ok, we only have to save the file */ /* (and probably continue with a pending operation) */ static void file_save_as_cb(GtkWidget *w _U_, gpointer fs) { gchar *cf_name; gchar *dirname; GtkWidget *compressed_cb; cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs))); compressed_cb = g_object_get_data(G_OBJECT(file_save_as_w), "compressed"); /* XXX - if the user requests to save to an already existing filename, */ /* ask in a dialog if that's intended */ /* currently, cf_save() will simply deny it */ /* Write out the packets (all, or only the ones from the current range) to the file with the specified name. */ if (cf_save(&cfile, cf_name, &range, filetype, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb))) != 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); /* 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)); return; } /* The write succeeded; get rid of the file selection box. */ /* cf_save() might already closed our dialog! */ if (file_save_as_w) window_destroy(GTK_WIDGET (fs)); /* Save the directory name for future file dialogs. */ dirname = get_dirname(cf_name); /* Overwrites cf_name */ set_last_open_dir(dirname); g_free(cf_name); /* we have finished saving, do we have pending things to do? */ switch(action_after_save_g) { case(after_save_no_action): break; case(after_save_open_dialog): file_open_cmd(action_after_save_data_g); break; case(after_save_open_recent_file): menu_open_recent_file_cmd(action_after_save_data_g); break; case(after_save_open_dnd_file): dnd_open_file_cmd(action_after_save_data_g); break; case(after_save_merge_dialog): file_merge_cmd(action_after_save_data_g); break; #ifdef HAVE_LIBPCAP case(after_save_capture_dialog): capture_start_confirmed(); break; #endif case(after_save_close_file): cf_close(&cfile); break; case(after_save_exit): main_do_quit(); break; default: g_assert_not_reached(); } action_after_save_g = after_save_no_action; } static void file_save_as_exists_answered_cb(gpointer dialog _U_, gint btn, gpointer data) { gchar *cf_name; cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data))); switch(btn) { case(ESD_BTN_OK): /* save file */ ws_unlink(cf_name); file_save_as_cb(NULL, data); break; case(ESD_BTN_CANCEL): /* 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(file_save_as_w); break; default: g_assert_not_reached(); } } /* user pressed "Save" dialog "Ok" button */ static void file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) { gchar *cf_name; gpointer dialog; cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs))); /* Perhaps the user specified a directory instead of a file. Check whether they did. */ if (test_for_directory(cf_name) == EISDIR) { /* It's a directory - set the file selection box to display that directory, and leave the selection box displayed. */ set_last_open_dir(cf_name); g_free(cf_name); file_selection_set_current_folder(fs, get_last_open_dir()); 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); /* 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)); return; } /* * Check that the from file is not the same as to file * We do it here so we catch all cases ... * Unfortunately, the file requester gives us an absolute file * name and the read file name may be relative (if supplied on * the command line). From Joerg Mayer. */ if (files_identical(cfile.filename, cf_name)) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%sCapture file: \"%s\" identical to loaded file!%s\n\n" "Please choose a different filename.", simple_dialog_primary_start(), cf_name, simple_dialog_primary_end()); g_free(cf_name); /* 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)); return; } /* don't show the dialog while saving (or asking) */ gtk_widget_hide(GTK_WIDGET (fs)); /* it the file doesn't exist, simply try to save it */ if (!file_exists(cf_name)) { file_save_as_cb(NULL, fs); g_free(cf_name); return; } /* the file exists, ask the user to remove it first */ dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL, "%sA file named \"%s\" already exists.%s\n\n" "Do you want to replace it with the capture you are saving?", simple_dialog_primary_start(), cf_name, simple_dialog_primary_end()); simple_dialog_set_cb(dialog, file_save_as_exists_answered_cb, fs); g_free(cf_name); } void file_save_as_destroy(void) { if (file_save_as_w) window_destroy(file_save_as_w); } static void file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) { /* Note that we no longer have a "Save Capture File As" dialog box. */ file_save_as_w = NULL; } /* Reload a file using the current read and display filters */ void file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) { cf_reload(&cfile); } /******************** Color Filters *********************************/ /* * Keep a static pointer to the current "Color Export" window, if * any, so that if somebody tries to do "Export" * while there's already a "Color Export" window up, we just pop * up the existing one, rather than creating a new one. */ static GtkWidget *file_color_import_w; /* sets the file path to the global color filter file. WARNING: called by both the import and the export dialog. */ static void color_global_cb(GtkWidget *widget _U_, gpointer data) { GtkWidget *fs_widget = data; gchar *path; /* decide what file to open (from dfilter code) */ path = get_datafile_path("colorfilters"); gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path); g_free((gchar *)path); } /* Import color filters */ void file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_) { #if _WIN32 win32_import_color_file(GDK_WINDOW_HWND(top_level->window), color_filters); #else /* _WIN32 */ GtkWidget *main_vb, *cfglobal_but; /* 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). */ if (file_color_import_w != NULL) { /* There's already an "Import Color Filters" dialog box; reactivate it. */ reactivate_window(file_color_import_w); return; } file_color_import_w = file_selection_new("Wireshark: Import Color Filters", FILE_SELECTION_OPEN); /* Container for each row of widgets */ main_vb = gtk_vbox_new(FALSE, 3); gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5); file_selection_set_extra_widget(file_color_import_w, main_vb); gtk_widget_show(main_vb); cfglobal_but = gtk_button_new_with_label("Global Color Filter File"); gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but); g_signal_connect(cfglobal_but, "clicked", G_CALLBACK(color_global_cb), file_color_import_w); gtk_widget_show(cfglobal_but); g_signal_connect(file_color_import_w, "destroy", G_CALLBACK(file_color_import_destroy_cb), NULL); if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT) { file_color_import_ok_cb(file_color_import_w, color_filters); } else window_destroy(file_color_import_w); #endif /* _WIN32 */ } static void file_color_import_ok_cb(GtkWidget *w, gpointer color_filters) { gchar *cf_name, *s; GtkWidget *fs = gtk_widget_get_toplevel(w); cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs))); /* Perhaps the user specified a directory instead of a file. Check whether they did. */ if (test_for_directory(cf_name) == EISDIR) { /* It's a directory - set the file selection box to display that directory, don't try to open the directory as a color filter file. */ set_last_open_dir(cf_name); g_free(cf_name); file_selection_set_current_folder(fs, get_last_open_dir()); return; } /* Try to open the color filter file. */ if (!color_filters_import(cf_name, color_filters)) { /* 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. */ g_free(cf_name); /* 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)); return; } /* We've crossed the Rubicon; get rid of the file selection box. */ window_destroy(GTK_WIDGET (fs)); /* 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); set_last_open_dir(s); gtk_widget_grab_focus(packet_list); g_free(cf_name); } static void file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) { /* Note that we no longer have a "Open Capture File" dialog box. */ file_color_import_w = NULL; } static GtkWidget *file_color_export_w; /* * Set the "Export only selected filters" toggle button as appropriate for * the current output file type and count of selected filters. * * Called when the "Export" dialog box is created and when the selected * count changes. */ static void color_set_export_selected_sensitive(GtkWidget * cfselect_cb) { if (file_color_export_w == NULL) { /* We don't currently have an "Export" dialog box up. */ return; } /* We can request that only the selected filters be saved only if there *are* selected filters. */ if (color_selected_count() != 0) gtk_widget_set_sensitive(cfselect_cb, TRUE); else { /* Force the "Export only selected filters" toggle to "false", turn off the flag it controls. */ color_selected = FALSE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE); gtk_widget_set_sensitive(cfselect_cb, FALSE); } } static void color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_) { color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget)); } void file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list) { #if _WIN32 win32_export_color_file(GDK_WINDOW_HWND(top_level->window), filter_list); #else /* _WIN32 */ GtkWidget *main_vb, *cfglobal_but; if (file_color_export_w != NULL) { /* There's already an "Color Filter Export" dialog box; reactivate it. */ reactivate_window(file_color_export_w); return; } /* Default to saving all packets, in the file's current format. */ color_selected = FALSE; filetype = cfile.cd_t; file_color_export_w = file_selection_new("Wireshark: Export Color Filters", FILE_SELECTION_SAVE); /* Container for each row of widgets */ main_vb = gtk_vbox_new(FALSE, 3); gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5); file_selection_set_extra_widget(file_color_export_w, main_vb); gtk_widget_show(main_vb); cfselect_cb = gtk_check_button_new_with_label("Export only selected filters"); gtk_container_add(GTK_CONTAINER(main_vb), cfselect_cb); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE); g_signal_connect(cfselect_cb, "toggled", G_CALLBACK(color_toggle_selected_cb), NULL); gtk_widget_show(cfselect_cb); color_set_export_selected_sensitive(cfselect_cb); cfglobal_but = gtk_button_new_with_label("Global Color Filter File"); gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but); g_signal_connect(cfglobal_but, "clicked", G_CALLBACK(color_global_cb), file_color_export_w); gtk_widget_show(cfglobal_but); g_signal_connect(file_color_export_w, "destroy", G_CALLBACK(file_color_export_destroy_cb), NULL); if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT) { file_color_export_ok_cb(file_color_export_w, filter_list); } else window_destroy(file_color_export_w); #endif /* _WIN32 */ } static void file_color_export_ok_cb(GtkWidget *w, gpointer filter_list) { gchar *cf_name; gchar *dirname; GtkWidget *fs = gtk_widget_get_toplevel(w); cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs))); /* Perhaps the user specified a directory instead of a file. Check whether they did. */ if (test_for_directory(cf_name) == EISDIR) { /* It's a directory - set the file selection box to display that directory, and leave the selection box displayed. */ set_last_open_dir(cf_name); g_free(cf_name); file_selection_set_current_folder(fs, get_last_open_dir()); return; } /* Write out the filters (all, or only the ones that are currently displayed or selected) to the file with the specified name. */ if (!color_filters_export(cf_name, filter_list, color_selected)) { /* 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); /* 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)); return; } /* The write succeeded; get rid of the file selection box. */ window_destroy(GTK_WIDGET (fs)); /* Save the directory name for future file dialogs. */ dirname = get_dirname(cf_name); /* Overwrites cf_name */ set_last_open_dir(dirname); g_free(cf_name); } static void file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) { file_color_export_w = NULL; }