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/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);
92 static gboolean test_file_close(capture_file *cf, gboolean from_quit,
93 const char *before_what);
95 #define E_FILE_TYPE_COMBO_BOX_KEY "file_type_combo_box"
96 #define E_COMPRESSED_CB_KEY "compressed_cb"
98 #define PREVIEW_TABLE_KEY "preview_table_key"
99 #define PREVIEW_FORMAT_KEY "preview_format_key"
100 #define PREVIEW_SIZE_KEY "preview_size_key"
101 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
102 #define PREVIEW_PACKETS_KEY "preview_packets_key"
103 #define PREVIEW_FIRST_KEY "preview_first_key"
105 /* XXX - can we make these not be static? */
106 static gboolean color_selected;
108 #define PREVIEW_STR_MAX 200
111 /* set a new filename for the preview widget */
113 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
119 gchar string_buff[PREVIEW_STR_MAX];
123 /* init preview labels */
124 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
125 gtk_label_set_text(GTK_LABEL(label), "-");
126 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
127 gtk_label_set_text(GTK_LABEL(label), "-");
128 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
129 gtk_label_set_text(GTK_LABEL(label), "-");
130 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
131 gtk_label_set_text(GTK_LABEL(label), "-");
132 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
133 gtk_label_set_text(GTK_LABEL(label), "-");
139 if (test_for_directory(cf_name) == EISDIR) {
140 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
141 gtk_label_set_text(GTK_LABEL(label), "directory");
145 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
147 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
148 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
149 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
151 gtk_label_set_text(GTK_LABEL(label), "error opening file");
156 /* Find the size of the file. */
157 filesize = wtap_file_size(wth, &err);
158 if (filesize == -1) {
159 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
163 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize);
164 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
165 gtk_label_set_text(GTK_LABEL(label), string_buff);
168 g_strlcpy(string_buff, wtap_file_type_string(wtap_file_type(wth)), PREVIEW_STR_MAX);
169 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
170 gtk_label_set_text(GTK_LABEL(label), string_buff);
176 /* do a preview run on the currently selected capture file */
178 preview_do(GtkWidget *prev, wtap *wth)
181 unsigned int elapsed_time;
187 const struct wtap_pkthdr *phdr;
188 double start_time = 0; /* seconds, with nsec resolution */
189 double stop_time = 0; /* seconds, with nsec resolution */
191 unsigned int packets = 0;
192 gboolean is_breaked = FALSE;
193 gchar string_buff[PREVIEW_STR_MAX];
199 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
200 phdr = wtap_phdr(wth);
201 cur_time = wtap_nstime_to_sec(&phdr->ts);
203 start_time = cur_time;
204 stop_time = cur_time;
206 if (cur_time < start_time) {
207 start_time = cur_time;
209 if (cur_time > stop_time){
210 stop_time = cur_time;
214 if(packets%1000 == 0) {
215 /* do we have a timeout? */
217 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
225 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
226 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
227 gtk_label_set_text(GTK_LABEL(label), string_buff);
234 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
236 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
238 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
239 gtk_label_set_text(GTK_LABEL(label), string_buff);
242 ti_time = (long)start_time;
243 ti_tm = localtime( &ti_time );
245 g_snprintf(string_buff, PREVIEW_STR_MAX,
246 "%04d-%02d-%02d %02d:%02d:%02d",
247 ti_tm->tm_year + 1900,
254 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
256 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
257 gtk_label_set_text(GTK_LABEL(label), string_buff);
260 elapsed_time = (unsigned int)(stop_time-start_time);
261 if(elapsed_time/86400) {
262 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
263 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
265 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
266 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
269 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
271 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
272 gtk_label_set_text(GTK_LABEL(label), string_buff);
278 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
279 simply use the same layout as in GTK2.0 */
281 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
283 GtkWidget *prev = GTK_WIDGET (data);
285 gboolean have_preview;
287 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
289 have_preview = preview_set_filename(prev, cf_name);
294 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
299 /* the filename text entry changed */
301 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
303 GtkWidget *prev = (GtkWidget *)g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY);
305 gboolean have_preview;
308 /* get the filename */
309 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
311 /* set the filename to the preview */
312 wth = preview_set_filename(prev, cf_name);
313 have_preview = (wth != NULL);
317 /* make the preview widget sensitive */
318 gtk_widget_set_sensitive(prev, have_preview);
321 * XXX - if the Open button isn't sensitive, you can't type into
322 * the location bar and select the file or directory you've typed.
325 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1791
327 * It's not as if allowing users to click Open when they've
328 * selected a file that's not a valid capture file will cause
329 * anything worse than an error dialog, so we'll leave the Open
330 * button sensitive for now. Perhaps making it sensitive if
331 * cf_name is NULL would also work, although I don't know whether
332 * there are any cases where it would be non-null when you've
333 * typed in the location bar.
335 * XXX - Bug 1791 also notes that, with the line removed, Bill
336 * Meier "somehow managed to get the file chooser window somewhat
337 * wedged in that neither the cancel or open buttons were responsive".
338 * That seems a bit odd, given that, without this line, we're not
339 * monkeying with the Open button's sensitivity, but...
342 /* make the open/save/... dialog button sensitive */
344 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, 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.0f, 0.5f);
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.0f, 0.5f);
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, "Format:", "-");
401 g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label);
402 label = add_string_to_table(table, &row, "Size:", "-");
403 g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label);
404 label = add_string_to_table(table, &row, "Packets:", "-");
405 g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label);
406 label = add_string_to_table(table, &row, "First Packet:", "-");
407 g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label);
408 label = add_string_to_table(table, &row, "Elapsed time:", "-");
409 g_object_set_data(G_OBJECT(table), PREVIEW_ELAPSED_KEY, label);
414 #ifndef USE_WIN32_FILE_DIALOGS
417 gtk_open_file(GtkWidget *w, GString *file_name, GString *display_filter)
419 GtkWidget *file_open_w;
420 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
421 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *e_resolv_cb, *prev;
422 /* No Apply button, and "OK" just sets our text widget, it doesn't
423 activate it (i.e., it doesn't cause us to try to open the file). */
424 static construct_args_t args = {
425 "Wireshark: Display Filter",
432 if (!file_name || !display_filter)
435 file_open_w = file_selection_new("Wireshark: Open Capture File",
436 FILE_SELECTION_OPEN);
437 /* it's annoying, that the file chooser dialog is already shown here,
438 so we cannot use the correct gtk_window_set_default_size() to resize it */
439 gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT);
441 if (file_name->len > 0) {
442 gchar *dirname = g_path_get_dirname(file_name->str);
444 file_selection_set_current_folder(file_open_w, dirname);
447 switch (prefs.gui_fileopen_style) {
449 case FO_STYLE_LAST_OPENED:
450 /* The user has specified that we should start out in the last directory
451 we looked in. If we've already opened a file, use its containing
452 directory, if we could determine it, as the directory, otherwise
453 use the "last opened" directory saved in the preferences file if
455 /* This is now the default behaviour in file_selection_new() */
458 case FO_STYLE_SPECIFIED:
459 /* The user has specified that we should always start out in a
460 specified directory; if they've specified that directory,
461 start out by showing the files in that dir. */
462 if (prefs.gui_fileopen_dir[0] != '\0')
463 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
468 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
469 file_selection_set_extra_widget(file_open_w, main_hb);
470 gtk_widget_show(main_hb);
472 /* Container for each row of widgets */
473 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
474 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
475 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
476 gtk_widget_show(main_vb);
479 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
480 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
481 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
482 gtk_widget_show(filter_hbox);
484 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
485 g_signal_connect(filter_bt, "clicked",
486 G_CALLBACK(display_filter_construct_cb), &args);
487 g_signal_connect(filter_bt, "destroy",
488 G_CALLBACK(filter_button_destroy_cb), NULL);
489 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
490 gtk_widget_show(filter_bt);
491 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
493 filter_te = gtk_entry_new();
494 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
495 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
496 g_signal_connect(filter_te, "changed",
497 G_CALLBACK(filter_te_syntax_check_cb), NULL);
498 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
499 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
500 g_signal_connect(file_open_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
501 colorize_filter_te_as_empty(filter_te);
502 gtk_entry_set_text(GTK_ENTRY(filter_te), display_filter->str);
503 gtk_widget_show(filter_te);
504 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
506 g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te);
508 /* resolve buttons */
509 m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution");
510 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
511 gbl_resolv_flags.mac_name);
512 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
513 gtk_widget_show(m_resolv_cb);
515 t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution");
516 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
517 gbl_resolv_flags.transport_name);
518 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
519 gtk_widget_show(t_resolv_cb);
521 n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution");
522 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
523 gbl_resolv_flags.network_name);
524 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
525 gtk_widget_show(n_resolv_cb);
527 e_resolv_cb = gtk_check_button_new_with_mnemonic("Use _external network name resolver");
528 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e_resolv_cb),
529 gbl_resolv_flags.use_external_net_name_resolver);
530 gtk_box_pack_start(GTK_BOX(main_vb), e_resolv_cb, FALSE, FALSE, 0);
531 gtk_widget_show(e_resolv_cb);
534 prev = preview_new();
535 g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev);
536 gtk_widget_show_all(prev);
537 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
539 g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
540 G_CALLBACK(file_open_entry_changed), file_open_w);
541 file_open_entry_changed(file_open_w, file_open_w);
543 g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY,
544 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
546 cf_name = file_selection_run(file_open_w);
547 if (cf_name == NULL) {
548 /* User cancelled or closed the dialog. */
552 g_string_printf(file_name, "%s", cf_name);
554 g_string_printf(display_filter, "%s", gtk_entry_get_text(GTK_ENTRY(filter_te)));
556 /* Set the global resolving variable */
557 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_resolv_cb)))
558 gbl_resolv_flags.mac_name = TRUE;
560 gbl_resolv_flags.mac_name = FALSE;
561 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(n_resolv_cb)))
562 gbl_resolv_flags.network_name = TRUE;
564 gbl_resolv_flags.network_name = FALSE;
565 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t_resolv_cb)))
566 gbl_resolv_flags.transport_name = TRUE;
568 gbl_resolv_flags.transport_name = FALSE;
569 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(e_resolv_cb)))
570 gbl_resolv_flags.use_external_net_name_resolver = TRUE;
572 gbl_resolv_flags.use_external_net_name_resolver = FALSE;
574 /* We've crossed the Rubicon; get rid of the file selection box. */
575 window_destroy(GTK_WIDGET(file_open_w));
579 #endif /* USE_WIN32_FILE_DIALOGS */
584 * <platform/>_open_file routines should upon entry...
585 * Set the path and fill in the filename if the path+filename is provided.
586 * Set the display filter if provided. Filter syntax should be checked.
587 * Set the name resolution check boxes to match the global settings.
588 * ...and upon exit...
589 * Return TRUE on "OK" and "FALSE" on "Cancel".
590 * Set the global name resolution preferences on "OK".
595 file_open_cmd(capture_file *cf, GtkWidget *w _U_)
597 GString *file_name = g_string_new("");
598 GString *display_filter = g_string_new("");
599 dfilter_t *rfcode = NULL;
603 * Loop until the user either selects a file or gives up.
606 #ifdef USE_WIN32_FILE_DIALOGS
607 if (win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), file_name, display_filter)) {
608 #else /* USE_WIN32_FILE_DIALOGS */
609 if (gtk_open_file(w, file_name, display_filter)) {
610 #endif /* USE_WIN32_FILE_DIALOGS */
612 /* Only close the old file now that we know we want to open another one. */
614 /* apply our filter */
615 if (dfilter_compile(display_filter->str, &rfcode)) {
616 cf_set_rfcode(&cfile, rfcode);
618 /* Not valid. Tell the user, and go back and run the file
619 selection box again once they dismiss the alert. */
620 bad_dfilter_alert_box(top_level, display_filter->str);
624 /* Try to open the capture file. */
625 if (cf_open(&cfile, file_name->str, FALSE, &err) != CF_OK) {
626 /* We couldn't open it; don't dismiss the open dialog box,
627 just leave it around so that the user can, after they
628 dismiss the alert box popped up for the open error,
631 dfilter_free(rfcode);
636 switch (cf_read(&cfile, FALSE)) {
640 /* Just because we got an error, that doesn't mean we were unable
641 to read any of the file; we handle what we could get from the
645 case CF_READ_ABORTED:
646 /* The user bailed out of re-reading the capture file; the
647 capture file has been closed - just free the capture file name
648 string and return (without changing the last containing
650 g_string_free(file_name, TRUE);
651 g_string_free(display_filter, TRUE);
654 /* Save the name of the containing directory specified in the path name,
655 if any; we can write over cf_name, which is a good thing, given that
656 "get_dirname()" does write over its argument. */
657 set_last_open_dir(get_dirname(file_name->str));
658 gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), display_filter->str);
660 g_string_free(file_name, TRUE);
661 g_string_free(display_filter, TRUE);
667 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
668 /* If there's unsaved data, let the user save it first.
669 If they cancel out of it, don't quit. */
670 if (test_file_close(&cfile, FALSE, " before opening a new capture file"))
671 file_open_cmd(&cfile, widget);
674 /* Merge existing with another file */
676 file_merge_cmd(GtkWidget *w)
678 #ifdef USE_WIN32_FILE_DIALOGS
679 win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
680 new_packet_list_freeze();
681 new_packet_list_thaw();
682 #else /* USE_WIN32_FILE_DIALOGS */
683 GtkWidget *file_merge_w;
684 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
685 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
688 /* No Apply button, and "OK" just sets our text widget, it doesn't
689 activate it (i.e., it doesn't cause us to try to open the file). */
690 static construct_args_t args = {
691 "Wireshark: Read Filter",
697 const gchar *rfilter;
698 dfilter_t *rfcode = NULL;
702 cf_status_t merge_status;
703 char *in_filenames[2];
706 /* Default to saving all packets, in the file's current format. */
708 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
709 FILE_SELECTION_OPEN);
710 /* it's annoying, that the file chooser dialog is already shown here,
711 so we cannot use the correct gtk_window_set_default_size() to resize it */
712 gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
714 switch (prefs.gui_fileopen_style) {
716 case FO_STYLE_LAST_OPENED:
717 /* The user has specified that we should start out in the last directory
718 we looked in. If we've already opened a file, use its containing
719 directory, if we could determine it, as the directory, otherwise
720 use the "last opened" directory saved in the preferences file if
722 /* This is now the default behaviour in file_selection_new() */
725 case FO_STYLE_SPECIFIED:
726 /* The user has specified that we should always start out in a
727 specified directory; if they've specified that directory,
728 start out by showing the files in that dir. */
729 if (prefs.gui_fileopen_dir[0] != '\0')
730 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
734 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
735 file_selection_set_extra_widget(file_merge_w, main_hb);
736 gtk_widget_show(main_hb);
738 /* Container for each row of widgets */
739 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
740 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
741 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
742 gtk_widget_show(main_vb);
745 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
746 gtk_box_pack_start(GTK_BOX (main_vb), ft_hb, TRUE, TRUE, 0);
747 gtk_widget_show(ft_hb);
749 ft_lb = gtk_label_new("Merged output file type:");
750 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
751 gtk_widget_show(ft_lb);
753 ft_combo_box = ws_combo_box_new_text_and_pointer();
755 /* Generate the list of file types we can save. */
756 set_file_type_list(ft_combo_box, &cfile, FALSE);
757 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
758 gtk_widget_show(ft_combo_box);
759 g_object_set_data(G_OBJECT(file_merge_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
760 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
762 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
763 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
764 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
765 gtk_widget_show(filter_hbox);
767 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
768 g_signal_connect(filter_bt, "clicked",
769 G_CALLBACK(display_filter_construct_cb), &args);
770 g_signal_connect(filter_bt, "destroy",
771 G_CALLBACK(filter_button_destroy_cb), NULL);
772 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
773 gtk_widget_show(filter_bt);
774 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
776 filter_te = gtk_entry_new();
777 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
778 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
779 g_signal_connect(filter_te, "changed",
780 G_CALLBACK(filter_te_syntax_check_cb), NULL);
781 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
782 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
783 g_signal_connect(file_merge_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
784 colorize_filter_te_as_empty(filter_te);
785 gtk_widget_show(filter_te);
786 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
788 g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te);
790 prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL,
791 "Prepend packets to existing file");
792 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.");
793 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
794 gtk_widget_show(prepend_rb);
796 chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically");
797 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.");
798 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
799 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
800 gtk_widget_show(chrono_rb);
802 append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file");
803 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.");
804 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
805 gtk_widget_show(append_rb);
808 prev = preview_new();
809 g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev);
810 gtk_widget_show_all(prev);
811 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
813 g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
814 G_CALLBACK(file_open_entry_changed), file_merge_w);
815 file_open_entry_changed(file_merge_w, file_merge_w);
817 g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY,
818 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
821 * Loop until the user either selects a file or gives up.
824 cf_name = file_selection_run(file_merge_w);
825 if (cf_name == NULL) {
826 /* User cancelled or closed the dialog. */
830 /* Get the specified read filter and try to compile it. */
831 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
832 if (!dfilter_compile(rfilter, &rfcode)) {
833 /* Not valid. Tell the user, and go back and run the file
834 selection box again once they dismiss the alert. */
835 bad_dfilter_alert_box(file_merge_w, rfilter);
840 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
841 g_assert_not_reached(); /* Programming error: somehow nothing is active */
843 file_type = GPOINTER_TO_INT(ptr);
845 /* Try to merge or append the two files */
847 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(chrono_rb))) {
848 /* chronological order */
849 in_filenames[0] = cfile.filename;
850 in_filenames[1] = cf_name;
851 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
852 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prepend_rb))) {
854 in_filenames[0] = cf_name;
855 in_filenames[1] = cfile.filename;
856 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
860 in_filenames[0] = cfile.filename;
861 in_filenames[1] = cf_name;
862 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
868 if (merge_status != CF_OK) {
870 dfilter_free(rfcode);
877 /* We've crossed the Rubicon; get rid of the file selection box. */
878 window_destroy(GTK_WIDGET(file_merge_w));
880 /* Try to open the merged capture file. */
881 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
882 /* We couldn't open it; fail. */
884 dfilter_free(rfcode);
890 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
891 it closed the previous capture file, and thus destroyed any
892 previous read filter attached to "cf"). */
893 cfile.rfcode = rfcode;
895 switch (cf_read(&cfile, FALSE)) {
899 /* Just because we got an error, that doesn't mean we were unable
900 to read any of the file; we handle what we could get from the
904 case CF_READ_ABORTED:
905 /* The user bailed out of re-reading the capture file; the
906 capture file has been closed - just free the capture file name
907 string and return (without changing the last containing
912 /* Save the name of the containing directory specified in the path name,
913 if any; we can write over cf_merged_name, which is a good thing, given that
914 "get_dirname()" does write over its argument. */
915 s = get_dirname(tmpname);
916 set_last_open_dir(s);
919 #endif /* USE_WIN32_FILE_DIALOGS */
923 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
924 /* If there's unsaved data, let the user save it first.
925 If they cancel out of it, don't merge. */
926 GtkWidget *msg_dialog;
927 gchar *display_basename;
930 if (prefs.gui_ask_unsaved) {
931 if (cfile.is_tempfile || cfile.unsaved_changes) {
932 /* This is a temporary capture file or has unsaved changes; ask the
933 user whether to save the capture. */
934 if (cfile.is_tempfile) {
935 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
936 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
937 GTK_MESSAGE_QUESTION,
939 "Do you want to save the captured packets before merging another capture file into it?");
941 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
942 "A temporary capture file can't be merged.");
945 * Format the message.
947 display_basename = g_filename_display_basename(cfile.filename);
948 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
949 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
950 GTK_MESSAGE_QUESTION,
952 "Do you want to save the changes you've made "
953 "to the capture file \"%s\" before merging another capture file into it?",
955 g_free(display_basename);
956 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
957 "The changes must be saved before the files are merged.");
961 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
962 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
963 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
964 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
966 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
967 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
968 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
969 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
971 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
973 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
974 gtk_widget_destroy(msg_dialog);
978 case GTK_RESPONSE_ACCEPT:
979 /* Save the file but don't close it */
980 do_file_save(&cfile, FALSE);
983 case GTK_RESPONSE_CANCEL:
984 case GTK_RESPONSE_NONE:
985 case GTK_RESPONSE_DELETE_EVENT:
987 /* Don't do the merge. */
994 file_merge_cmd(widget);
999 do_capture_stop(capture_file *cf)
1001 /* Stop the capture (complete with UI updates). */
1002 capture_stop_cb(NULL, NULL);
1004 /* Now run the main loop until the capture stops and we finish
1005 reading it; we need to run the main loop so we respond to
1006 messages on the sync pipe and the sync pipe being closed. */
1007 while (cf->state == FILE_READ_IN_PROGRESS)
1008 gtk_main_iteration();
1012 /* Returns true if the current file has been saved or if the user has chosen
1013 * to discard it, ie if it is safe to continue with the call to close, and
1014 * false otherwise. */
1016 test_file_close(capture_file *cf, gboolean from_quit, const char *before_what)
1018 GtkWidget *msg_dialog;
1019 gchar *display_basename;
1021 gboolean capture_in_progress;
1023 if (cf->state == FILE_CLOSED)
1024 return TRUE; /* already closed, nothing to do */
1027 if (cf->state == FILE_READ_IN_PROGRESS) {
1028 /* This is true if we're reading a capture file *or* if we're doing
1029 a live capture. If we're reading a capture file, the main loop
1030 is busy reading packets, and only accepting input from the
1031 progress dialog, so we can't get here, so this means we're
1033 capture_in_progress = TRUE;
1036 capture_in_progress = FALSE;
1038 if (prefs.gui_ask_unsaved) {
1039 if (cf->is_tempfile || capture_in_progress || cf->unsaved_changes) {
1040 /* This is a temporary capture file, or there's a capture in
1041 progress, or the file has unsaved changes; ask the user whether
1042 to save the data. */
1043 if (cf->is_tempfile) {
1044 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1045 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1046 GTK_MESSAGE_QUESTION,
1048 capture_in_progress ?
1049 "Do you want to stop the capture and save the captured packets%s?" :
1050 "Do you want to save the captured packets%s?",
1053 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1054 "Your captured packets will be lost if you don't save them.");
1057 * Format the message.
1059 display_basename = g_filename_display_basename(cf->filename);
1060 if (capture_in_progress) {
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 stop the capture and save the captured packets%s?",
1068 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1069 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1070 GTK_MESSAGE_QUESTION,
1072 "Do you want to save the changes you've made "
1073 "to the capture file \"%s\"%s?",
1074 display_basename, before_what);
1076 g_free(display_basename);
1077 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1078 capture_in_progress ?
1079 "Your captured packets will be lost if you don't save them." :
1080 "Your changes will be lost if you don't save them.");
1084 /* If this is from a Quit operation, use "quit and don't save"
1085 rather than just "don't save". */
1086 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1088 (cf->state == FILE_READ_IN_PROGRESS ?
1089 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1090 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1091 (capture_in_progress ?
1092 WIRESHARK_STOCK_STOP_DONT_SAVE :
1093 WIRESHARK_STOCK_DONT_SAVE)),
1094 GTK_RESPONSE_REJECT);
1095 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1096 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1097 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1098 (capture_in_progress ?
1099 WIRESHARK_STOCK_STOP_SAVE :
1101 GTK_RESPONSE_ACCEPT);
1103 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1104 (capture_in_progress ?
1105 WIRESHARK_STOCK_STOP_SAVE :
1107 GTK_RESPONSE_ACCEPT);
1108 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1109 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1110 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1112 (capture_in_progress ?
1113 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1114 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1115 (capture_in_progress ?
1116 WIRESHARK_STOCK_STOP_DONT_SAVE :
1117 WIRESHARK_STOCK_DONT_SAVE)),
1118 GTK_RESPONSE_REJECT);
1120 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
1122 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1123 gtk_widget_destroy(msg_dialog);
1127 case GTK_RESPONSE_ACCEPT:
1129 /* If there's a capture in progress, we have to stop the capture
1130 and then do the save. */
1131 if (capture_in_progress)
1132 do_capture_stop(cf);
1134 /* Save the file and close it */
1135 do_file_save(cf, TRUE);
1138 case GTK_RESPONSE_REJECT:
1140 /* If there's a capture in progress; we have to stop the capture
1141 and then do the close. */
1142 if (capture_in_progress)
1143 do_capture_stop(cf);
1147 case GTK_RESPONSE_CANCEL:
1148 case GTK_RESPONSE_NONE:
1149 case GTK_RESPONSE_DELETE_EVENT:
1151 /* Don't close the file (and don't stop any capture in progress). */
1152 return FALSE; /* file not closed */
1155 /* unchanged file, safe to close */
1159 /* User asked not to be bothered by those prompts, just close it.
1160 XXX - should that apply only to saving temporary files? */
1162 /* If there's a capture in progress, we have to stop the capture
1163 and then do the close. */
1164 if (capture_in_progress)
1165 do_capture_stop(cf);
1169 return TRUE; /* shouldn't get here? */
1173 do_file_close(capture_file *cf, gboolean from_quit, const char *before_what)
1175 if (test_file_close(cf, from_quit, before_what)) {
1184 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1185 do_file_close(&cfile, FALSE, "");
1190 SAVE_WITHOUT_COMMENTS,
1191 SAVE_IN_ANOTHER_FORMAT,
1193 } check_savability_t;
1195 #define RESPONSE_DISCARD_COMMENTS_AND_SAVE 1
1196 #define RESPONSE_SAVE_IN_ANOTHER_FORMAT 2
1198 static check_savability_t
1199 check_save_with_comments(capture_file *cf)
1201 GtkWidget *msg_dialog;
1204 /* Do we have any comments? */
1205 if (!cf_has_comments(cf)) {
1206 /* No. Let the save happen; no comments to delete. */
1210 /* OK, we have comments. Can we write them out in the file's format?
1212 XXX - for now, we "know" that pcap-ng is the only format for which
1213 we support comments. We should really ask Wiretap what the
1214 format in question supports (and handle different types of
1215 comments, some but not all of which some file formats might
1217 if (cf->cd_t == WTAP_FILE_PCAPNG) {
1218 /* Yes - the file is a pcap-ng file. Let the save happen; we can
1219 save the comments, so no need to delete them. */
1223 /* Is pcap-ng one of the formats in which we can write this file? */
1224 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, cf->linktypes)) {
1225 /* Yes. Ooffer the user a choice of "Save in a format that
1226 supports comments", "Discard comments and save in the
1227 file's own format", or "Cancel", meaning "don't bother
1228 saving the file at all". */
1229 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1230 GTK_DIALOG_DESTROY_WITH_PARENT,
1231 GTK_MESSAGE_QUESTION,
1233 "The capture has comments, but the file's format "
1234 "doesn't support comments. Do you want to save the capture "
1235 "in a format that supports comments, or discard the comments "
1236 "and save in the file's format?");
1238 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1239 "Discard comments and save",
1240 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1242 GTK_RESPONSE_CANCEL,
1243 "Save in another format",
1244 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1247 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1248 "Save in another format",
1249 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1251 GTK_RESPONSE_CANCEL,
1252 "Discard comments and save",
1253 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1256 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1257 RESPONSE_SAVE_IN_ANOTHER_FORMAT);
1259 /* No. Offer the user a choice of "Discard comments and
1260 save in the file's format" or "Cancel". */
1261 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1262 GTK_DIALOG_DESTROY_WITH_PARENT,
1263 GTK_MESSAGE_QUESTION,
1265 "The capture has comments, but no file format in which it "
1266 "can be saved supports comments. Do you want to discard "
1267 "the comments and save in the file's format?");
1269 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1270 "Discard comments and save",
1271 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1273 GTK_RESPONSE_CANCEL,
1276 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1278 GTK_RESPONSE_CANCEL,
1279 "Discard comments and save",
1280 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1283 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1284 GTK_RESPONSE_CANCEL);
1287 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1288 gtk_widget_destroy(msg_dialog);
1292 case RESPONSE_SAVE_IN_ANOTHER_FORMAT:
1293 /* Let the user select another format. */
1294 return SAVE_IN_ANOTHER_FORMAT;
1296 case RESPONSE_DISCARD_COMMENTS_AND_SAVE:
1297 /* Save without the comments and, if that succeeds, delete the
1299 return SAVE_WITHOUT_COMMENTS;
1301 case GTK_RESPONSE_CANCEL:
1302 case GTK_RESPONSE_NONE:
1303 case GTK_RESPONSE_DELETE_EVENT:
1311 * Save the capture file in question, prompting the user for a file
1312 * name to save to if necessary.
1315 do_file_save(capture_file *cf, gboolean dont_reopen)
1318 gboolean discard_comments;
1319 cf_write_status_t status;
1321 if (cf->is_tempfile) {
1322 /* This is a temporary capture file, so saving it means saving
1323 it to a permanent file. Prompt the user for a location
1324 to which to save it. Don't require that the file format
1325 support comments - if it's a temporary capture file, it's
1326 probably pcap-ng, which supports comments and, if it's
1327 not pcap-ng, let the user decide what they want to do
1328 if they've added comments. */
1329 do_file_save_as(cf, FALSE, dont_reopen);
1331 if (cf->unsaved_changes) {
1332 /* This is not a temporary capture file, but it has unsaved
1333 changes, so saving it means doing a "safe save" on top
1334 of the existing file, in the same format - no UI needed
1335 unless the file has comments and the file's format doesn't
1338 If the file has comments, does the file's format support them?
1339 If not, ask the user whether they want to discard the comments
1340 or choose a different format. */
1341 switch (check_save_with_comments(cf)) {
1344 /* The file can be saved in the specified format as is;
1345 just drive on and save in the format they selected. */
1346 discard_comments = FALSE;
1349 case SAVE_WITHOUT_COMMENTS:
1350 /* The file can't be saved in the specified format as is,
1351 but it can be saved without the comments, and the user
1352 said "OK, discard the comments", so save it in the
1353 format they specified without the comments. */
1354 discard_comments = TRUE;
1357 case SAVE_IN_ANOTHER_FORMAT:
1358 /* There are file formats in which we can save this that
1359 support comments, and the user said not to delete the
1360 comments. Do a "Save As" so the user can select
1361 one of those formats and choose a file name. */
1362 do_file_save_as(cf, TRUE, dont_reopen);
1366 /* The user said "forget it". Just return. */
1370 /* Squelch warnings that discard_comments is being used
1372 g_assert_not_reached();
1376 /* XXX - cf->filename might get freed out from under us, because
1377 the code path through which cf_save_packets() goes currently
1378 closes the current file and then opens and reloads the saved file,
1379 so make a copy and free it later. */
1380 fname = g_strdup(cf->filename);
1381 status = cf_save_packets(cf, fname, cf->cd_t, cf->iscompressed,
1382 discard_comments, dont_reopen);
1386 /* The save succeeded; we're done.
1387 If we discarded comments, redraw the packet list to reflect
1388 any packets that no longer have comments. */
1389 if (discard_comments)
1390 new_packet_list_queue_draw();
1393 case CF_WRITE_ERROR:
1394 /* The write failed.
1395 XXX - OK, what do we do now? Let them try a
1396 "Save As", in case they want to try to save to a
1397 different directory r file system? */
1400 case CF_WRITE_ABORTED:
1401 /* The write was aborted; just drive on. */
1406 /* Otherwise just do nothing. */
1411 file_save_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1412 do_file_save(&cfile, FALSE);
1415 /* Attach a list of the valid 'save as' file types to a combo_box by
1416 checking what Wiretap supports. Make the default type the first
1417 in the list. If must_supprt_comments is true, restrict the list
1418 to those formats that support comments (currently, just pcap-ng).
1420 Returns the default file type. */
1422 set_file_type_list(GtkWidget *combo_box, capture_file *cf,
1423 gboolean must_support_comments)
1425 GArray *savable_file_types;
1428 int default_ft = -1;
1430 savable_file_types = wtap_get_savable_file_types(cf->cd_t, cf->linktypes);
1432 if (savable_file_types != NULL) {
1433 /* OK, we have at least one file type we can save this file as.
1434 (If we didn't, we shouldn't have gotten here in the first
1435 place.) Add them all to the combo box. */
1436 for (i = 0; i < savable_file_types->len; i++) {
1437 ft = g_array_index(savable_file_types, int, i);
1438 if (must_support_comments) {
1439 if (ft != WTAP_FILE_PCAPNG)
1442 if (default_ft == -1)
1443 default_ft = ft; /* first file type is the default */
1444 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(combo_box),
1445 wtap_file_type_string(ft),
1446 GINT_TO_POINTER(ft));
1448 g_array_free(savable_file_types, TRUE);
1455 file_select_file_type_cb(GtkWidget *w, gpointer parent_arg)
1457 GtkWidget *parent = parent_arg;
1460 GtkWidget *compressed_cb;
1462 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(parent), E_COMPRESSED_CB_KEY);
1463 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr)) {
1464 /* XXX - this can happen when we clear the list of file types
1465 and then reconstruct it. */
1466 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1467 gtk_widget_set_sensitive(compressed_cb, FALSE);
1470 new_file_type = GPOINTER_TO_INT(ptr);
1472 if (!wtap_dump_can_compress(new_file_type)) {
1473 /* Can't compress this file type; turn off compression and make
1474 the compression checkbox insensitive. */
1475 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1476 gtk_widget_set_sensitive(compressed_cb, FALSE);
1478 gtk_widget_set_sensitive(compressed_cb, TRUE);
1481 static check_savability_t
1482 check_save_as_with_comments(capture_file *cf, GtkWidget *file_chooser_w,
1483 GtkWidget *ft_combo_box)
1486 int selected_file_type;
1487 GtkWidget *msg_dialog;
1489 GtkWidget *compressed_cb;
1490 gboolean compressed;
1492 /* Do we have any comments? */
1493 if (!cf_has_comments(cf)) {
1494 /* No. Let the save happen; no comments to delete. */
1498 /* OK, we have comments. Can we write them out in the selected
1500 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1501 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1503 selected_file_type = GPOINTER_TO_INT(ptr);
1505 /* XXX - for now, we "know" that pcap-ng is the only format for which
1506 we support comments. We should really ask Wiretap what the
1507 format in question supports (and handle different types of
1508 comments, some but not all of which some file formats might
1510 if (selected_file_type == WTAP_FILE_PCAPNG) {
1511 /* Yes - they selected pcap-ng. Let the save happen; we can
1512 save the comments, so no need to delete them. */
1515 /* No. Is pcap-ng one of the formats in which we can write this file? */
1516 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, cf->linktypes)) {
1517 /* Yes. Offer the user a choice of "Save in a format that
1518 supports comments", "Discard comments and save in the
1519 format you selected", or "Cancel", meaning "don't bother
1520 saving the file at all". */
1521 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_chooser_w),
1522 GTK_DIALOG_DESTROY_WITH_PARENT,
1523 GTK_MESSAGE_QUESTION,
1525 "The capture has comments, but the file format you chose "
1526 "doesn't support comments. Do you want to save the capture "
1527 "in a format that supports comments, or discard the comments "
1528 "and save in the format you chose?");
1530 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1531 "Discard comments and save",
1532 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1534 GTK_RESPONSE_CANCEL,
1535 "Save in another format",
1536 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1539 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1540 "Save in another format",
1541 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1543 GTK_RESPONSE_CANCEL,
1544 "Discard comments and save",
1545 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1548 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1549 RESPONSE_SAVE_IN_ANOTHER_FORMAT);
1551 /* No. Offer the user a choice of "Discard comments and
1552 save in the format you selected" or "Cancel". */
1553 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_chooser_w),
1554 GTK_DIALOG_DESTROY_WITH_PARENT,
1555 GTK_MESSAGE_QUESTION,
1557 "The capture has comments, but no file format in which it "
1558 "can be saved supports comments. Do you want to discard "
1559 "the comments and save in the format you chose?");
1561 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1562 "Discard comments and save",
1563 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1565 GTK_RESPONSE_CANCEL,
1568 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1570 GTK_RESPONSE_CANCEL,
1571 "Discard comments and save",
1572 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1575 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1576 GTK_RESPONSE_CANCEL);
1579 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1580 gtk_widget_destroy(msg_dialog);
1584 case RESPONSE_SAVE_IN_ANOTHER_FORMAT:
1585 /* OK, the only other format we support is pcap-ng. Make that
1586 the one and only format in the combo box, and return to
1587 let the user continue with the dialog.
1589 XXX - removing all the formats from the combo box will clear
1590 the compressed checkbox; get the current value and restore
1593 XXX - we know pcap-ng can be compressed; if we ever end up
1594 supporting saving comments in a format that *can't* be
1595 compressed, such as NetMon format, we must check this. */
1596 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(file_chooser_w),
1597 E_COMPRESSED_CB_KEY);
1598 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1599 ws_combo_box_clear_text_and_pointer(GTK_COMBO_BOX(ft_combo_box));
1600 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box),
1601 wtap_file_type_string(WTAP_FILE_PCAPNG),
1602 GINT_TO_POINTER(WTAP_FILE_PCAPNG));
1603 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), compressed);
1605 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
1606 return SAVE_IN_ANOTHER_FORMAT;
1608 case RESPONSE_DISCARD_COMMENTS_AND_SAVE:
1609 /* Save without the comments and, if that succeeds, delete the
1611 return SAVE_WITHOUT_COMMENTS;
1613 case GTK_RESPONSE_CANCEL:
1614 case GTK_RESPONSE_NONE:
1615 case GTK_RESPONSE_DELETE_EVENT:
1623 do_file_save_as(capture_file *cf, gboolean must_support_comments,
1624 gboolean dont_reopen)
1626 #ifdef USE_WIN32_FILE_DIALOGS
1627 if (win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)),
1628 cf, must_support_comments, dont_reopen)) {
1629 /* They discarded comments, so redraw the packet details window
1630 to reflect any packets that no longer have comments. */
1631 new_packet_list_queue_draw();
1633 #else /* USE_WIN32_FILE_DIALOGS */
1634 GtkWidget *file_save_as_w;
1635 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *compressed_cb;
1638 gboolean discard_comments;
1640 /* Default to saving in the file's current format. */
1642 /* build the file selection */
1643 file_save_as_w = file_selection_new("Wireshark: Save Capture File As",
1644 FILE_SELECTION_SAVE);
1645 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_save_as_w),
1648 /* Container for each row of widgets */
1650 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1651 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1652 file_selection_set_extra_widget(file_save_as_w, main_vb);
1653 gtk_widget_show(main_vb);
1656 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1657 gtk_box_pack_start(GTK_BOX (main_vb), ft_hb, TRUE, TRUE, 0);
1658 gtk_widget_show(ft_hb);
1660 ft_lb = gtk_label_new("File type:");
1661 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1662 gtk_widget_show(ft_lb);
1664 ft_combo_box = ws_combo_box_new_text_and_pointer();
1666 /* Generate the list of file types we can save. */
1667 default_ft = set_file_type_list(ft_combo_box, cf, must_support_comments);
1668 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1669 gtk_widget_show(ft_combo_box);
1670 g_object_set_data(G_OBJECT(file_save_as_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1672 /* compressed - if the file is currently compressed, and the default
1673 file type supports compression, turn the checkbox on */
1674 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1675 gtk_box_pack_start(GTK_BOX (ft_hb), compressed_cb, TRUE, TRUE, 0);
1676 if (cf->iscompressed && wtap_dump_can_compress(default_ft))
1677 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), TRUE);
1678 gtk_widget_show(compressed_cb);
1679 g_object_set_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY, compressed_cb);
1681 /* Ok: now "select" the default filetype which invokes file_select_file_type_cb */
1682 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_select_file_type_cb), file_save_as_w);
1683 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1686 * Loop until the user either selects a file or gives up.
1689 cf_name = file_selection_run(file_save_as_w);
1690 if (cf_name == NULL) {
1691 /* User cancelled or closed the dialog. */
1695 /* If the file has comments, does the format the user selected
1696 support them? If not, ask the user whether they want to
1697 discard the comments or choose a different format. */
1698 switch (check_save_as_with_comments(cf, file_save_as_w, ft_combo_box)) {
1701 /* The file can be saved in the specified format as is;
1702 just drive on and save in the format they selected. */
1703 discard_comments = FALSE;
1706 case SAVE_WITHOUT_COMMENTS:
1707 /* The file can't be saved in the specified format as is,
1708 but it can be saved without the comments, and the user
1709 said "OK, discard the comments", so save it in the
1710 format they specified without the comments. */
1711 discard_comments = TRUE;
1714 case SAVE_IN_ANOTHER_FORMAT:
1715 /* There are file formats in which we can save this that
1716 support comments, and the user said not to delete the
1717 comments. The combo box of file formats has had the
1718 formats that don't support comments trimmed from it,
1719 so run the dialog again, to let the user decide
1720 whether to save in one of those formats or give up. */
1725 /* The user said "forget it". Just get rid of the dialog box
1727 window_destroy(file_save_as_w);
1732 /* If the file exists and it's user-immutable or not writable,
1733 ask the user whether they want to override that. */
1734 if (!file_target_unwritable_ui(file_save_as_w, cf_name)) {
1735 /* They don't. Let them try another file name or cancel. */
1741 /* Attempt to save the file */
1743 switch (file_save_as_cb(file_save_as_w, discard_comments, dont_reopen)) {
1746 /* The save succeeded; we're done.
1747 If we discarded comments, redraw the packet list to reflect
1748 any packets that no longer have comments. */
1749 if (discard_comments)
1750 new_packet_list_queue_draw();
1753 case CF_WRITE_ERROR:
1754 /* The save failed; let the user try again. */
1757 case CF_WRITE_ABORTED:
1758 /* The user aborted the save; just return. */
1762 #endif /* USE_WIN32_FILE_DIALOGS */
1766 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1768 do_file_save_as(&cfile, FALSE, FALSE);
1771 /* all tests ok, we only have to save the file */
1772 /* (and probably continue with a pending operation) */
1773 static cf_write_status_t
1774 file_save_as_cb(GtkWidget *fs, gboolean discard_comments,
1775 gboolean dont_reopen)
1777 GtkWidget *ft_combo_box;
1778 GtkWidget *compressed_cb;
1783 gboolean compressed;
1784 cf_write_status_t status;
1786 /* Hide the file chooser while doing the save. */
1787 gtk_widget_hide(fs);
1789 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1791 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1792 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1794 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1795 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1797 file_type = GPOINTER_TO_INT(ptr);
1798 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1800 /* Write out all the packets to the file with the specified name. */
1801 status = cf_save_packets(&cfile, cf_name, file_type, compressed,
1802 discard_comments, dont_reopen);
1806 /* The write succeeded; get rid of the file selection box. */
1807 /* cf_save_packets() might already closed our dialog! */
1810 /* Save the directory name for future file dialogs. */
1811 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1812 set_last_open_dir(dirname);
1815 case CF_WRITE_ERROR:
1816 /* The write failed.
1817 just leave the file selection box around so that the user can,
1818 after they dismiss the alert box popped up for the error, try
1822 case CF_WRITE_ABORTED:
1823 /* The write was aborted; just get rid of the file selection
1833 file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1835 #ifdef USE_WIN32_FILE_DIALOGS
1836 win32_export_specified_packets_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
1837 #else /* USE_WIN32_FILE_DIALOGS */
1838 GtkWidget *file_export_specified_packets_w;
1839 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *range_tb,
1841 packet_range_t range;
1843 gchar *display_basename;
1844 GtkWidget *msg_dialog;
1846 /* Default to writing out all displayed packets, in the file's current format. */
1848 /* init the packet range */
1849 packet_range_init(&range);
1850 range.process_filtered = TRUE;
1851 range.include_dependents = TRUE;
1853 /* build the file selection */
1854 file_export_specified_packets_w = file_selection_new("Wireshark: Export Specified Packets",
1855 FILE_SELECTION_SAVE);
1856 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_export_specified_packets_w),
1859 /* Container for each row of widgets */
1861 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1862 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1863 file_selection_set_extra_widget(file_export_specified_packets_w, main_vb);
1864 gtk_widget_show(main_vb);
1866 /*** Packet Range frame ***/
1867 range_fr = gtk_frame_new("Packet Range");
1868 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1869 gtk_widget_show(range_fr);
1872 range_tb = range_new(&range, TRUE);
1873 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1874 gtk_widget_show(range_tb);
1877 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1878 gtk_box_pack_start(GTK_BOX (main_vb), ft_hb, TRUE, TRUE, 0);
1880 gtk_widget_show(ft_hb);
1882 ft_lb = gtk_label_new("File type:");
1883 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1884 gtk_widget_show(ft_lb);
1886 ft_combo_box = ws_combo_box_new_text_and_pointer();
1888 /* Generate the list of file types we can save. */
1889 set_file_type_list(ft_combo_box, &cfile, FALSE);
1890 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1891 gtk_widget_show(ft_combo_box);
1892 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1894 /* dynamic values in the range frame */
1895 range_update_dynamics(range_tb);
1898 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1899 gtk_box_pack_start(GTK_BOX (ft_hb), compressed_cb, TRUE, TRUE, 0);
1900 gtk_widget_show(compressed_cb);
1901 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_COMPRESSED_CB_KEY, compressed_cb);
1903 /* Ok: now "select" the default filetype which invokes file_select_file_type_cb */
1904 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_select_file_type_cb), file_export_specified_packets_w);
1905 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1908 * Loop until the user either selects a file or gives up.
1911 cf_name = file_selection_run(file_export_specified_packets_w);
1912 if (cf_name == NULL) {
1913 /* User cancelled or closed the dialog. */
1917 /* Check whether the range is valid. */
1918 if (!range_check_validity_modal(file_export_specified_packets_w, &range)) {
1919 /* The range isn't valid; the user was told that, and dismissed
1920 the dialog telling them that, so let them fix the range
1921 and try again, or cancel. */
1927 * Check that we're not going to save on top of the current
1929 * We do it here so we catch all cases ...
1930 * Unfortunately, the file requester gives us an absolute file
1931 * name and the read file name may be relative (if supplied on
1932 * the command line). From Joerg Mayer.
1934 if (files_identical(cfile.filename, cf_name)) {
1935 display_basename = g_filename_display_basename(cf_name);
1936 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_export_specified_packets_w),
1937 GTK_DIALOG_DESTROY_WITH_PARENT,
1940 "The file \"%s\" is the capture file from which you're exporting the packets.",
1942 g_free(display_basename);
1943 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1944 "You cannot export packets on top of the current capture file.");
1945 gtk_dialog_run(GTK_DIALOG(msg_dialog));
1946 gtk_widget_destroy(msg_dialog);
1952 /* If the file exists and it's user-immutable or not writable,
1953 ask the user whether they want to override that. */
1954 if (!file_target_unwritable_ui(file_export_specified_packets_w, cf_name)) {
1955 /* They don't. Let them try another file name or cancel. */
1961 /* attempt to export the packets */
1963 switch (file_export_specified_packets_cb(file_export_specified_packets_w,
1967 /* The save succeeded; we're done. */
1970 case CF_WRITE_ERROR:
1971 /* The save failed; let the user try again */
1974 case CF_WRITE_ABORTED:
1975 /* The user aborted the save; just return. */
1979 #endif /* USE_WIN32_FILE_DIALOGS */
1982 /* all tests ok, we only have to write out the packets */
1983 /* (and probably continue with a pending operation) */
1984 static cf_write_status_t
1985 file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range)
1987 GtkWidget *ft_combo_box;
1988 GtkWidget *compressed_cb;
1993 gboolean compressed;
1994 cf_write_status_t status;
1996 /* Hide the file chooser while we're doing the export. */
1997 gtk_widget_hide(fs);
1999 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
2001 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
2002 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
2004 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
2005 g_assert_not_reached(); /* Programming error: somehow nothing is active */
2007 file_type = GPOINTER_TO_INT(ptr);
2008 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
2010 /* Write out the specified packets to the file with the specified name. */
2011 status = cf_export_specified_packets(&cfile, cf_name, range, file_type,
2016 /* The write succeeded; get rid of the file selection box. */
2017 /* cf_export_specified_packets() might already closed our dialog! */
2018 window_destroy(GTK_WIDGET(fs));
2020 /* Save the directory name for future file dialogs.
2021 XXX - should there be separate ones for "Save As" and
2022 "Export Specified Packets"? */
2023 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2024 set_last_open_dir(dirname);
2027 case CF_WRITE_ERROR:
2028 /* The write failed.
2029 just leave the file selection box around so that the user can,
2030 after they dismiss the alert box popped up for the error, try
2034 case CF_WRITE_ABORTED:
2035 /* The write was aborted; just get rid of the file selection
2044 /* Reload a file using the current read and display filters */
2046 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
2050 /******************** Color Filters *********************************/
2052 * Keep a static pointer to the current "Color Export" window, if
2053 * any, so that if somebody tries to do "Export"
2054 * while there's already a "Color Export" window up, we just pop
2055 * up the existing one, rather than creating a new one.
2057 static GtkWidget *file_color_import_w;
2059 /* sets the file path to the global color filter file.
2060 WARNING: called by both the import and the export dialog.
2063 color_global_cb(GtkWidget *widget _U_, gpointer data)
2065 GtkWidget *fs_widget = (GtkWidget *)data;
2068 /* decide what file to open (from dfilter code) */
2069 path = get_datafile_path("colorfilters");
2071 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
2076 /* Import color filters */
2078 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
2080 #ifdef USE_WIN32_FILE_DIALOGS
2081 win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
2082 #else /* USE_WIN32_FILE_DIALOGS */
2083 GtkWidget *main_vb, *cfglobal_but;
2086 /* No Apply button, and "OK" just sets our text widget, it doesn't
2087 activate it (i.e., it doesn't cause us to try to open the file). */
2089 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
2090 FILE_SELECTION_OPEN);
2092 /* Container for each row of widgets */
2093 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2094 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2095 file_selection_set_extra_widget(file_color_import_w, main_vb);
2096 gtk_widget_show(main_vb);
2098 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2099 gtk_box_pack_start(GTK_BOX (main_vb), cfglobal_but, TRUE, TRUE, 0);
2100 g_signal_connect(cfglobal_but, "clicked",
2101 G_CALLBACK(color_global_cb), file_color_import_w);
2102 gtk_widget_show(cfglobal_but);
2105 * Loop until the user either selects a file or gives up.
2108 cf_name = file_selection_run(file_color_import_w);
2109 if (cf_name == NULL) {
2110 /* User cancelled or closed the dialog. */
2114 /* Try to open the color filter file. */
2115 if (!color_filters_import(cf_name, color_filters)) {
2116 /* We couldn't open it; don't dismiss the open dialog box,
2117 just leave it around so that the user can, after they
2118 dismiss the alert box popped up for the open error,
2124 /* We've crossed the Rubicon; get rid of the file selection box. */
2125 window_destroy(GTK_WIDGET(file_color_import_w));
2127 /* Save the name of the containing directory specified in the path name,
2128 if any; we can write over cf_name, which is a good thing, given that
2129 "get_dirname()" does write over its argument. */
2130 s = get_dirname(cf_name);
2131 set_last_open_dir(s);
2136 #endif /* USE_WIN32_FILE_DIALOGS */
2140 * Set the "Export only selected filters" toggle button as appropriate for
2141 * the current output file type and count of selected filters.
2143 * Called when the "Export" dialog box is created and when the selected
2147 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
2149 /* We can request that only the selected filters be saved only if
2150 there *are* selected filters. */
2151 if (color_selected_count() != 0)
2152 gtk_widget_set_sensitive(cfselect_cb, TRUE);
2154 /* Force the "Export only selected filters" toggle to "false", turn
2155 off the flag it controls. */
2156 color_selected = FALSE;
2157 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2158 gtk_widget_set_sensitive(cfselect_cb, FALSE);
2163 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
2165 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
2169 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
2171 #ifdef USE_WIN32_FILE_DIALOGS
2172 win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
2173 #else /* USE_WIN32_FILE_DIALOGS */
2174 GtkWidget *file_color_export_w;
2175 GtkWidget *main_vb, *cfglobal_but;
2176 GtkWidget *cfselect_cb;
2180 color_selected = FALSE;
2182 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
2183 FILE_SELECTION_SAVE);
2184 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_color_export_w),
2187 /* Container for each row of widgets */
2188 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2189 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2190 file_selection_set_extra_widget(file_color_export_w, main_vb);
2191 gtk_widget_show(main_vb);
2193 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
2194 gtk_box_pack_start(GTK_BOX (main_vb), cfselect_cb, TRUE, TRUE, 0);
2195 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2196 g_signal_connect(cfselect_cb, "toggled",
2197 G_CALLBACK(color_toggle_selected_cb), NULL);
2198 gtk_widget_show(cfselect_cb);
2199 color_set_export_selected_sensitive(cfselect_cb);
2201 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2202 gtk_box_pack_start(GTK_BOX (main_vb), cfglobal_but, TRUE, TRUE, 0);
2203 g_signal_connect(cfglobal_but, "clicked",
2204 G_CALLBACK(color_global_cb), file_color_export_w);
2205 gtk_widget_show(cfglobal_but);
2208 * Loop until the user either selects a file or gives up.
2211 cf_name = file_selection_run(file_color_export_w);
2212 if (cf_name == NULL) {
2213 /* User cancelled or closed the dialog. */
2218 /* If the file exists and it's user-immutable or not writable,
2219 ask the user whether they want to override that. */
2220 if (!file_target_unwritable_ui(file_color_export_w, cf_name)) {
2221 /* They don't. Let them try another file name or cancel. */
2227 /* Write out the filters (all, or only the ones that are currently
2228 displayed or selected) to the file with the specified name. */
2229 if (!color_filters_export(cf_name, filter_list, color_selected)) {
2230 /* The write failed; don't dismiss the open dialog box,
2231 just leave it around so that the user can, after they
2232 dismiss the alert box popped up for the error, try again. */
2237 /* The write succeeded; get rid of the file selection box. */
2238 window_destroy(GTK_WIDGET(file_color_export_w));
2240 /* Save the directory name for future file dialogs. */
2241 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2242 set_last_open_dir(dirname);
2245 #endif /* USE_WIN32_FILE_DIALOGS */
2254 * indent-tabs-mode: nil
2257 * ex: set shiftwidth=2 tabstop=8 expandtab:
2258 * :indentSize=2:tabSize=8:noTabs=true: