2 * Dialog boxes for handling capture files
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include "packet-range.h"
34 #include <epan/filesystem.h>
37 #include "gtkglobals.h"
38 #include <epan/addr_resolv.h>
40 #include "filter_dlg.h"
41 #include "gui_utils.h"
42 #include "alert_box.h"
43 #include "simple_dialog.h"
45 #include "dlg_utils.h"
47 #include "capture_file_dlg.h"
49 #include "compat_macros.h"
50 #include <epan/prefs.h>
53 #include "../ui_util.h"
54 #include "color_filters.h"
55 #include "gtk/color_dlg.h"
57 #include "capture_dlg.h"
59 #include "range_utils.h"
67 #if GTK_MAJOR_VERSION >= 2 && _WIN32
68 #include <gdk/gdkwin32.h>
70 #include "win32-file-dlg.h"
73 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
74 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
75 static void file_merge_ok_cb(GtkWidget *w, gpointer fs);
76 static void file_merge_destroy_cb(GtkWidget *win, gpointer user_data);
77 static void select_file_type_cb(GtkWidget *w, gpointer data);
78 static void file_save_as_ok_cb(GtkWidget *w, gpointer fs);
79 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
80 static void file_color_import_ok_cb(GtkWidget *w, gpointer filter_list);
81 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
82 static void file_color_export_ok_cb(GtkWidget *w, gpointer filter_list);
83 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
84 static void set_file_type_list(GtkWidget *option_menu);
86 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
87 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
88 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
90 #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key"
91 #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key"
92 #define E_MERGE_APPEND_KEY "merge_dlg_append_key"
95 #define PREVIEW_TABLE_KEY "preview_table_key"
96 #define PREVIEW_FILENAME_KEY "preview_filename_key"
97 #define PREVIEW_FORMAT_KEY "preview_format_key"
98 #define PREVIEW_SIZE_KEY "preview_size_key"
99 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
100 #define PREVIEW_PACKETS_KEY "preview_packets_key"
101 #define PREVIEW_FIRST_KEY "preview_first_key"
105 * Keep a static pointer to the current "Save Capture File As" window, if
106 * any, so that if somebody tries to do "File:Save" or "File:Save As"
107 * while there's already a "Save Capture File As" window up, we just pop
108 * up the existing one, rather than creating a new one.
110 static GtkWidget *file_save_as_w;
112 /* XXX - can we make these not be static? */
113 static packet_range_t range;
114 static gboolean color_selected;
116 static GtkWidget *cfselect_cb;
117 static GtkWidget *ft_om;
118 static GtkWidget *range_tb;
120 #define PREVIEW_STR_MAX 200
123 /* set a new filename for the preview widget */
125 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
131 gchar string_buff[PREVIEW_STR_MAX];
135 /* init preview labels */
136 label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
137 gtk_label_set_text(GTK_LABEL(label), "-");
138 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
139 gtk_label_set_text(GTK_LABEL(label), "-");
140 label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
141 gtk_label_set_text(GTK_LABEL(label), "-");
142 label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
143 gtk_label_set_text(GTK_LABEL(label), "-");
144 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
145 gtk_label_set_text(GTK_LABEL(label), "-");
146 label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
147 gtk_label_set_text(GTK_LABEL(label), "-");
153 label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
154 gtk_label_set_text(GTK_LABEL(label), get_basename(cf_name));
156 if (test_for_directory(cf_name) == EISDIR) {
157 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
158 gtk_label_set_text(GTK_LABEL(label), "directory");
162 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
164 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
165 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
166 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
168 gtk_label_set_text(GTK_LABEL(label), "error opening file");
173 /* Find the size of the file. */
174 filesize = wtap_file_size(wth, &err);
175 if (filesize == -1) {
176 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
180 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" PRId64 " bytes", filesize);
181 label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
182 gtk_label_set_text(GTK_LABEL(label), string_buff);
185 g_snprintf(string_buff, PREVIEW_STR_MAX, "%s", wtap_file_type_string(wtap_file_type(wth)));
186 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
187 gtk_label_set_text(GTK_LABEL(label), string_buff);
193 /* do a preview run on the currently selected capture file */
195 preview_do(GtkWidget *prev, wtap *wth)
198 unsigned int elapsed_time;
204 const struct wtap_pkthdr *phdr;
205 double start_time = 0; /* seconds, with nsec resolution */
206 double stop_time = 0; /* seconds, with nsec resolution */
208 unsigned int packets = 0;
209 gboolean is_breaked = FALSE;
210 gchar string_buff[PREVIEW_STR_MAX];
216 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
217 phdr = wtap_phdr(wth);
218 cur_time = nstime_to_sec( (const nstime_t *) &phdr->ts );
220 start_time = cur_time;
221 stop_time = cur_time;
223 if (cur_time < start_time) {
224 start_time = cur_time;
226 if (cur_time > stop_time){
227 stop_time = cur_time;
232 /* do we have a timeout? */
234 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
242 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
243 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
244 gtk_label_set_text(GTK_LABEL(label), string_buff);
251 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
253 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
255 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
256 gtk_label_set_text(GTK_LABEL(label), string_buff);
259 ti_time = (long)start_time;
260 ti_tm = localtime( &ti_time );
262 g_snprintf(string_buff, PREVIEW_STR_MAX,
263 "%04d-%02d-%02d %02d:%02d:%02d",
264 ti_tm->tm_year + 1900,
271 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
273 label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
274 gtk_label_set_text(GTK_LABEL(label), string_buff);
277 elapsed_time = (unsigned int)(stop_time-start_time);
278 if(elapsed_time/86400) {
279 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
280 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
282 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
283 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
286 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
288 label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
289 gtk_label_set_text(GTK_LABEL(label), string_buff);
295 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
296 simply use the same layout as in GTK1 */
297 /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
299 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
301 GtkWidget *prev = GTK_WIDGET (data);
303 gboolean have_preview;
305 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
307 have_preview = preview_set_filename(prev, cf_name);
312 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
317 /* the filename text entry changed */
319 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
321 GtkWidget *prev = OBJECT_GET_DATA(file_sel, PREVIEW_TABLE_KEY);
322 const gchar* cf_name;
323 gboolean have_preview;
326 /* get the filename */
327 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
328 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
330 cf_name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_sel));
333 /* set the filename to the preview */
334 wth = preview_set_filename(prev, cf_name);
335 have_preview = (wth != NULL);
337 /* make the preview widget sensitive */
338 gtk_widget_set_sensitive(prev, have_preview);
340 /* make the open/save/... dialog button sensitive */
341 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
342 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
344 gtk_widget_set_sensitive(GTK_FILE_SELECTION(file_sel)->ok_button, have_preview);
347 /* do the actual preview */
349 preview_do(prev, wth);
353 /* copied from summary_dlg.c */
355 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
360 if(strlen(value) != 0) {
361 indent = g_strdup_printf(" %s", title);
363 indent = g_strdup(title);
365 label = gtk_label_new(indent);
367 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
368 gtk_widget_set_sensitive(label, sensitive);
369 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
371 label = gtk_label_new(value);
372 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
373 gtk_widget_set_sensitive(label, sensitive);
374 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
382 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
384 return add_string_to_table_sensitive(list, row, title, value, TRUE);
392 GtkWidget *table, *label;
395 table = gtk_table_new(1, 2, FALSE);
396 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
397 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
400 label = add_string_to_table(table, &row, "Filename:", "-");
401 WIDGET_SET_SIZE(label, DEF_WIDTH/3, -1);
402 OBJECT_SET_DATA(table, PREVIEW_FILENAME_KEY, label);
403 label = add_string_to_table(table, &row, "Format:", "-");
404 OBJECT_SET_DATA(table, PREVIEW_FORMAT_KEY, label);
405 label = add_string_to_table(table, &row, "Size:", "-");
406 OBJECT_SET_DATA(table, PREVIEW_SIZE_KEY, label);
407 label = add_string_to_table(table, &row, "Packets:", "-");
408 OBJECT_SET_DATA(table, PREVIEW_PACKETS_KEY, label);
409 label = add_string_to_table(table, &row, "First Packet:", "-");
410 OBJECT_SET_DATA(table, PREVIEW_FIRST_KEY, label);
411 label = add_string_to_table(table, &row, "Elapsed time:", "-");
412 OBJECT_SET_DATA(table, PREVIEW_ELAPSED_KEY, label);
418 * Keep a static pointer to the current "Open Capture File" window, if
419 * any, so that if somebody tries to do "File:Open" while there's already
420 * an "Open Capture File" window up, we just pop up the existing one,
421 * rather than creating a new one.
423 static GtkWidget *file_open_w;
427 file_open_cmd(GtkWidget *w)
429 #if GTK_MAJOR_VERSION >= 2 && _WIN32
430 win32_open_file(GDK_WINDOW_HWND(top_level->window));
431 #else /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
432 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
433 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
434 #if GTK_MAJOR_VERSION < 2
435 GtkAccelGroup *accel_group;
438 /* No Apply button, and "OK" just sets our text widget, it doesn't
439 activate it (i.e., it doesn't cause us to try to open the file). */
440 static construct_args_t args = {
441 "Wireshark: Read Filter",
447 if (file_open_w != NULL) {
448 /* There's already an "Open Capture File" dialog box; reactivate it. */
449 reactivate_window(file_open_w);
453 file_open_w = file_selection_new("Wireshark: Open Capture File",
454 FILE_SELECTION_OPEN);
455 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
456 /* it's annoying, that the file chooser dialog is already shown here,
457 so we cannot use the correct gtk_window_set_default_size() to resize it */
458 WIDGET_SET_SIZE(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
460 gtk_window_set_default_size(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
463 #if GTK_MAJOR_VERSION < 2
464 /* Accelerator group for the accelerators (or, as they're called in
465 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
466 Ctrl+<key> is an accelerator). */
467 accel_group = gtk_accel_group_new();
468 gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
471 switch (prefs.gui_fileopen_style) {
473 case FO_STYLE_LAST_OPENED:
474 /* The user has specified that we should start out in the last directory
475 we looked in. If we've already opened a file, use its containing
476 directory, if we could determine it, as the directory, otherwise
477 use the "last opened" directory saved in the preferences file if
479 /* This is now the default behaviour in file_selection_new() */
482 case FO_STYLE_SPECIFIED:
483 /* The user has specified that we should always start out in a
484 specified directory; if they've specified that directory,
485 start out by showing the files in that dir. */
486 if (prefs.gui_fileopen_dir[0] != '\0')
487 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
492 main_hb = gtk_hbox_new(FALSE, 3);
493 file_selection_set_extra_widget(file_open_w, main_hb);
494 gtk_widget_show(main_hb);
496 /* Container for each row of widgets */
497 main_vb = gtk_vbox_new(FALSE, 3);
498 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
499 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
500 gtk_widget_show(main_vb);
503 filter_hbox = gtk_hbox_new(FALSE, 1);
504 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
505 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
506 gtk_widget_show(filter_hbox);
508 filter_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
509 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
510 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
511 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
512 gtk_widget_show(filter_bt);
514 filter_te = gtk_entry_new();
515 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
516 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
517 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
518 gtk_widget_show(filter_te);
520 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
521 OBJECT_SET_DATA(file_open_w, E_RFILTER_TE_KEY, filter_te);
523 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
524 E_RFILTER_TE_KEY, filter_te);
527 /* resolve buttons */
528 m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
529 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
530 g_resolv_flags & RESOLV_MAC);
531 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
532 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
533 OBJECT_SET_DATA(file_open_w,
534 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
536 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
537 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
539 gtk_widget_show(m_resolv_cb);
541 n_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _network name resolution", accel_group);
542 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
543 g_resolv_flags & RESOLV_NETWORK);
544 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
545 gtk_widget_show(n_resolv_cb);
546 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
547 OBJECT_SET_DATA(file_open_w, E_FILE_N_RESOLVE_KEY, n_resolv_cb);
549 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
550 E_FILE_N_RESOLVE_KEY, n_resolv_cb);
553 t_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _transport name resolution", accel_group);
554 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
555 g_resolv_flags & RESOLV_TRANSPORT);
556 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
557 gtk_widget_show(t_resolv_cb);
558 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
559 OBJECT_SET_DATA(file_open_w, E_FILE_T_RESOLVE_KEY, t_resolv_cb);
561 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
562 E_FILE_T_RESOLVE_KEY, t_resolv_cb);
566 SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
569 prev = preview_new();
570 OBJECT_SET_DATA(file_open_w, PREVIEW_TABLE_KEY, prev);
571 gtk_widget_show_all(prev);
572 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
574 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
575 SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
576 file_open_entry_changed, file_open_w);
577 file_open_entry_changed(file_open_w, file_open_w);
579 OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
580 OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
581 if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
583 file_open_ok_cb(file_open_w, file_open_w);
585 else window_destroy(file_open_w);
586 #else /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
587 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->selection_entry, "changed",
588 file_open_entry_changed, file_open_w);
590 /* Connect the ok_button to file_open_ok_cb function and pass along a
591 pointer to the file selection box widget */
592 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
593 file_open_ok_cb, file_open_w);
595 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
596 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
598 /* Connect the cancel_button to destroy the widget */
599 window_set_cancel_button(file_open_w,
600 GTK_FILE_SELECTION(file_open_w)->cancel_button, window_cancel_button_cb);
602 SIGNAL_CONNECT(file_open_w, "delete_event", window_delete_event_cb, NULL);
604 gtk_widget_show(file_open_w);
605 window_present(file_open_w);
606 #endif /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
607 #endif /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
610 static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
614 /* save file first */
615 file_save_as_cmd(after_save_open_dialog, data);
617 case(ESD_BTN_DONT_SAVE):
621 case(ESD_BTN_CANCEL):
624 g_assert_not_reached();
629 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
632 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
633 /* user didn't saved his current file, ask him */
634 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
635 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
636 "If you open a new capture file without saving, your capture data will be discarded.");
637 simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
639 /* unchanged file, just open a new one */
640 file_open_cmd(widget);
644 /* user pressed "open" button */
646 file_open_ok_cb(GtkWidget *w, gpointer fs) {
648 const gchar *rfilter;
649 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
650 dfilter_t *rfcode = NULL;
653 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
654 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
656 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
658 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
659 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
660 if (!dfilter_compile(rfilter, &rfcode)) {
661 bad_dfilter_alert_box(rfilter);
666 /* Perhaps the user specified a directory instead of a file.
667 Check whether they did. */
668 if (test_for_directory(cf_name) == EISDIR) {
669 /* It's a directory - set the file selection box to display that
670 directory, don't try to open the directory as a capture file. */
671 set_last_open_dir(cf_name);
673 file_selection_set_current_folder(fs, get_last_open_dir());
677 /* Try to open the capture file. */
678 if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
679 /* We couldn't open it; don't dismiss the open dialog box,
680 just leave it around so that the user can, after they
681 dismiss the alert box popped up for the open error,
684 dfilter_free(rfcode);
689 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
690 it closed the previous capture file, and thus destroyed any
691 previous read filter attached to "cf"). */
692 cfile.rfcode = rfcode;
694 /* Set the global resolving variable */
695 g_resolv_flags = prefs.name_resolve;
696 m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
697 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
698 g_resolv_flags |= RESOLV_MAC;
700 g_resolv_flags &= ~RESOLV_MAC;
701 n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
702 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
703 g_resolv_flags |= RESOLV_NETWORK;
705 g_resolv_flags &= ~RESOLV_NETWORK;
706 t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
707 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
708 g_resolv_flags |= RESOLV_TRANSPORT;
710 g_resolv_flags &= ~RESOLV_TRANSPORT;
712 /* We've crossed the Rubicon; get rid of the file selection box. */
713 window_destroy(GTK_WIDGET (fs));
715 switch (cf_read(&cfile)) {
719 /* Just because we got an error, that doesn't mean we were unable
720 to read any of the file; we handle what we could get from the
724 case CF_READ_ABORTED:
725 /* The user bailed out of re-reading the capture file; the
726 capture file has been closed - just free the capture file name
727 string and return (without changing the last containing
733 /* Save the name of the containing directory specified in the path name,
734 if any; we can write over cf_name, which is a good thing, given that
735 "get_dirname()" does write over its argument. */
736 s = get_dirname(cf_name);
737 set_last_open_dir(s);
738 gtk_widget_grab_focus(packet_list);
744 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
746 /* Note that we no longer have a "Open Capture File" dialog box. */
751 * Keep a static pointer to the current "Merge Capture File" window, if
752 * any, so that if somebody tries to do "File:Merge" while there's already
753 * an "Merge Capture File" window up, we just pop up the existing one,
754 * rather than creating a new one.
756 static GtkWidget *file_merge_w;
758 /* Merge existing with another file */
760 file_merge_cmd(GtkWidget *w)
762 #if GTK_MAJOR_VERSION >= 2 && _WIN32
763 win32_merge_file(GDK_WINDOW_HWND(top_level->window));
764 packet_list_freeze();
766 #else /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
767 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *filter_hbox,
768 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
770 #if GTK_MAJOR_VERSION < 2
771 GtkAccelGroup *accel_group;
773 GtkTooltips *tooltips = gtk_tooltips_new();
774 /* No Apply button, and "OK" just sets our text widget, it doesn't
775 activate it (i.e., it doesn't cause us to try to open the file). */
776 static construct_args_t args = {
777 "Wireshark: Read Filter",
783 if (file_merge_w != NULL) {
784 /* There's already an "Merge Capture File" dialog box; reactivate it. */
785 reactivate_window(file_merge_w);
789 /* Default to saving all packets, in the file's current format. */
790 filetype = cfile.cd_t;
792 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
793 FILE_SELECTION_OPEN);
794 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
795 /* it's annoying, that the file chooser dialog is already shown here,
796 so we cannot use the correct gtk_window_set_default_size() to resize it */
797 WIDGET_SET_SIZE(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
799 gtk_window_set_default_size(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
802 #if GTK_MAJOR_VERSION < 2
803 /* Accelerator group for the accelerators (or, as they're called in
804 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
805 Ctrl+<key> is an accelerator). */
806 accel_group = gtk_accel_group_new();
807 gtk_window_add_accel_group(GTK_WINDOW(file_merge_w), accel_group);
810 switch (prefs.gui_fileopen_style) {
812 case FO_STYLE_LAST_OPENED:
813 /* The user has specified that we should start out in the last directory
814 we looked in. If we've already opened a file, use its containing
815 directory, if we could determine it, as the directory, otherwise
816 use the "last opened" directory saved in the preferences file if
818 /* This is now the default behaviour in file_selection_new() */
821 case FO_STYLE_SPECIFIED:
822 /* The user has specified that we should always start out in a
823 specified directory; if they've specified that directory,
824 start out by showing the files in that dir. */
825 if (prefs.gui_fileopen_dir[0] != '\0')
826 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
830 main_hb = gtk_hbox_new(FALSE, 3);
831 file_selection_set_extra_widget(file_merge_w, main_hb);
832 gtk_widget_show(main_hb);
834 /* Container for each row of widgets */
835 main_vb = gtk_vbox_new(FALSE, 3);
836 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
837 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
838 gtk_widget_show(main_vb);
842 ft_hb = gtk_hbox_new(FALSE, 3);
843 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
844 gtk_widget_show(ft_hb);
846 ft_lb = gtk_label_new("Merged output file type:");
847 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
848 gtk_widget_show(ft_lb);
850 ft_om = gtk_option_menu_new();
852 /* Generate the list of file types we can save. */
853 set_file_type_list(ft_om);
854 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
855 gtk_widget_show(ft_om);
857 filter_hbox = gtk_hbox_new(FALSE, 1);
858 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
859 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
860 gtk_widget_show(filter_hbox);
862 filter_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
863 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
864 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
865 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
866 gtk_widget_show(filter_bt);
868 filter_te = gtk_entry_new();
869 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
870 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
871 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
872 gtk_widget_show(filter_te);
874 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
875 OBJECT_SET_DATA(file_merge_w, E_RFILTER_TE_KEY, filter_te);
877 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
878 E_RFILTER_TE_KEY, filter_te);
881 prepend_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Prepend packets to existing file", accel_group);
882 gtk_tooltips_set_tip(tooltips, prepend_rb,
883 "The resulting file contains the packets from the selected, followed by the packets from the currently loaded file,"
884 " the packet timestamps will be ignored.", NULL);
885 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
886 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
887 OBJECT_SET_DATA(file_merge_w,
888 E_MERGE_PREPEND_KEY, prepend_rb);
890 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
891 E_MERGE_PREPEND_KEY, prepend_rb);
893 gtk_widget_show(prepend_rb);
895 chrono_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Merge packets chronologically", accel_group);
896 gtk_tooltips_set_tip(tooltips, chrono_rb,
897 "The resulting file contains all the packets from the currently loaded and the selected file,"
898 " sorted by the packet timestamps.", NULL);
899 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
900 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
901 gtk_widget_show(chrono_rb);
902 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
903 OBJECT_SET_DATA(file_merge_w, E_MERGE_CHRONO_KEY, chrono_rb);
905 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
906 E_MERGE_CHRONO_KEY, chrono_rb);
909 append_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Append packets to existing file", accel_group);
910 gtk_tooltips_set_tip(tooltips, append_rb,
911 "The resulting file contains the packets from the currently loaded, followed by the packets from the selected file,"
912 " the packet timestamps will be ignored.", NULL);
913 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(append_rb),
914 g_resolv_flags & RESOLV_TRANSPORT);
915 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
916 gtk_widget_show(append_rb);
917 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
918 OBJECT_SET_DATA(file_merge_w, E_MERGE_APPEND_KEY, append_rb);
920 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
921 E_MERGE_APPEND_KEY, append_rb);
925 SIGNAL_CONNECT(file_merge_w, "destroy", file_merge_destroy_cb, NULL);
928 prev = preview_new();
929 OBJECT_SET_DATA(file_merge_w, PREVIEW_TABLE_KEY, prev);
930 gtk_widget_show_all(prev);
931 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
933 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
934 SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
935 file_open_entry_changed, file_merge_w);
936 file_open_entry_changed(file_merge_w, file_merge_w);
938 OBJECT_SET_DATA(file_merge_w, E_DFILTER_TE_KEY,
939 OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
940 if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
942 file_merge_ok_cb(file_merge_w, file_merge_w);
944 else window_destroy(file_merge_w);
945 #else /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
946 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->selection_entry, "changed",
947 file_open_entry_changed, file_merge_w);
949 /* Connect the ok_button to file_merge_ok_cb function and pass along a
950 pointer to the file selection box widget */
951 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->ok_button, "clicked",
952 file_merge_ok_cb, file_merge_w);
954 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
955 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
957 /* Connect the cancel_button to destroy the widget */
958 window_set_cancel_button(file_merge_w,
959 GTK_FILE_SELECTION(file_merge_w)->cancel_button, window_cancel_button_cb);
961 SIGNAL_CONNECT(file_merge_w, "delete_event", window_delete_event_cb, NULL);
963 gtk_widget_show(file_merge_w);
964 window_present(file_merge_w);
965 #endif /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
966 #endif /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
969 static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
973 /* save file first */
974 file_save_as_cmd(after_save_merge_dialog, data);
976 case(ESD_BTN_CANCEL):
979 g_assert_not_reached();
984 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
987 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
988 /* user didn't saved his current file, ask him */
989 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
990 PRIMARY_TEXT_START "Save the capture file before merging to another one?" PRIMARY_TEXT_END "\n\n"
991 "A temporary capture file can't be merged.");
992 simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
994 /* unchanged file, just start to merge */
995 file_merge_cmd(widget);
1001 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
1003 const gchar *rfilter;
1004 GtkWidget *filter_te, *rb;
1005 dfilter_t *rfcode = NULL;
1007 cf_status_t merge_status;
1008 char *in_filenames[2];
1011 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1012 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1014 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1016 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
1017 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
1018 if (!dfilter_compile(rfilter, &rfcode)) {
1019 bad_dfilter_alert_box(rfilter);
1024 /* Perhaps the user specified a directory instead of a file.
1025 Check whether they did. */
1026 if (test_for_directory(cf_name) == EISDIR) {
1027 /* It's a directory - set the file selection box to display that
1028 directory, don't try to open the directory as a capture file. */
1029 set_last_open_dir(cf_name);
1031 file_selection_set_current_folder(fs, get_last_open_dir());
1035 /* merge or append the two files */
1036 rb = OBJECT_GET_DATA(w, E_MERGE_CHRONO_KEY);
1038 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1039 /* chronological order */
1040 in_filenames[0] = cfile.filename;
1041 in_filenames[1] = cf_name;
1042 merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype, FALSE);
1044 rb = OBJECT_GET_DATA(w, E_MERGE_PREPEND_KEY);
1045 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1047 in_filenames[0] = cfile.filename;
1048 in_filenames[1] = cf_name;
1049 merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype,
1053 in_filenames[0] = cf_name;
1054 in_filenames[1] = cfile.filename;
1055 merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype,
1062 if (merge_status != CF_OK) {
1064 dfilter_free(rfcode);
1071 /* We've crossed the Rubicon; get rid of the file selection box. */
1072 window_destroy(GTK_WIDGET (fs));
1074 /* Try to open the merged capture file. */
1075 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
1076 /* We couldn't open it; don't dismiss the open dialog box,
1077 just leave it around so that the user can, after they
1078 dismiss the alert box popped up for the open error,
1081 dfilter_free(rfcode);
1087 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
1088 it closed the previous capture file, and thus destroyed any
1089 previous read filter attached to "cf"). */
1090 cfile.rfcode = rfcode;
1092 switch (cf_read(&cfile)) {
1096 /* Just because we got an error, that doesn't mean we were unable
1097 to read any of the file; we handle what we could get from the
1101 case CF_READ_ABORTED:
1102 /* The user bailed out of re-reading the capture file; the
1103 capture file has been closed - just free the capture file name
1104 string and return (without changing the last containing
1109 /* Save the name of the containing directory specified in the path name,
1110 if any; we can write over cf_merged_name, which is a good thing, given that
1111 "get_dirname()" does write over its argument. */
1112 s = get_dirname(tmpname);
1113 set_last_open_dir(s);
1114 gtk_widget_grab_focus(packet_list);
1118 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1120 /* Note that we no longer have a "Merge Capture File" dialog box. */
1121 file_merge_w = NULL;
1125 static void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1129 /* save file first */
1130 file_save_as_cmd(after_save_close_file, NULL);
1132 case(ESD_BTN_DONT_SAVE):
1135 case(ESD_BTN_CANCEL):
1138 g_assert_not_reached();
1144 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1147 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1148 /* user didn't saved his current file, ask him */
1149 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1150 PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
1151 "If you close without saving, your capture data will be discarded.");
1153 simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
1155 /* unchanged file, just close it */
1161 file_save_cmd_cb(GtkWidget *w, gpointer data) {
1162 /* If the file's already been saved, do nothing. */
1163 if (cfile.user_saved)
1166 /* Do a "Save As". */
1167 file_save_as_cmd_cb(w, data);
1171 can_save_with_wiretap(int ft)
1173 /* To save a file with Wiretap, Wiretap has to handle that format,
1174 and its code to handle that format must be able to write a file
1175 with this file's encapsulation type. */
1176 return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
1180 /* Generate a list of the file types we can save this file as, by
1181 checking what Wiretap supports. */
1183 set_file_type_list(GtkWidget *option_menu)
1185 GtkWidget *ft_menu, *ft_menu_item;
1188 guint item_to_select;
1190 /* Default to the first supported file type, if the file's current
1191 type isn't supported. */
1194 ft_menu = gtk_menu_new();
1196 /* Check all file types. */
1198 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
1199 if (can_save_with_wiretap(ft)) {
1200 /* OK, we can write it out in this type. */
1201 ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
1202 if (ft == filetype) {
1203 /* Default to the same format as the file, if it's supported. */
1204 item_to_select = index;
1206 SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
1207 GINT_TO_POINTER(ft));
1208 gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
1209 gtk_widget_show(ft_menu_item);
1214 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
1215 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
1219 select_file_type_cb(GtkWidget *w _U_, gpointer data)
1221 int new_filetype = GPOINTER_TO_INT(data);
1222 GtkWidget *compressed_cb;
1224 if (filetype != new_filetype) {
1225 filetype = new_filetype;
1226 compressed_cb = OBJECT_GET_DATA(file_save_as_w, "compressed");
1227 gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(new_filetype));
1233 * Update various dynamic parts of the range controls; called from outside
1234 * the file dialog code whenever the packet counts change.
1237 file_save_update_dynamics(void)
1239 if (file_save_as_w == NULL) {
1240 /* We don't currently have a "Save As..." dialog box up. */
1244 range_update_dynamics(range_tb);
1248 action_after_save_e action_after_save_g;
1249 gpointer action_after_save_data_g;
1253 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
1255 #if GTK_MAJOR_VERSION >= 2 && _WIN32
1256 win32_save_as_file(GDK_WINDOW_HWND(top_level->window), action_after_save, action_after_save_data);
1257 #else /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
1258 GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr, *compressed_cb;
1259 GtkTooltips *tooltips;
1261 #if GTK_MAJOR_VERSION < 2
1262 GtkAccelGroup *accel_group;
1265 if (file_save_as_w != NULL) {
1266 /* There's already an "Save Capture File As" dialog box; reactivate it. */
1267 reactivate_window(file_save_as_w);
1271 /* Default to saving all packets, in the file's current format. */
1272 filetype = cfile.cd_t;
1274 /* init the packet range */
1275 packet_range_init(&range);
1277 /* Enable tooltips */
1278 tooltips = gtk_tooltips_new();
1280 /* build the file selection */
1281 file_save_as_w = file_selection_new ("Wireshark: Save Capture File As",
1282 FILE_SELECTION_SAVE);
1284 /* as the dialog might already be gone, when using this values, we cannot
1285 * set data to the dialog object, but keep global values */
1286 action_after_save_g = action_after_save;
1287 action_after_save_data_g = action_after_save_data;
1289 #if GTK_MAJOR_VERSION < 2
1290 accel_group = gtk_accel_group_new();
1291 gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
1294 /* Container for each row of widgets */
1296 main_vb = gtk_vbox_new(FALSE, 5);
1297 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1298 file_selection_set_extra_widget(file_save_as_w, main_vb);
1299 gtk_widget_show(main_vb);
1301 /*** Packet Range frame ***/
1302 range_fr = gtk_frame_new("Packet Range");
1303 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1304 gtk_widget_show(range_fr);
1307 range_tb = range_new(&range
1308 #if GTK_MAJOR_VERSION < 2
1312 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1313 gtk_widget_show(range_tb);
1316 ft_hb = gtk_hbox_new(FALSE, 3);
1317 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1318 gtk_widget_show(ft_hb);
1320 ft_lb = gtk_label_new("File type:");
1321 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1322 gtk_widget_show(ft_lb);
1324 ft_om = gtk_option_menu_new();
1326 /* Generate the list of file types we can save. */
1327 set_file_type_list(ft_om);
1328 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1329 gtk_widget_show(ft_om);
1331 /* dynamic values in the range frame */
1332 range_update_dynamics(range_tb);
1335 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1336 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1337 /* XXX - disable output compression for now, as this doesn't work with the
1338 * current optimization to simply copy a capture file if it's using the same
1339 * encapsulation ... */
1340 /* the rest of the implementation is just working fine :-( */
1341 /*gtk_widget_show(compressed_cb);*/
1342 OBJECT_SET_DATA(file_save_as_w, "compressed", compressed_cb);
1343 gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(cfile.cd_t));
1345 SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
1347 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1348 if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) {
1349 file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1351 window_destroy(file_save_as_w);
1353 #else /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
1354 /* Connect the ok_button to file_save_as_ok_cb function and pass along a
1355 pointer to the file selection box widget */
1356 SIGNAL_CONNECT(GTK_FILE_SELECTION (file_save_as_w)->ok_button, "clicked",
1357 file_save_as_ok_cb, file_save_as_w);
1359 window_set_cancel_button(file_save_as_w,
1360 GTK_FILE_SELECTION(file_save_as_w)->cancel_button, window_cancel_button_cb);
1362 SIGNAL_CONNECT(file_save_as_w, "delete_event", window_delete_event_cb, NULL);
1364 gtk_widget_show(file_save_as_w);
1365 window_present(file_save_as_w);
1366 #endif /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
1367 #endif /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
1371 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1373 file_save_as_cmd(after_save_no_action, NULL);
1377 /* all tests ok, we only have to save the file */
1378 /* (and probably continue with a pending operation) */
1380 file_save_as_cb(GtkWidget *w _U_, gpointer fs) {
1383 GtkWidget *compressed_cb;
1386 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1387 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1389 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1392 compressed_cb = OBJECT_GET_DATA(file_save_as_w, "compressed");
1394 /* XXX - if the user requests to save to an already existing filename, */
1395 /* ask in a dialog if that's intended */
1396 /* currently, cf_save() will simply deny it */
1398 /* Write out the packets (all, or only the ones from the current
1399 range) to the file with the specified name. */
1400 if (cf_save(&cfile, cf_name, &range, filetype,
1401 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb))) != CF_OK) {
1402 /* The write failed; don't dismiss the open dialog box,
1403 just leave it around so that the user can, after they
1404 dismiss the alert box popped up for the error, try again. */
1406 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1407 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1408 * as this will prevent the user from closing the now existing error
1409 * message, simply close the dialog (this is the best we can do here). */
1411 window_destroy(GTK_WIDGET (fs));
1413 gtk_widget_show(GTK_WIDGET (fs));
1418 /* The write succeeded; get rid of the file selection box. */
1419 /* cf_save() might already closed our dialog! */
1421 window_destroy(GTK_WIDGET (fs));
1423 /* Save the directory name for future file dialogs. */
1424 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1425 set_last_open_dir(dirname);
1428 /* we have finished saving, do we have pending things to do? */
1429 switch(action_after_save_g) {
1430 case(after_save_no_action):
1432 case(after_save_open_dialog):
1433 file_open_cmd(action_after_save_data_g);
1435 case(after_save_open_recent_file):
1436 menu_open_recent_file_cmd(action_after_save_data_g);
1438 case(after_save_open_dnd_file):
1439 dnd_open_file_cmd(action_after_save_data_g);
1441 case(after_save_merge_dialog):
1442 file_merge_cmd(action_after_save_data_g);
1445 case(after_save_capture_dialog):
1446 capture_start_confirmed();
1449 case(after_save_close_file):
1452 case(after_save_exit):
1456 g_assert_not_reached();
1459 action_after_save_g = after_save_no_action;
1463 static void file_save_as_exists_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
1467 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1468 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data)));
1470 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(data)));
1477 file_save_as_cb(NULL, data);
1479 case(ESD_BTN_CANCEL):
1482 g_assert_not_reached();
1487 /* user pressed "Save" dialog "Ok" button */
1489 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1493 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1494 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1496 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1499 /* Perhaps the user specified a directory instead of a file.
1500 Check whether they did. */
1501 if (test_for_directory(cf_name) == EISDIR) {
1502 /* It's a directory - set the file selection box to display that
1503 directory, and leave the selection box displayed. */
1504 set_last_open_dir(cf_name);
1506 file_selection_set_current_folder(fs, get_last_open_dir());
1510 /* Check whether the range is valid. */
1511 if (!range_check_validity(&range)) {
1512 /* The range isn't valid; don't dismiss the open dialog box,
1513 just leave it around so that the user can, after they
1514 dismiss the alert box popped up for the error, try again. */
1516 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1517 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1518 * as this will prevent the user from closing the now existing error
1519 * message, simply close the dialog (this is the best we can do here). */
1521 window_destroy(GTK_WIDGET (fs));
1523 gtk_widget_show(GTK_WIDGET (fs));
1529 * Check that the from file is not the same as to file
1530 * We do it here so we catch all cases ...
1531 * Unfortunately, the file requester gives us an absolute file
1532 * name and the read file name may be relative (if supplied on
1533 * the command line). From Joerg Mayer.
1535 if (files_identical(cfile.filename, cf_name)) {
1536 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1537 "%sCapture file: \"%s\" identical to loaded file!%s\n\n"
1538 "Please choose a different filename.",
1539 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1541 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1542 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1543 * as this will prevent the user from closing the now existing error
1544 * message, simply close the dialog (this is the best we can do here). */
1546 window_destroy(GTK_WIDGET (fs));
1548 gtk_widget_show(GTK_WIDGET (fs));
1553 /* don't show the dialog while saving (or asking) */
1554 gtk_widget_hide(GTK_WIDGET (fs));
1556 /* it the file doesn't exist, simply try to save it */
1557 if (!file_exists(cf_name)) {
1558 file_save_as_cb(NULL, fs);
1563 /* the file exists, ask the user to remove it first */
1564 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
1565 PRIMARY_TEXT_START "A file named \"%s\" already exists."
1566 PRIMARY_TEXT_END "\n\n"
1567 "Do you want to replace it with the capture you are saving?", cf_name);
1568 simple_dialog_set_cb(dialog, file_save_as_exists_answered_cb, fs);
1574 file_save_as_destroy(void)
1577 window_destroy(file_save_as_w);
1581 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1583 /* Note that we no longer have a "Save Capture File As" dialog box. */
1584 file_save_as_w = NULL;
1587 /* Reload a file using the current read and display filters */
1589 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1593 /******************** Color Filters *********************************/
1595 * Keep a static pointer to the current "Color Export" window, if
1596 * any, so that if somebody tries to do "Export"
1597 * while there's already a "Color Export" window up, we just pop
1598 * up the existing one, rather than creating a new one.
1600 static GtkWidget *file_color_import_w;
1602 /* sets the file path to the global color filter file.
1603 WARNING: called by both the import and the export dialog.
1606 color_global_cb(GtkWidget *widget _U_, gpointer data)
1608 GtkWidget *fs_widget = data;
1611 /* decide what file to open (from dfilter code) */
1612 path = get_datafile_path("colorfilters");
1614 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1615 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1617 file_selection_set_current_folder(fs_widget, path);
1619 g_free((gchar *)path);
1622 /* Import color filters */
1624 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
1626 #if GTK_MAJOR_VERSION >= 2 && _WIN32
1627 win32_import_color_file(GDK_WINDOW_HWND(top_level->window), color_filters);
1628 #else /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
1629 GtkWidget *main_vb, *cfglobal_but;
1630 #if GTK_MAJOR_VERSION < 2
1631 GtkAccelGroup *accel_group;
1634 /* No Apply button, and "OK" just sets our text widget, it doesn't
1635 activate it (i.e., it doesn't cause us to try to open the file). */
1637 if (file_color_import_w != NULL) {
1638 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1639 reactivate_window(file_color_import_w);
1643 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
1644 FILE_SELECTION_OPEN);
1646 #if GTK_MAJOR_VERSION < 2
1647 /* Accelerator group for the accelerators (or, as they're called in
1648 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1649 Ctrl+<key> is an accelerator). */
1650 accel_group = gtk_accel_group_new();
1651 gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1654 /* Container for each row of widgets */
1655 main_vb = gtk_vbox_new(FALSE, 3);
1656 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1657 file_selection_set_extra_widget(file_color_import_w, main_vb);
1658 gtk_widget_show(main_vb);
1661 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1662 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1663 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1664 gtk_widget_show(cfglobal_but);
1666 SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1668 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1670 if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1672 file_color_import_ok_cb(file_color_import_w, color_filters);
1674 else window_destroy(file_color_import_w);
1675 #else /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
1676 /* Connect the ok_button to file_open_ok_cb function and pass along a
1677 pointer to the file selection box widget */
1678 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1679 file_color_import_ok_cb, color_filters);
1681 window_set_cancel_button(file_color_import_w,
1682 GTK_FILE_SELECTION(file_color_import_w)->cancel_button, window_cancel_button_cb);
1684 SIGNAL_CONNECT(file_color_import_w, "delete_event", window_delete_event_cb, NULL);
1687 gtk_widget_show(file_color_import_w);
1688 window_present(file_color_import_w);
1689 #endif /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
1690 #endif /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
1694 file_color_import_ok_cb(GtkWidget *w, gpointer color_filters) {
1696 GtkWidget *fs = gtk_widget_get_toplevel(w);
1698 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1699 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1701 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1703 /* Perhaps the user specified a directory instead of a file.
1704 Check whether they did. */
1705 if (test_for_directory(cf_name) == EISDIR) {
1706 /* It's a directory - set the file selection box to display that
1707 directory, don't try to open the directory as a color filter file. */
1708 set_last_open_dir(cf_name);
1710 file_selection_set_current_folder(fs, get_last_open_dir());
1714 /* Try to open the color filter file. */
1716 if (!color_filters_import(cf_name, color_filters)) {
1717 /* We couldn't open it; don't dismiss the open dialog box,
1718 just leave it around so that the user can, after they
1719 dismiss the alert box popped up for the open error,
1725 /* We've crossed the Rubicon; get rid of the file selection box. */
1726 window_destroy(GTK_WIDGET (fs));
1728 /* Save the name of the containing directory specified in the path name,
1729 if any; we can write over cf_name, which is a good thing, given that
1730 "get_dirname()" does write over its argument. */
1731 s = get_dirname(cf_name);
1732 set_last_open_dir(s);
1733 gtk_widget_grab_focus(packet_list);
1739 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1741 /* Note that we no longer have a "Open Capture File" dialog box. */
1742 file_color_import_w = NULL;
1745 static GtkWidget *file_color_export_w;
1747 * Set the "Export only selected filters" toggle button as appropriate for
1748 * the current output file type and count of selected filters.
1750 * Called when the "Export" dialog box is created and when the selected
1754 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
1756 if (file_color_export_w == NULL) {
1757 /* We don't currently have an "Export" dialog box up. */
1761 /* We can request that only the selected filters be saved only if
1762 there *are* selected filters. */
1763 if (color_selected_count() != 0)
1764 gtk_widget_set_sensitive(cfselect_cb, TRUE);
1766 /* Force the "Export only selected filters" toggle to "false", turn
1767 off the flag it controls. */
1768 color_selected = FALSE;
1769 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
1770 gtk_widget_set_sensitive(cfselect_cb, FALSE);
1775 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
1777 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1781 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
1783 #if GTK_MAJOR_VERSION >= 2 && _WIN32
1784 win32_export_color_file(GDK_WINDOW_HWND(top_level->window), filter_list);
1785 #else /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
1786 GtkWidget *main_vb, *cfglobal_but;
1788 if (file_color_export_w != NULL) {
1789 /* There's already an "Color Filter Export" dialog box; reactivate it. */
1790 reactivate_window(file_color_export_w);
1794 /* Default to saving all packets, in the file's current format. */
1795 color_selected = FALSE;
1796 filetype = cfile.cd_t;
1798 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
1799 FILE_SELECTION_SAVE);
1801 /* Container for each row of widgets */
1802 main_vb = gtk_vbox_new(FALSE, 3);
1803 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1804 file_selection_set_extra_widget(file_color_export_w, main_vb);
1805 gtk_widget_show(main_vb);
1807 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
1808 gtk_container_add(GTK_CONTAINER(main_vb), cfselect_cb);
1809 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
1810 SIGNAL_CONNECT(cfselect_cb, "toggled", color_toggle_selected_cb, NULL);
1811 gtk_widget_show(cfselect_cb);
1812 color_set_export_selected_sensitive(cfselect_cb);
1814 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1815 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1816 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1817 gtk_widget_show(cfglobal_but);
1819 SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1821 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1822 if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1824 file_color_export_ok_cb(file_color_export_w, filter_list);
1826 else window_destroy(file_color_export_w);
1827 #else /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
1828 /* Connect the ok_button to file_export_ok_cb function and pass along a
1829 pointer to the file selection box widget */
1830 SIGNAL_CONNECT(GTK_FILE_SELECTION (file_color_export_w)->ok_button, "clicked",
1831 file_color_export_ok_cb, filter_list);
1833 window_set_cancel_button(file_color_export_w,
1834 GTK_FILE_SELECTION(file_color_export_w)->cancel_button, window_cancel_button_cb);
1836 SIGNAL_CONNECT(file_color_export_w, "delete_event", window_delete_event_cb, NULL);
1839 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1841 gtk_widget_show(file_color_export_w);
1842 window_present(file_color_export_w);
1843 #endif /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
1844 #endif /* GTK_MAJOR_VERSION >= 2 && _WIN32 */
1848 file_color_export_ok_cb(GtkWidget *w, gpointer filter_list) {
1851 GtkWidget *fs = gtk_widget_get_toplevel(w);
1853 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1854 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1856 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1859 /* Perhaps the user specified a directory instead of a file.
1860 Check whether they did. */
1861 if (test_for_directory(cf_name) == EISDIR) {
1862 /* It's a directory - set the file selection box to display that
1863 directory, and leave the selection box displayed. */
1864 set_last_open_dir(cf_name);
1866 file_selection_set_current_folder(fs, get_last_open_dir());
1870 /* Write out the filters (all, or only the ones that are currently
1871 displayed or selected) to the file with the specified name. */
1873 if (!color_filters_export(cf_name, filter_list, color_selected))
1875 /* The write failed; don't dismiss the open dialog box,
1876 just leave it around so that the user can, after they
1877 dismiss the alert box popped up for the error, try again. */
1883 /* The write succeeded; get rid of the file selection box. */
1884 window_destroy(GTK_WIDGET (fs));
1886 /* Save the directory name for future file dialogs. */
1887 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1888 set_last_open_dir(dirname);
1893 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1895 file_color_export_w = NULL;