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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 #include "packet-range.h"
38 #include <epan/filesystem.h>
39 #include <epan/addr_resolv.h>
40 #include <epan/prefs.h>
42 #include "../globals.h"
44 #include "../color_filters.h"
47 #include <wsutil/file_util.h>
49 #include "ui/alert_box.h"
50 #include "ui/recent.h"
51 #include "ui/simple_dialog.h"
52 #include "ui/ui_util.h"
54 #include "ui/gtk/gtkglobals.h"
55 #include "ui/gtk/keys.h"
56 #include "ui/gtk/filter_dlg.h"
57 #include "ui/gtk/gui_utils.h"
58 #include "ui/gtk/dlg_utils.h"
59 #include "ui/gtk/file_dlg.h"
60 #include "ui/gtk/capture_file_dlg.h"
61 #include "ui/gtk/drag_and_drop.h"
62 #include "ui/gtk/main.h"
63 #include "ui/gtk/color_dlg.h"
64 #include "ui/gtk/new_packet_list.h"
66 #include "ui/gtk/capture_dlg.h"
68 #include "ui/gtk/stock_icons.h"
69 #include "ui/gtk/range_utils.h"
70 #include "ui/gtk/filter_autocomplete.h"
73 #define USE_WIN32_FILE_DIALOGS
76 #ifdef USE_WIN32_FILE_DIALOGS
77 #include <gdk/gdkwin32.h>
79 #include "ui/win32/file_dlg_win32.h"
82 static void do_file_save(capture_file *cf, gboolean dont_reopen);
83 static void do_file_save_as(capture_file *cf, gboolean must_support_comments,
84 gboolean dont_reopen);
85 static cf_write_status_t file_save_as_cb(GtkWidget *fs,
86 gboolean discard_comments,
87 gboolean dont_reopen);
88 static void file_select_file_type_cb(GtkWidget *w, gpointer data);
89 static cf_write_status_t file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range);
90 static int set_file_type_list(GtkWidget *combo_box, capture_file *cf,
91 gboolean must_support_comments);
93 #define E_FILE_TYPE_COMBO_BOX_KEY "file_type_combo_box"
94 #define E_COMPRESSED_CB_KEY "compressed_cb"
96 #define PREVIEW_TABLE_KEY "preview_table_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"
103 /* XXX - can we make these not be static? */
104 static gboolean color_selected;
106 #define PREVIEW_STR_MAX 200
109 /* set a new filename for the preview widget */
111 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
117 gchar string_buff[PREVIEW_STR_MAX];
121 /* init preview labels */
122 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
123 gtk_label_set_text(GTK_LABEL(label), "-");
124 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
125 gtk_label_set_text(GTK_LABEL(label), "-");
126 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
127 gtk_label_set_text(GTK_LABEL(label), "-");
128 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
129 gtk_label_set_text(GTK_LABEL(label), "-");
130 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
131 gtk_label_set_text(GTK_LABEL(label), "-");
137 if (test_for_directory(cf_name) == EISDIR) {
138 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
139 gtk_label_set_text(GTK_LABEL(label), "directory");
143 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
145 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
146 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
147 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
149 gtk_label_set_text(GTK_LABEL(label), "error opening file");
154 /* Find the size of the file. */
155 filesize = wtap_file_size(wth, &err);
156 if (filesize == -1) {
157 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
161 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize);
162 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
163 gtk_label_set_text(GTK_LABEL(label), string_buff);
166 g_strlcpy(string_buff, wtap_file_type_string(wtap_file_type(wth)), PREVIEW_STR_MAX);
167 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
168 gtk_label_set_text(GTK_LABEL(label), string_buff);
174 /* do a preview run on the currently selected capture file */
176 preview_do(GtkWidget *prev, wtap *wth)
179 unsigned int elapsed_time;
185 const struct wtap_pkthdr *phdr;
186 double start_time = 0; /* seconds, with nsec resolution */
187 double stop_time = 0; /* seconds, with nsec resolution */
189 unsigned int packets = 0;
190 gboolean is_breaked = FALSE;
191 gchar string_buff[PREVIEW_STR_MAX];
197 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
198 phdr = wtap_phdr(wth);
199 cur_time = wtap_nstime_to_sec(&phdr->ts);
201 start_time = cur_time;
202 stop_time = cur_time;
204 if (cur_time < start_time) {
205 start_time = cur_time;
207 if (cur_time > stop_time){
208 stop_time = cur_time;
212 if(packets%1000 == 0) {
213 /* do we have a timeout? */
215 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
223 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
224 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
225 gtk_label_set_text(GTK_LABEL(label), string_buff);
232 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
234 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
236 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
237 gtk_label_set_text(GTK_LABEL(label), string_buff);
240 ti_time = (long)start_time;
241 ti_tm = localtime( &ti_time );
243 g_snprintf(string_buff, PREVIEW_STR_MAX,
244 "%04d-%02d-%02d %02d:%02d:%02d",
245 ti_tm->tm_year + 1900,
252 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
254 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
255 gtk_label_set_text(GTK_LABEL(label), string_buff);
258 elapsed_time = (unsigned int)(stop_time-start_time);
259 if(elapsed_time/86400) {
260 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
261 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
263 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
264 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
267 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
269 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
270 gtk_label_set_text(GTK_LABEL(label), string_buff);
276 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
277 simply use the same layout as in GTK2.0 */
279 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
281 GtkWidget *prev = GTK_WIDGET (data);
283 gboolean have_preview;
285 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
287 have_preview = preview_set_filename(prev, cf_name);
292 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
297 /* the filename text entry changed */
299 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
301 GtkWidget *prev = (GtkWidget *)g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY);
303 gboolean have_preview;
306 /* get the filename */
307 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
309 /* set the filename to the preview */
310 wth = preview_set_filename(prev, cf_name);
311 have_preview = (wth != NULL);
315 /* make the preview widget sensitive */
316 gtk_widget_set_sensitive(prev, have_preview);
319 * XXX - if the Open button isn't sensitive, you can't type into
320 * the location bar and select the file or directory you've typed.
323 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1791
325 * It's not as if allowing users to click Open when they've
326 * selected a file that's not a valid capture file will cause
327 * anything worse than an error dialog, so we'll leave the Open
328 * button sensitive for now. Perhaps making it sensitive if
329 * cf_name is NULL would also work, although I don't know whether
330 * there are any cases where it would be non-null when you've
331 * typed in the location bar.
333 * XXX - Bug 1791 also notes that, with the line removed, Bill
334 * Meier "somehow managed to get the file chooser window somewhat
335 * wedged in that neither the cancel or open buttons were responsive".
336 * That seems a bit odd, given that, without this line, we're not
337 * monkeying with the Open button's sensitivity, but...
340 /* make the open/save/... dialog button sensitive */
342 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
345 /* do the actual preview */
347 preview_do(prev, wth);
351 /* copied from summary_dlg.c */
353 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
358 if(strlen(value) != 0) {
359 indent = g_strdup_printf(" %s", title);
361 indent = g_strdup(title);
363 label = gtk_label_new(indent);
365 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
366 gtk_widget_set_sensitive(label, sensitive);
367 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
369 label = gtk_label_new(value);
370 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
371 gtk_widget_set_sensitive(label, sensitive);
372 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
380 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
382 return add_string_to_table_sensitive(list, row, title, value, TRUE);
390 GtkWidget *table, *label;
393 table = gtk_table_new(1, 2, FALSE);
394 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
395 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
398 label = add_string_to_table(table, &row, "Format:", "-");
399 g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label);
400 label = add_string_to_table(table, &row, "Size:", "-");
401 g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label);
402 label = add_string_to_table(table, &row, "Packets:", "-");
403 g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label);
404 label = add_string_to_table(table, &row, "First Packet:", "-");
405 g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label);
406 label = add_string_to_table(table, &row, "Elapsed time:", "-");
407 g_object_set_data(G_OBJECT(table), PREVIEW_ELAPSED_KEY, label);
412 #ifndef USE_WIN32_FILE_DIALOGS
415 gtk_open_file(GtkWidget *w, GString *file_name, GString *display_filter)
417 GtkWidget *file_open_w;
418 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
419 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *e_resolv_cb, *prev;
420 /* No Apply button, and "OK" just sets our text widget, it doesn't
421 activate it (i.e., it doesn't cause us to try to open the file). */
422 static construct_args_t args = {
423 "Wireshark: Display Filter",
430 if (!file_name || !display_filter)
433 file_open_w = file_selection_new("Wireshark: Open Capture File",
434 FILE_SELECTION_OPEN);
435 /* it's annoying, that the file chooser dialog is already shown here,
436 so we cannot use the correct gtk_window_set_default_size() to resize it */
437 gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT);
439 if (file_name->len > 0) {
440 gchar *dirname = g_path_get_dirname(file_name->str);
442 file_selection_set_current_folder(file_open_w, dirname);
445 switch (prefs.gui_fileopen_style) {
447 case FO_STYLE_LAST_OPENED:
448 /* The user has specified that we should start out in the last directory
449 we looked in. If we've already opened a file, use its containing
450 directory, if we could determine it, as the directory, otherwise
451 use the "last opened" directory saved in the preferences file if
453 /* This is now the default behaviour in file_selection_new() */
456 case FO_STYLE_SPECIFIED:
457 /* The user has specified that we should always start out in a
458 specified directory; if they've specified that directory,
459 start out by showing the files in that dir. */
460 if (prefs.gui_fileopen_dir[0] != '\0')
461 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
466 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
467 file_selection_set_extra_widget(file_open_w, main_hb);
468 gtk_widget_show(main_hb);
470 /* Container for each row of widgets */
471 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
472 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
473 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
474 gtk_widget_show(main_vb);
477 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
478 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
479 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
480 gtk_widget_show(filter_hbox);
482 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
483 g_signal_connect(filter_bt, "clicked",
484 G_CALLBACK(display_filter_construct_cb), &args);
485 g_signal_connect(filter_bt, "destroy",
486 G_CALLBACK(filter_button_destroy_cb), NULL);
487 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
488 gtk_widget_show(filter_bt);
489 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
491 filter_te = gtk_entry_new();
492 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
493 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
494 g_signal_connect(filter_te, "changed",
495 G_CALLBACK(filter_te_syntax_check_cb), NULL);
496 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
497 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
498 g_signal_connect(file_open_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
499 colorize_filter_te_as_empty(filter_te);
500 gtk_entry_set_text(GTK_ENTRY(filter_te), display_filter->str);
501 gtk_widget_show(filter_te);
502 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
504 g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te);
506 /* resolve buttons */
507 m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution");
508 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
509 gbl_resolv_flags.mac_name);
510 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
511 gtk_widget_show(m_resolv_cb);
513 t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution");
514 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
515 gbl_resolv_flags.transport_name);
516 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
517 gtk_widget_show(t_resolv_cb);
519 n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution");
520 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
521 gbl_resolv_flags.network_name);
522 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
523 gtk_widget_show(n_resolv_cb);
525 e_resolv_cb = gtk_check_button_new_with_mnemonic("Use _external network name resolver");
526 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e_resolv_cb),
527 gbl_resolv_flags.use_external_net_name_resolver);
528 gtk_box_pack_start(GTK_BOX(main_vb), e_resolv_cb, FALSE, FALSE, 0);
529 gtk_widget_show(e_resolv_cb);
532 prev = preview_new();
533 g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev);
534 gtk_widget_show_all(prev);
535 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
537 g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
538 G_CALLBACK(file_open_entry_changed), file_open_w);
539 file_open_entry_changed(file_open_w, file_open_w);
541 g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY,
542 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
544 cf_name = file_selection_run(file_open_w);
545 if (cf_name == NULL) {
546 /* User cancelled or closed the dialog. */
550 g_string_printf(file_name, "%s", cf_name);
552 g_string_printf(display_filter, "%s", gtk_entry_get_text(GTK_ENTRY(filter_te)));
554 /* Set the global resolving variable */
555 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_resolv_cb)))
556 gbl_resolv_flags.mac_name = TRUE;
558 gbl_resolv_flags.mac_name = FALSE;
559 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(n_resolv_cb)))
560 gbl_resolv_flags.network_name = TRUE;
562 gbl_resolv_flags.network_name = FALSE;
563 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t_resolv_cb)))
564 gbl_resolv_flags.transport_name = TRUE;
566 gbl_resolv_flags.transport_name = FALSE;
567 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(e_resolv_cb)))
568 gbl_resolv_flags.use_external_net_name_resolver = TRUE;
570 gbl_resolv_flags.use_external_net_name_resolver = FALSE;
572 /* We've crossed the Rubicon; get rid of the file selection box. */
573 window_destroy(GTK_WIDGET(file_open_w));
577 #endif /* USE_WIN32_FILE_DIALOGS */
582 * <platform/>_open_file routines should upon entry...
583 * Set the path and fill in the filename if the path+filename is provided.
584 * Set the display filter if provided. Filter syntax should be checked.
585 * Set the name resolution check boxes to match the global settings.
586 * ...and upon exit...
587 * Return TRUE on "OK" and "FALSE" on "Cancel".
588 * Set the global name resolution preferences on "OK".
593 file_open_cmd(GtkWidget *w _U_)
595 GString *file_name = g_string_new("");
596 GString *display_filter = g_string_new("");
597 dfilter_t *rfcode = NULL;
601 * Loop until the user either selects a file or gives up.
604 #ifdef USE_WIN32_FILE_DIALOGS
605 if (win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), file_name, display_filter)) {
606 #else /* USE_WIN32_FILE_DIALOGS */
607 if (gtk_open_file(w, file_name, display_filter)) {
608 #endif /* USE_WIN32_FILE_DIALOGS */
610 /* apply our filter */
611 if (dfilter_compile(display_filter->str, &rfcode)) {
612 cf_set_rfcode(&cfile, rfcode);
614 /* Not valid. Tell the user, and go back and run the file
615 selection box again once they dismiss the alert. */
616 bad_dfilter_alert_box(top_level, display_filter->str);
620 /* Try to open the capture file. */
621 if (cf_open(&cfile, file_name->str, FALSE, &err) != CF_OK) {
622 /* We couldn't open it; don't dismiss the open dialog box,
623 just leave it around so that the user can, after they
624 dismiss the alert box popped up for the open error,
627 dfilter_free(rfcode);
632 switch (cf_read(&cfile, FALSE)) {
636 /* Just because we got an error, that doesn't mean we were unable
637 to read any of the file; we handle what we could get from the
641 case CF_READ_ABORTED:
642 /* The user bailed out of re-reading the capture file; the
643 capture file has been closed - just free the capture file name
644 string and return (without changing the last containing
646 g_string_free(file_name, TRUE);
647 g_string_free(display_filter, TRUE);
650 /* Save the name of the containing directory specified in the path name,
651 if any; we can write over cf_name, which is a good thing, given that
652 "get_dirname()" does write over its argument. */
653 set_last_open_dir(get_dirname(file_name->str));
654 gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), display_filter->str);
656 g_string_free(file_name, TRUE);
657 g_string_free(display_filter, TRUE);
663 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
664 /* If there's unsaved data, let the user save it first.
665 If they cancel out of it, don't quit. */
666 if (do_file_close(&cfile, FALSE, " before opening a new capture file"))
667 file_open_cmd(widget);
670 /* Merge existing with another file */
672 file_merge_cmd(GtkWidget *w)
674 #ifdef USE_WIN32_FILE_DIALOGS
675 win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
676 new_packet_list_freeze();
677 new_packet_list_thaw();
678 #else /* USE_WIN32_FILE_DIALOGS */
679 GtkWidget *file_merge_w;
680 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
681 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
684 /* No Apply button, and "OK" just sets our text widget, it doesn't
685 activate it (i.e., it doesn't cause us to try to open the file). */
686 static construct_args_t args = {
687 "Wireshark: Read Filter",
693 const gchar *rfilter;
694 dfilter_t *rfcode = NULL;
698 cf_status_t merge_status;
699 char *in_filenames[2];
702 /* Default to saving all packets, in the file's current format. */
704 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
705 FILE_SELECTION_OPEN);
706 /* it's annoying, that the file chooser dialog is already shown here,
707 so we cannot use the correct gtk_window_set_default_size() to resize it */
708 gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
710 switch (prefs.gui_fileopen_style) {
712 case FO_STYLE_LAST_OPENED:
713 /* The user has specified that we should start out in the last directory
714 we looked in. If we've already opened a file, use its containing
715 directory, if we could determine it, as the directory, otherwise
716 use the "last opened" directory saved in the preferences file if
718 /* This is now the default behaviour in file_selection_new() */
721 case FO_STYLE_SPECIFIED:
722 /* The user has specified that we should always start out in a
723 specified directory; if they've specified that directory,
724 start out by showing the files in that dir. */
725 if (prefs.gui_fileopen_dir[0] != '\0')
726 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
730 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
731 file_selection_set_extra_widget(file_merge_w, main_hb);
732 gtk_widget_show(main_hb);
734 /* Container for each row of widgets */
735 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
736 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
737 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
738 gtk_widget_show(main_vb);
741 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
742 gtk_box_pack_start(GTK_BOX (main_vb), ft_hb, TRUE, TRUE, 0);
743 gtk_widget_show(ft_hb);
745 ft_lb = gtk_label_new("Merged output file type:");
746 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
747 gtk_widget_show(ft_lb);
749 ft_combo_box = ws_combo_box_new_text_and_pointer();
751 /* Generate the list of file types we can save. */
752 set_file_type_list(ft_combo_box, &cfile, FALSE);
753 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
754 gtk_widget_show(ft_combo_box);
755 g_object_set_data(G_OBJECT(file_merge_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
756 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
758 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
759 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
760 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
761 gtk_widget_show(filter_hbox);
763 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
764 g_signal_connect(filter_bt, "clicked",
765 G_CALLBACK(display_filter_construct_cb), &args);
766 g_signal_connect(filter_bt, "destroy",
767 G_CALLBACK(filter_button_destroy_cb), NULL);
768 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
769 gtk_widget_show(filter_bt);
770 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
772 filter_te = gtk_entry_new();
773 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
774 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
775 g_signal_connect(filter_te, "changed",
776 G_CALLBACK(filter_te_syntax_check_cb), NULL);
777 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
778 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
779 g_signal_connect(file_merge_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
780 colorize_filter_te_as_empty(filter_te);
781 gtk_widget_show(filter_te);
782 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
784 g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te);
786 prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL,
787 "Prepend packets to existing file");
788 gtk_widget_set_tooltip_text(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.");
789 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
790 gtk_widget_show(prepend_rb);
792 chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically");
793 gtk_widget_set_tooltip_text(chrono_rb, "The resulting file contains all the packets from the currently loaded and the selected file, sorted by the packet timestamps.");
794 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
795 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
796 gtk_widget_show(chrono_rb);
798 append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file");
799 gtk_widget_set_tooltip_text(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.");
800 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
801 gtk_widget_show(append_rb);
804 prev = preview_new();
805 g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev);
806 gtk_widget_show_all(prev);
807 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
809 g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
810 G_CALLBACK(file_open_entry_changed), file_merge_w);
811 file_open_entry_changed(file_merge_w, file_merge_w);
813 g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY,
814 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
817 * Loop until the user either selects a file or gives up.
820 cf_name = file_selection_run(file_merge_w);
821 if (cf_name == NULL) {
822 /* User cancelled or closed the dialog. */
826 /* Get the specified read filter and try to compile it. */
827 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
828 if (!dfilter_compile(rfilter, &rfcode)) {
829 /* Not valid. Tell the user, and go back and run the file
830 selection box again once they dismiss the alert. */
831 bad_dfilter_alert_box(file_merge_w, rfilter);
836 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
837 g_assert_not_reached(); /* Programming error: somehow nothing is active */
839 file_type = GPOINTER_TO_INT(ptr);
841 /* Try to merge or append the two files */
843 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(chrono_rb))) {
844 /* chronological order */
845 in_filenames[0] = cfile.filename;
846 in_filenames[1] = cf_name;
847 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
848 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prepend_rb))) {
850 in_filenames[0] = cf_name;
851 in_filenames[1] = cfile.filename;
852 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
856 in_filenames[0] = cfile.filename;
857 in_filenames[1] = cf_name;
858 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
864 if (merge_status != CF_OK) {
866 dfilter_free(rfcode);
873 /* We've crossed the Rubicon; get rid of the file selection box. */
874 window_destroy(GTK_WIDGET(file_merge_w));
876 /* Try to open the merged capture file. */
877 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
878 /* We couldn't open it; fail. */
880 dfilter_free(rfcode);
886 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
887 it closed the previous capture file, and thus destroyed any
888 previous read filter attached to "cf"). */
889 cfile.rfcode = rfcode;
891 switch (cf_read(&cfile, FALSE)) {
895 /* Just because we got an error, that doesn't mean we were unable
896 to read any of the file; we handle what we could get from the
900 case CF_READ_ABORTED:
901 /* The user bailed out of re-reading the capture file; the
902 capture file has been closed - just free the capture file name
903 string and return (without changing the last containing
908 /* Save the name of the containing directory specified in the path name,
909 if any; we can write over cf_merged_name, which is a good thing, given that
910 "get_dirname()" does write over its argument. */
911 s = get_dirname(tmpname);
912 set_last_open_dir(s);
915 #endif /* USE_WIN32_FILE_DIALOGS */
919 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
920 /* If there's unsaved data, let the user save it first.
921 If they cancel out of it, don't merge. */
922 GtkWidget *msg_dialog;
923 gchar *display_basename;
926 if (prefs.gui_ask_unsaved) {
927 if (cfile.is_tempfile || cfile.unsaved_changes) {
928 /* This is a temporary capture file or has unsaved changes; ask the
929 user whether to save the capture. */
930 if (cfile.is_tempfile) {
931 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
932 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
933 GTK_MESSAGE_QUESTION,
935 "Do you want to save the captured packets before merging another capture file into it?");
937 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
938 "A temporary capture file can't be merged.");
941 * Format the message.
943 display_basename = g_filename_display_basename(cfile.filename);
944 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
945 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
946 GTK_MESSAGE_QUESTION,
948 "Do you want to save the changes you've made "
949 "to the capture file \"%s\" before merging another capture file into it?",
951 g_free(display_basename);
952 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
953 "The changes must be saved before the files are merged.");
957 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
958 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
959 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
960 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
962 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
963 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
964 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
965 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
967 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
969 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
970 gtk_widget_destroy(msg_dialog);
974 case GTK_RESPONSE_ACCEPT:
975 /* Save the file but don't close it */
976 do_file_save(&cfile, FALSE);
979 case GTK_RESPONSE_CANCEL:
980 case GTK_RESPONSE_NONE:
981 case GTK_RESPONSE_DELETE_EVENT:
983 /* Don't do the merge. */
990 file_merge_cmd(widget);
995 do_capture_stop(capture_file *cf)
997 /* Stop the capture (complete with UI updates). */
998 capture_stop_cb(NULL, NULL);
1000 /* Now run the main loop until the capture stops and we finish
1001 reading it; we need to run the main loop so we respond to
1002 messages on the sync pipe and the sync pipe being closed. */
1003 while (cf->state == FILE_READ_IN_PROGRESS)
1004 gtk_main_iteration();
1009 do_file_close(capture_file *cf, gboolean from_quit, const char *before_what)
1011 GtkWidget *msg_dialog;
1012 gchar *display_basename;
1014 gboolean capture_in_progress;
1016 if (cf->state == FILE_CLOSED)
1017 return TRUE; /* already closed, nothing to do */
1020 if (cf->state == FILE_READ_IN_PROGRESS) {
1021 /* This is true if we're reading a capture file *or* if we're doing
1022 a live capture. If we're reading a capture file, the main loop
1023 is busy reading packets, and only accepting input from the
1024 progress dialog, so we can't get here, so this means we're
1026 capture_in_progress = TRUE;
1029 capture_in_progress = FALSE;
1031 if (prefs.gui_ask_unsaved) {
1032 if (cf->is_tempfile || capture_in_progress || cf->unsaved_changes) {
1033 /* This is a temporary capture file, or there's a capture in
1034 progress, or the file has unsaved changes; ask the user whether
1035 to save the data. */
1036 if (cf->is_tempfile) {
1037 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1038 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1039 GTK_MESSAGE_QUESTION,
1041 capture_in_progress ?
1042 "Do you want to stop the capture and save the captured packets%s?" :
1043 "Do you want to save the captured packets%s?",
1046 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1047 "Your captured packets will be lost if you don't save them.");
1050 * Format the message.
1052 display_basename = g_filename_display_basename(cf->filename);
1053 if (capture_in_progress) {
1054 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1055 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1056 GTK_MESSAGE_QUESTION,
1058 "Do you want to stop the capture and save the captured packets%s?",
1061 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1062 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1063 GTK_MESSAGE_QUESTION,
1065 "Do you want to save the changes you've made "
1066 "to the capture file \"%s\"%s?",
1067 display_basename, before_what);
1069 g_free(display_basename);
1070 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1071 capture_in_progress ?
1072 "Your captured packets will be lost if you don't save them." :
1073 "Your changes will be lost if you don't save them.");
1077 /* If this is from a Quit operation, use "quit and don't save"
1078 rather than just "don't save". */
1079 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1081 (cf->state == FILE_READ_IN_PROGRESS ?
1082 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1083 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1084 (capture_in_progress ?
1085 WIRESHARK_STOCK_STOP_DONT_SAVE :
1086 WIRESHARK_STOCK_DONT_SAVE)),
1087 GTK_RESPONSE_REJECT);
1088 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1089 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1090 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1091 (capture_in_progress ?
1092 WIRESHARK_STOCK_STOP_SAVE :
1094 GTK_RESPONSE_ACCEPT);
1096 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1097 (capture_in_progress ?
1098 WIRESHARK_STOCK_STOP_SAVE :
1100 GTK_RESPONSE_ACCEPT);
1101 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1102 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1103 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1105 (capture_in_progress ?
1106 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1107 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1108 (capture_in_progress ?
1109 WIRESHARK_STOCK_STOP_DONT_SAVE :
1110 WIRESHARK_STOCK_DONT_SAVE)),
1111 GTK_RESPONSE_REJECT);
1113 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
1115 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1116 gtk_widget_destroy(msg_dialog);
1120 case GTK_RESPONSE_ACCEPT:
1122 /* If there's a capture in progress, we have to stop the capture
1123 and then do the save. */
1124 if (capture_in_progress)
1125 do_capture_stop(cf);
1127 /* Save the file and close it */
1128 do_file_save(cf, TRUE);
1131 case GTK_RESPONSE_REJECT:
1133 /* If there's a capture in progress; we have to stop the capture
1134 and then do the close. */
1135 if (capture_in_progress)
1136 do_capture_stop(cf);
1138 /* Just close the file, discarding changes */
1142 case GTK_RESPONSE_CANCEL:
1143 case GTK_RESPONSE_NONE:
1144 case GTK_RESPONSE_DELETE_EVENT:
1146 /* Don't close the file (and don't stop any capture in progress). */
1147 return FALSE; /* file not closed */
1151 /* unchanged file, just close it */
1155 /* User asked not to be bothered by those prompts, just close it.
1156 XXX - should that apply only to saving temporary files? */
1158 /* If there's a capture in progress, we have to stop the capture
1159 and then do the close. */
1160 if (capture_in_progress)
1161 do_capture_stop(cf);
1165 return TRUE; /* file closed */
1170 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1171 do_file_close(&cfile, FALSE, "");
1176 SAVE_WITHOUT_COMMENTS,
1177 SAVE_IN_ANOTHER_FORMAT,
1179 } check_savability_t;
1181 #define RESPONSE_DISCARD_COMMENTS_AND_SAVE 1
1182 #define RESPONSE_SAVE_IN_ANOTHER_FORMAT 2
1184 static check_savability_t
1185 check_save_with_comments(capture_file *cf)
1187 GtkWidget *msg_dialog;
1190 /* Do we have any comments? */
1191 if (!cf_has_comments(cf)) {
1192 /* No. Let the save happen; no comments to delete. */
1196 /* OK, we have comments. Can we write them out in the file's format?
1198 XXX - for now, we "know" that pcap-ng is the only format for which
1199 we support comments. We should really ask Wiretap what the
1200 format in question supports (and handle different types of
1201 comments, some but not all of which some file formats might
1203 if (cf->cd_t == WTAP_FILE_PCAPNG) {
1204 /* Yes - the file is a pcap-ng file. Let the save happen; we can
1205 save the comments, so no need to delete them. */
1209 /* Is pcap-ng one of the formats in which we can write this file? */
1210 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, cf->linktypes)) {
1211 /* Yes. Ooffer the user a choice of "Save in a format that
1212 supports comments", "Discard comments and save in the
1213 file's own format", or "Cancel", meaning "don't bother
1214 saving the file at all". */
1215 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1216 GTK_DIALOG_DESTROY_WITH_PARENT,
1217 GTK_MESSAGE_QUESTION,
1219 "The capture has comments, but the file's format "
1220 "doesn't support comments. Do you want to save the capture "
1221 "in a format that supports comments, or discard the comments "
1222 "and save in the file's format?");
1224 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1225 "Discard comments and save",
1226 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1228 GTK_RESPONSE_CANCEL,
1229 "Save in another format",
1230 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1233 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1234 "Save in another format",
1235 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1237 GTK_RESPONSE_CANCEL,
1238 "Discard comments and save",
1239 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1242 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1243 RESPONSE_SAVE_IN_ANOTHER_FORMAT);
1245 /* No. Offer the user a choice of "Discard comments and
1246 save in the file's format" or "Cancel". */
1247 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1248 GTK_DIALOG_DESTROY_WITH_PARENT,
1249 GTK_MESSAGE_QUESTION,
1251 "The capture has comments, but no file format in which it "
1252 "can be saved supports comments. Do you want to discard "
1253 "the comments and save in the file's format?");
1255 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1256 "Discard comments and save",
1257 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1259 GTK_RESPONSE_CANCEL,
1262 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1264 GTK_RESPONSE_CANCEL,
1265 "Discard comments and save",
1266 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1269 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1270 GTK_RESPONSE_CANCEL);
1273 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1274 gtk_widget_destroy(msg_dialog);
1278 case RESPONSE_SAVE_IN_ANOTHER_FORMAT:
1279 /* Let the user select another format. */
1280 return SAVE_IN_ANOTHER_FORMAT;
1282 case RESPONSE_DISCARD_COMMENTS_AND_SAVE:
1283 /* Save without the comments and, if that succeeds, delete the
1285 return SAVE_WITHOUT_COMMENTS;
1287 case GTK_RESPONSE_CANCEL:
1288 case GTK_RESPONSE_NONE:
1289 case GTK_RESPONSE_DELETE_EVENT:
1297 * Save the capture file in question, prompting the user for a file
1298 * name to save to if necessary.
1301 do_file_save(capture_file *cf, gboolean dont_reopen)
1304 gboolean discard_comments;
1305 cf_write_status_t status;
1307 if (cf->is_tempfile) {
1308 /* This is a temporary capture file, so saving it means saving
1309 it to a permanent file. Prompt the user for a location
1310 to which to save it. Don't require that the file format
1311 support comments - if it's a temporary capture file, it's
1312 probably pcap-ng, which supports comments and, if it's
1313 not pcap-ng, let the user decide what they want to do
1314 if they've added comments. */
1315 do_file_save_as(cf, FALSE, dont_reopen);
1317 if (cf->unsaved_changes) {
1318 /* This is not a temporary capture file, but it has unsaved
1319 changes, so saving it means doing a "safe save" on top
1320 of the existing file, in the same format - no UI needed
1321 unless the file has comments and the file's format doesn't
1324 If the file has comments, does the file's format support them?
1325 If not, ask the user whether they want to discard the comments
1326 or choose a different format. */
1327 switch (check_save_with_comments(cf)) {
1330 /* The file can be saved in the specified format as is;
1331 just drive on and save in the format they selected. */
1332 discard_comments = FALSE;
1335 case SAVE_WITHOUT_COMMENTS:
1336 /* The file can't be saved in the specified format as is,
1337 but it can be saved without the comments, and the user
1338 said "OK, discard the comments", so save it in the
1339 format they specified without the comments. */
1340 discard_comments = TRUE;
1343 case SAVE_IN_ANOTHER_FORMAT:
1344 /* There are file formats in which we can save this that
1345 support comments, and the user said not to delete the
1346 comments. Do a "Save As" so the user can select
1347 one of those formats and choose a file name. */
1348 do_file_save_as(cf, TRUE, dont_reopen);
1352 /* The user said "forget it". Just return. */
1356 /* Squelch warnings that discard_comments is being used
1358 g_assert_not_reached();
1362 /* XXX - cf->filename might get freed out from under us, because
1363 the code path through which cf_save_packets() goes currently
1364 closes the current file and then opens and reloads the saved file,
1365 so make a copy and free it later. */
1366 fname = g_strdup(cf->filename);
1367 status = cf_save_packets(cf, fname, cf->cd_t, cf->iscompressed,
1368 discard_comments, dont_reopen);
1372 /* The save succeeded; we're done.
1373 If we discarded comments, redraw the packet list to reflect
1374 any packets that no longer have comments. */
1375 if (discard_comments)
1376 new_packet_list_queue_draw();
1379 case CF_WRITE_ERROR:
1380 /* The write failed.
1381 XXX - OK, what do we do now? Let them try a
1382 "Save As", in case they want to try to save to a
1383 different directory r file system? */
1386 case CF_WRITE_ABORTED:
1387 /* The write was aborted; just drive on. */
1392 /* Otherwise just do nothing. */
1397 file_save_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1398 do_file_save(&cfile, FALSE);
1401 /* Attach a list of the valid 'save as' file types to a combo_box by
1402 checking what Wiretap supports. Make the default type the first
1403 in the list. If must_supprt_comments is true, restrict the list
1404 to those formats that support comments (currently, just pcap-ng).
1406 Returns the default file type. */
1408 set_file_type_list(GtkWidget *combo_box, capture_file *cf,
1409 gboolean must_support_comments)
1411 GArray *savable_file_types;
1414 int default_ft = -1;
1416 savable_file_types = wtap_get_savable_file_types(cf->cd_t, cf->linktypes);
1418 if (savable_file_types != NULL) {
1419 /* OK, we have at least one file type we can save this file as.
1420 (If we didn't, we shouldn't have gotten here in the first
1421 place.) Add them all to the combo box. */
1422 for (i = 0; i < savable_file_types->len; i++) {
1423 ft = g_array_index(savable_file_types, int, i);
1424 if (must_support_comments) {
1425 if (ft != WTAP_FILE_PCAPNG)
1428 if (default_ft == -1)
1429 default_ft = ft; /* first file type is the default */
1430 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(combo_box),
1431 wtap_file_type_string(ft),
1432 GINT_TO_POINTER(ft));
1434 g_array_free(savable_file_types, TRUE);
1441 file_select_file_type_cb(GtkWidget *w, gpointer parent_arg)
1443 GtkWidget *parent = parent_arg;
1446 GtkWidget *compressed_cb;
1448 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(parent), E_COMPRESSED_CB_KEY);
1449 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr)) {
1450 /* XXX - this can happen when we clear the list of file types
1451 and then reconstruct it. */
1452 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1453 gtk_widget_set_sensitive(compressed_cb, FALSE);
1456 new_file_type = GPOINTER_TO_INT(ptr);
1458 if (!wtap_dump_can_compress(new_file_type)) {
1459 /* Can't compress this file type; turn off compression and make
1460 the compression checkbox insensitive. */
1461 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1462 gtk_widget_set_sensitive(compressed_cb, FALSE);
1464 gtk_widget_set_sensitive(compressed_cb, TRUE);
1467 static check_savability_t
1468 check_save_as_with_comments(capture_file *cf, GtkWidget *file_chooser_w,
1469 GtkWidget *ft_combo_box)
1472 int selected_file_type;
1473 GtkWidget *msg_dialog;
1475 GtkWidget *compressed_cb;
1476 gboolean compressed;
1478 /* Do we have any comments? */
1479 if (!cf_has_comments(cf)) {
1480 /* No. Let the save happen; no comments to delete. */
1484 /* OK, we have comments. Can we write them out in the selected
1486 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1487 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1489 selected_file_type = GPOINTER_TO_INT(ptr);
1491 /* XXX - for now, we "know" that pcap-ng is the only format for which
1492 we support comments. We should really ask Wiretap what the
1493 format in question supports (and handle different types of
1494 comments, some but not all of which some file formats might
1496 if (selected_file_type == WTAP_FILE_PCAPNG) {
1497 /* Yes - they selected pcap-ng. Let the save happen; we can
1498 save the comments, so no need to delete them. */
1501 /* No. Is pcap-ng one of the formats in which we can write this file? */
1502 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, cf->linktypes)) {
1503 /* Yes. Offer the user a choice of "Save in a format that
1504 supports comments", "Discard comments and save in the
1505 format you selected", or "Cancel", meaning "don't bother
1506 saving the file at all". */
1507 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_chooser_w),
1508 GTK_DIALOG_DESTROY_WITH_PARENT,
1509 GTK_MESSAGE_QUESTION,
1511 "The capture has comments, but the file format you chose "
1512 "doesn't support comments. Do you want to save the capture "
1513 "in a format that supports comments, or discard the comments "
1514 "and save in the format you chose?");
1516 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1517 "Discard comments and save",
1518 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1520 GTK_RESPONSE_CANCEL,
1521 "Save in another format",
1522 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1525 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1526 "Save in another format",
1527 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1529 GTK_RESPONSE_CANCEL,
1530 "Discard comments and save",
1531 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1534 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1535 RESPONSE_SAVE_IN_ANOTHER_FORMAT);
1537 /* No. Offer the user a choice of "Discard comments and
1538 save in the format you selected" or "Cancel". */
1539 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_chooser_w),
1540 GTK_DIALOG_DESTROY_WITH_PARENT,
1541 GTK_MESSAGE_QUESTION,
1543 "The capture has comments, but no file format in which it "
1544 "can be saved supports comments. Do you want to discard "
1545 "the comments and save in the format you chose?");
1547 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1548 "Discard comments and save",
1549 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1551 GTK_RESPONSE_CANCEL,
1554 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1556 GTK_RESPONSE_CANCEL,
1557 "Discard comments and save",
1558 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1561 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1562 GTK_RESPONSE_CANCEL);
1565 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1566 gtk_widget_destroy(msg_dialog);
1570 case RESPONSE_SAVE_IN_ANOTHER_FORMAT:
1571 /* OK, the only other format we support is pcap-ng. Make that
1572 the one and only format in the combo box, and return to
1573 let the user continue with the dialog.
1575 XXX - removing all the formats from the combo box will clear
1576 the compressed checkbox; get the current value and restore
1579 XXX - we know pcap-ng can be compressed; if we ever end up
1580 supporting saving comments in a format that *can't* be
1581 compressed, such as NetMon format, we must check this. */
1582 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(file_chooser_w),
1583 E_COMPRESSED_CB_KEY);
1584 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1585 ws_combo_box_clear_text_and_pointer(GTK_COMBO_BOX(ft_combo_box));
1586 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box),
1587 wtap_file_type_string(WTAP_FILE_PCAPNG),
1588 GINT_TO_POINTER(WTAP_FILE_PCAPNG));
1589 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), compressed);
1591 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
1592 return SAVE_IN_ANOTHER_FORMAT;
1594 case RESPONSE_DISCARD_COMMENTS_AND_SAVE:
1595 /* Save without the comments and, if that succeeds, delete the
1597 return SAVE_WITHOUT_COMMENTS;
1599 case GTK_RESPONSE_CANCEL:
1600 case GTK_RESPONSE_NONE:
1601 case GTK_RESPONSE_DELETE_EVENT:
1609 do_file_save_as(capture_file *cf, gboolean must_support_comments,
1610 gboolean dont_reopen)
1612 #ifdef USE_WIN32_FILE_DIALOGS
1613 if (win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)),
1614 cf, must_support_comments, dont_reopen)) {
1615 /* They discarded comments, so redraw the packet details window
1616 to reflect any packets that no longer have comments. */
1617 new_packet_list_queue_draw();
1619 #else /* USE_WIN32_FILE_DIALOGS */
1620 GtkWidget *file_save_as_w;
1621 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *compressed_cb;
1624 gboolean discard_comments;
1626 /* Default to saving in the file's current format. */
1628 /* build the file selection */
1629 file_save_as_w = file_selection_new("Wireshark: Save Capture File As",
1630 FILE_SELECTION_SAVE);
1631 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_save_as_w),
1634 /* Container for each row of widgets */
1636 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1637 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1638 file_selection_set_extra_widget(file_save_as_w, main_vb);
1639 gtk_widget_show(main_vb);
1642 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1643 gtk_box_pack_start(GTK_BOX (main_vb), ft_hb, TRUE, TRUE, 0);
1644 gtk_widget_show(ft_hb);
1646 ft_lb = gtk_label_new("File type:");
1647 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1648 gtk_widget_show(ft_lb);
1650 ft_combo_box = ws_combo_box_new_text_and_pointer();
1652 /* Generate the list of file types we can save. */
1653 default_ft = set_file_type_list(ft_combo_box, cf, must_support_comments);
1654 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1655 gtk_widget_show(ft_combo_box);
1656 g_object_set_data(G_OBJECT(file_save_as_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1658 /* compressed - if the file is currently compressed, and the default
1659 file type supports compression, turn the checkbox on */
1660 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1661 gtk_box_pack_start(GTK_BOX (ft_hb), compressed_cb, TRUE, TRUE, 0);
1662 if (cf->iscompressed && wtap_dump_can_compress(default_ft))
1663 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), TRUE);
1664 gtk_widget_show(compressed_cb);
1665 g_object_set_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY, compressed_cb);
1667 /* Ok: now "select" the default filetype which invokes file_select_file_type_cb */
1668 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_select_file_type_cb), file_save_as_w);
1669 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1672 * Loop until the user either selects a file or gives up.
1675 cf_name = file_selection_run(file_save_as_w);
1676 if (cf_name == NULL) {
1677 /* User cancelled or closed the dialog. */
1681 /* If the file has comments, does the format the user selected
1682 support them? If not, ask the user whether they want to
1683 discard the comments or choose a different format. */
1684 switch (check_save_as_with_comments(cf, file_save_as_w, ft_combo_box)) {
1687 /* The file can be saved in the specified format as is;
1688 just drive on and save in the format they selected. */
1689 discard_comments = FALSE;
1692 case SAVE_WITHOUT_COMMENTS:
1693 /* The file can't be saved in the specified format as is,
1694 but it can be saved without the comments, and the user
1695 said "OK, discard the comments", so save it in the
1696 format they specified without the comments. */
1697 discard_comments = TRUE;
1700 case SAVE_IN_ANOTHER_FORMAT:
1701 /* There are file formats in which we can save this that
1702 support comments, and the user said not to delete the
1703 comments. The combo box of file formats has had the
1704 formats that don't support comments trimmed from it,
1705 so run the dialog again, to let the user decide
1706 whether to save in one of those formats or give up. */
1711 /* The user said "forget it". Just get rid of the dialog box
1713 window_destroy(file_save_as_w);
1718 /* If the file exists and it's user-immutable or not writable,
1719 ask the user whether they want to override that. */
1720 if (!file_target_unwritable_ui(file_save_as_w, cf_name)) {
1721 /* They don't. Let them try another file name or cancel. */
1727 /* Attempt to save the file */
1729 switch (file_save_as_cb(file_save_as_w, discard_comments, dont_reopen)) {
1732 /* The save succeeded; we're done.
1733 If we discarded comments, redraw the packet list to reflect
1734 any packets that no longer have comments. */
1735 if (discard_comments)
1736 new_packet_list_queue_draw();
1739 case CF_WRITE_ERROR:
1740 /* The save failed; let the user try again. */
1743 case CF_WRITE_ABORTED:
1744 /* The user aborted the save; just return. */
1748 #endif /* USE_WIN32_FILE_DIALOGS */
1752 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1754 do_file_save_as(&cfile, FALSE, FALSE);
1757 /* all tests ok, we only have to save the file */
1758 /* (and probably continue with a pending operation) */
1759 static cf_write_status_t
1760 file_save_as_cb(GtkWidget *fs, gboolean discard_comments,
1761 gboolean dont_reopen)
1763 GtkWidget *ft_combo_box;
1764 GtkWidget *compressed_cb;
1769 gboolean compressed;
1770 cf_write_status_t status;
1772 /* Hide the file chooser while doing the save. */
1773 gtk_widget_hide(fs);
1775 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1777 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1778 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1780 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1781 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1783 file_type = GPOINTER_TO_INT(ptr);
1784 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1786 /* Write out all the packets to the file with the specified name. */
1787 status = cf_save_packets(&cfile, cf_name, file_type, compressed,
1788 discard_comments, dont_reopen);
1792 /* The write succeeded; get rid of the file selection box. */
1793 /* cf_save_packets() might already closed our dialog! */
1796 /* Save the directory name for future file dialogs. */
1797 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1798 set_last_open_dir(dirname);
1801 case CF_WRITE_ERROR:
1802 /* The write failed.
1803 just leave the file selection box around so that the user can,
1804 after they dismiss the alert box popped up for the error, try
1808 case CF_WRITE_ABORTED:
1809 /* The write was aborted; just get rid of the file selection
1819 file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1821 #ifdef USE_WIN32_FILE_DIALOGS
1822 win32_export_specified_packets_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
1823 #else /* USE_WIN32_FILE_DIALOGS */
1824 GtkWidget *file_export_specified_packets_w;
1825 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *range_tb,
1827 packet_range_t range;
1829 gchar *display_basename;
1830 GtkWidget *msg_dialog;
1832 /* Default to writing out all displayed packets, in the file's current format. */
1834 /* init the packet range */
1835 packet_range_init(&range);
1836 range.process_filtered = TRUE;
1837 range.include_dependents = TRUE;
1839 /* build the file selection */
1840 file_export_specified_packets_w = file_selection_new("Wireshark: Export Specified Packets",
1841 FILE_SELECTION_SAVE);
1842 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_export_specified_packets_w),
1845 /* Container for each row of widgets */
1847 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1848 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1849 file_selection_set_extra_widget(file_export_specified_packets_w, main_vb);
1850 gtk_widget_show(main_vb);
1852 /*** Packet Range frame ***/
1853 range_fr = gtk_frame_new("Packet Range");
1854 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1855 gtk_widget_show(range_fr);
1858 range_tb = range_new(&range, TRUE);
1859 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1860 gtk_widget_show(range_tb);
1863 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1864 gtk_box_pack_start(GTK_BOX (main_vb), ft_hb, TRUE, TRUE, 0);
1866 gtk_widget_show(ft_hb);
1868 ft_lb = gtk_label_new("File type:");
1869 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1870 gtk_widget_show(ft_lb);
1872 ft_combo_box = ws_combo_box_new_text_and_pointer();
1874 /* Generate the list of file types we can save. */
1875 set_file_type_list(ft_combo_box, &cfile, FALSE);
1876 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1877 gtk_widget_show(ft_combo_box);
1878 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1880 /* dynamic values in the range frame */
1881 range_update_dynamics(range_tb);
1884 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1885 gtk_box_pack_start(GTK_BOX (ft_hb), compressed_cb, TRUE, TRUE, 0);
1886 gtk_widget_show(compressed_cb);
1887 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_COMPRESSED_CB_KEY, compressed_cb);
1889 /* Ok: now "select" the default filetype which invokes file_select_file_type_cb */
1890 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_select_file_type_cb), file_export_specified_packets_w);
1891 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1894 * Loop until the user either selects a file or gives up.
1897 cf_name = file_selection_run(file_export_specified_packets_w);
1898 if (cf_name == NULL) {
1899 /* User cancelled or closed the dialog. */
1903 /* Check whether the range is valid. */
1904 if (!range_check_validity_modal(file_export_specified_packets_w, &range)) {
1905 /* The range isn't valid; the user was told that, and dismissed
1906 the dialog telling them that, so let them fix the range
1907 and try again, or cancel. */
1913 * Check that we're not going to save on top of the current
1915 * We do it here so we catch all cases ...
1916 * Unfortunately, the file requester gives us an absolute file
1917 * name and the read file name may be relative (if supplied on
1918 * the command line). From Joerg Mayer.
1920 if (files_identical(cfile.filename, cf_name)) {
1921 display_basename = g_filename_display_basename(cf_name);
1922 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_export_specified_packets_w),
1923 GTK_DIALOG_DESTROY_WITH_PARENT,
1926 "The file \"%s\" is the capture file from which you're exporting the packets.",
1928 g_free(display_basename);
1929 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1930 "You cannot export packets on top of the current capture file.");
1931 gtk_dialog_run(GTK_DIALOG(msg_dialog));
1932 gtk_widget_destroy(msg_dialog);
1938 /* If the file exists and it's user-immutable or not writable,
1939 ask the user whether they want to override that. */
1940 if (!file_target_unwritable_ui(file_export_specified_packets_w, cf_name)) {
1941 /* They don't. Let them try another file name or cancel. */
1947 /* attempt to export the packets */
1949 switch (file_export_specified_packets_cb(file_export_specified_packets_w,
1953 /* The save succeeded; we're done. */
1956 case CF_WRITE_ERROR:
1957 /* The save failed; let the user try again */
1960 case CF_WRITE_ABORTED:
1961 /* The user aborted the save; just return. */
1965 #endif /* USE_WIN32_FILE_DIALOGS */
1968 /* all tests ok, we only have to write out the packets */
1969 /* (and probably continue with a pending operation) */
1970 static cf_write_status_t
1971 file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range)
1973 GtkWidget *ft_combo_box;
1974 GtkWidget *compressed_cb;
1979 gboolean compressed;
1980 cf_write_status_t status;
1982 /* Hide the file chooser while we're doing the export. */
1983 gtk_widget_hide(fs);
1985 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1987 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1988 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1990 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1991 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1993 file_type = GPOINTER_TO_INT(ptr);
1994 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1996 /* Write out the specified packets to the file with the specified name. */
1997 status = cf_export_specified_packets(&cfile, cf_name, range, file_type,
2002 /* The write succeeded; get rid of the file selection box. */
2003 /* cf_export_specified_packets() might already closed our dialog! */
2004 window_destroy(GTK_WIDGET(fs));
2006 /* Save the directory name for future file dialogs.
2007 XXX - should there be separate ones for "Save As" and
2008 "Export Specified Packets"? */
2009 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2010 set_last_open_dir(dirname);
2013 case CF_WRITE_ERROR:
2014 /* The write failed.
2015 just leave the file selection box around so that the user can,
2016 after they dismiss the alert box popped up for the error, try
2020 case CF_WRITE_ABORTED:
2021 /* The write was aborted; just get rid of the file selection
2030 /* Reload a file using the current read and display filters */
2032 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
2036 /******************** Color Filters *********************************/
2038 * Keep a static pointer to the current "Color Export" window, if
2039 * any, so that if somebody tries to do "Export"
2040 * while there's already a "Color Export" window up, we just pop
2041 * up the existing one, rather than creating a new one.
2043 static GtkWidget *file_color_import_w;
2045 /* sets the file path to the global color filter file.
2046 WARNING: called by both the import and the export dialog.
2049 color_global_cb(GtkWidget *widget _U_, gpointer data)
2051 GtkWidget *fs_widget = (GtkWidget *)data;
2054 /* decide what file to open (from dfilter code) */
2055 path = get_datafile_path("colorfilters");
2057 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
2062 /* Import color filters */
2064 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
2066 #ifdef USE_WIN32_FILE_DIALOGS
2067 win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
2068 #else /* USE_WIN32_FILE_DIALOGS */
2069 GtkWidget *main_vb, *cfglobal_but;
2072 /* No Apply button, and "OK" just sets our text widget, it doesn't
2073 activate it (i.e., it doesn't cause us to try to open the file). */
2075 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
2076 FILE_SELECTION_OPEN);
2078 /* Container for each row of widgets */
2079 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2080 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2081 file_selection_set_extra_widget(file_color_import_w, main_vb);
2082 gtk_widget_show(main_vb);
2084 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2085 gtk_box_pack_start(GTK_BOX (main_vb), cfglobal_but, TRUE, TRUE, 0);
2086 g_signal_connect(cfglobal_but, "clicked",
2087 G_CALLBACK(color_global_cb), file_color_import_w);
2088 gtk_widget_show(cfglobal_but);
2091 * Loop until the user either selects a file or gives up.
2094 cf_name = file_selection_run(file_color_import_w);
2095 if (cf_name == NULL) {
2096 /* User cancelled or closed the dialog. */
2100 /* Try to open the color filter file. */
2101 if (!color_filters_import(cf_name, color_filters)) {
2102 /* We couldn't open it; don't dismiss the open dialog box,
2103 just leave it around so that the user can, after they
2104 dismiss the alert box popped up for the open error,
2110 /* We've crossed the Rubicon; get rid of the file selection box. */
2111 window_destroy(GTK_WIDGET(file_color_import_w));
2113 /* Save the name of the containing directory specified in the path name,
2114 if any; we can write over cf_name, which is a good thing, given that
2115 "get_dirname()" does write over its argument. */
2116 s = get_dirname(cf_name);
2117 set_last_open_dir(s);
2122 #endif /* USE_WIN32_FILE_DIALOGS */
2126 * Set the "Export only selected filters" toggle button as appropriate for
2127 * the current output file type and count of selected filters.
2129 * Called when the "Export" dialog box is created and when the selected
2133 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
2135 /* We can request that only the selected filters be saved only if
2136 there *are* selected filters. */
2137 if (color_selected_count() != 0)
2138 gtk_widget_set_sensitive(cfselect_cb, TRUE);
2140 /* Force the "Export only selected filters" toggle to "false", turn
2141 off the flag it controls. */
2142 color_selected = FALSE;
2143 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2144 gtk_widget_set_sensitive(cfselect_cb, FALSE);
2149 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
2151 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
2155 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
2157 #ifdef USE_WIN32_FILE_DIALOGS
2158 win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
2159 #else /* USE_WIN32_FILE_DIALOGS */
2160 GtkWidget *file_color_export_w;
2161 GtkWidget *main_vb, *cfglobal_but;
2162 GtkWidget *cfselect_cb;
2166 color_selected = FALSE;
2168 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
2169 FILE_SELECTION_SAVE);
2170 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_color_export_w),
2173 /* Container for each row of widgets */
2174 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2175 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2176 file_selection_set_extra_widget(file_color_export_w, main_vb);
2177 gtk_widget_show(main_vb);
2179 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
2180 gtk_box_pack_start(GTK_BOX (main_vb), cfselect_cb, TRUE, TRUE, 0);
2181 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2182 g_signal_connect(cfselect_cb, "toggled",
2183 G_CALLBACK(color_toggle_selected_cb), NULL);
2184 gtk_widget_show(cfselect_cb);
2185 color_set_export_selected_sensitive(cfselect_cb);
2187 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2188 gtk_box_pack_start(GTK_BOX (main_vb), cfglobal_but, TRUE, TRUE, 0);
2189 g_signal_connect(cfglobal_but, "clicked",
2190 G_CALLBACK(color_global_cb), file_color_export_w);
2191 gtk_widget_show(cfglobal_but);
2194 * Loop until the user either selects a file or gives up.
2197 cf_name = file_selection_run(file_color_export_w);
2198 if (cf_name == NULL) {
2199 /* User cancelled or closed the dialog. */
2204 /* If the file exists and it's user-immutable or not writable,
2205 ask the user whether they want to override that. */
2206 if (!file_target_unwritable_ui(file_color_export_w, cf_name)) {
2207 /* They don't. Let them try another file name or cancel. */
2213 /* Write out the filters (all, or only the ones that are currently
2214 displayed or selected) to the file with the specified name. */
2215 if (!color_filters_export(cf_name, filter_list, color_selected)) {
2216 /* The write failed; don't dismiss the open dialog box,
2217 just leave it around so that the user can, after they
2218 dismiss the alert box popped up for the error, try again. */
2223 /* The write succeeded; get rid of the file selection box. */
2224 window_destroy(GTK_WIDGET(file_color_export_w));
2226 /* Save the directory name for future file dialogs. */
2227 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2228 set_last_open_dir(dirname);
2231 #endif /* USE_WIN32_FILE_DIALOGS */
2240 * indent-tabs-mode: nil
2243 * ex: set shiftwidth=2 tabstop=8 expandtab:
2244 * :indentSize=2:tabSize=8:noTabs=true: