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_FILENAME_KEY "preview_filename_key"
98 #define PREVIEW_FORMAT_KEY "preview_format_key"
99 #define PREVIEW_SIZE_KEY "preview_size_key"
100 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
101 #define PREVIEW_PACKETS_KEY "preview_packets_key"
102 #define PREVIEW_FIRST_KEY "preview_first_key"
104 /* XXX - can we make these not be static? */
105 static gboolean color_selected;
107 #define PREVIEW_STR_MAX 200
110 /* set a new filename for the preview widget */
112 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
115 gchar *display_basename;
119 gchar string_buff[PREVIEW_STR_MAX];
123 /* init preview labels */
124 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
125 gtk_label_set_text(GTK_LABEL(label), "-");
126 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
127 gtk_label_set_text(GTK_LABEL(label), "-");
128 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
129 gtk_label_set_text(GTK_LABEL(label), "-");
130 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
131 gtk_label_set_text(GTK_LABEL(label), "-");
132 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
133 gtk_label_set_text(GTK_LABEL(label), "-");
134 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
135 gtk_label_set_text(GTK_LABEL(label), "-");
141 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
142 display_basename = g_filename_display_basename(cf_name);
143 gtk_label_set_text(GTK_LABEL(label), display_basename);
144 g_free(display_basename);
146 if (test_for_directory(cf_name) == EISDIR) {
147 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
148 gtk_label_set_text(GTK_LABEL(label), "directory");
152 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
154 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
155 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
156 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
158 gtk_label_set_text(GTK_LABEL(label), "error opening file");
163 /* Find the size of the file. */
164 filesize = wtap_file_size(wth, &err);
165 if (filesize == -1) {
166 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
170 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize);
171 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
172 gtk_label_set_text(GTK_LABEL(label), string_buff);
175 g_strlcpy(string_buff, wtap_file_type_string(wtap_file_type(wth)), PREVIEW_STR_MAX);
176 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
177 gtk_label_set_text(GTK_LABEL(label), string_buff);
183 /* do a preview run on the currently selected capture file */
185 preview_do(GtkWidget *prev, wtap *wth)
188 unsigned int elapsed_time;
194 const struct wtap_pkthdr *phdr;
195 double start_time = 0; /* seconds, with nsec resolution */
196 double stop_time = 0; /* seconds, with nsec resolution */
198 unsigned int packets = 0;
199 gboolean is_breaked = FALSE;
200 gchar string_buff[PREVIEW_STR_MAX];
206 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
207 phdr = wtap_phdr(wth);
208 cur_time = wtap_nstime_to_sec(&phdr->ts);
210 start_time = cur_time;
211 stop_time = cur_time;
213 if (cur_time < start_time) {
214 start_time = cur_time;
216 if (cur_time > stop_time){
217 stop_time = cur_time;
221 if(packets%1000 == 0) {
222 /* do we have a timeout? */
224 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
232 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
233 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
234 gtk_label_set_text(GTK_LABEL(label), string_buff);
241 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
243 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
245 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
246 gtk_label_set_text(GTK_LABEL(label), string_buff);
249 ti_time = (long)start_time;
250 ti_tm = localtime( &ti_time );
252 g_snprintf(string_buff, PREVIEW_STR_MAX,
253 "%04d-%02d-%02d %02d:%02d:%02d",
254 ti_tm->tm_year + 1900,
261 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
263 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
264 gtk_label_set_text(GTK_LABEL(label), string_buff);
267 elapsed_time = (unsigned int)(stop_time-start_time);
268 if(elapsed_time/86400) {
269 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
270 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
272 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
273 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
276 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
278 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
279 gtk_label_set_text(GTK_LABEL(label), string_buff);
285 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
286 simply use the same layout as in GTK2.0 */
288 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
290 GtkWidget *prev = GTK_WIDGET (data);
292 gboolean have_preview;
294 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
296 have_preview = preview_set_filename(prev, cf_name);
301 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
306 /* the filename text entry changed */
308 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
310 GtkWidget *prev = (GtkWidget *)g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY);
312 gboolean have_preview;
315 /* get the filename */
316 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
318 /* set the filename to the preview */
319 wth = preview_set_filename(prev, cf_name);
320 have_preview = (wth != NULL);
324 /* make the preview widget sensitive */
325 gtk_widget_set_sensitive(prev, have_preview);
328 * XXX - if the Open button isn't sensitive, you can't type into
329 * the location bar and select the file or directory you've typed.
332 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1791
334 * It's not as if allowing users to click Open when they've
335 * selected a file that's not a valid capture file will cause
336 * anything worse than an error dialog, so we'll leave the Open
337 * button sensitive for now. Perhaps making it sensitive if
338 * cf_name is NULL would also work, although I don't know whether
339 * there are any cases where it would be non-null when you've
340 * typed in the location bar.
342 * XXX - Bug 1791 also notes that, with the line removed, Bill
343 * Meier "somehow managed to get the file chooser window somewhat
344 * wedged in that neither the cancel or open buttons were responsive".
345 * That seems a bit odd, given that, without this line, we're not
346 * monkeying with the Open button's sensitivity, but...
349 /* make the open/save/... dialog button sensitive */
351 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
354 /* do the actual preview */
356 preview_do(prev, wth);
360 /* copied from summary_dlg.c */
362 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
367 if(strlen(value) != 0) {
368 indent = g_strdup_printf(" %s", title);
370 indent = g_strdup(title);
372 label = gtk_label_new(indent);
374 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
375 gtk_widget_set_sensitive(label, sensitive);
376 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
378 label = gtk_label_new(value);
379 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
380 gtk_widget_set_sensitive(label, sensitive);
381 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
389 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
391 return add_string_to_table_sensitive(list, row, title, value, TRUE);
399 GtkWidget *table, *label;
402 table = gtk_table_new(1, 2, FALSE);
403 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
404 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
407 label = add_string_to_table(table, &row, "Filename:", "-");
408 gtk_widget_set_size_request(label, DEF_WIDTH/3, -1);
409 g_object_set_data(G_OBJECT(table), PREVIEW_FILENAME_KEY, label);
410 label = add_string_to_table(table, &row, "Format:", "-");
411 g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label);
412 label = add_string_to_table(table, &row, "Size:", "-");
413 g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label);
414 label = add_string_to_table(table, &row, "Packets:", "-");
415 g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label);
416 label = add_string_to_table(table, &row, "First Packet:", "-");
417 g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label);
418 label = add_string_to_table(table, &row, "Elapsed time:", "-");
419 g_object_set_data(G_OBJECT(table), PREVIEW_ELAPSED_KEY, label);
424 #ifndef USE_WIN32_FILE_DIALOGS
427 gtk_open_file(GtkWidget *w, GString *file_name, GString *display_filter)
429 GtkWidget *file_open_w;
430 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
431 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *e_resolv_cb, *prev;
432 /* No Apply button, and "OK" just sets our text widget, it doesn't
433 activate it (i.e., it doesn't cause us to try to open the file). */
434 static construct_args_t args = {
435 "Wireshark: Display Filter",
442 if (!file_name || !display_filter)
445 file_open_w = file_selection_new("Wireshark: Open Capture File",
446 FILE_SELECTION_OPEN);
447 /* it's annoying, that the file chooser dialog is already shown here,
448 so we cannot use the correct gtk_window_set_default_size() to resize it */
449 gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT);
451 if (file_name->len > 0) {
452 file_selection_set_current_folder(file_open_w, file_name->str);
454 switch (prefs.gui_fileopen_style) {
456 case FO_STYLE_LAST_OPENED:
457 /* The user has specified that we should start out in the last directory
458 we looked in. If we've already opened a file, use its containing
459 directory, if we could determine it, as the directory, otherwise
460 use the "last opened" directory saved in the preferences file if
462 /* This is now the default behaviour in file_selection_new() */
465 case FO_STYLE_SPECIFIED:
466 /* The user has specified that we should always start out in a
467 specified directory; if they've specified that directory,
468 start out by showing the files in that dir. */
469 if (prefs.gui_fileopen_dir[0] != '\0')
470 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
475 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
476 file_selection_set_extra_widget(file_open_w, main_hb);
477 gtk_widget_show(main_hb);
479 /* Container for each row of widgets */
480 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
481 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
482 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
483 gtk_widget_show(main_vb);
486 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
487 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
488 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
489 gtk_widget_show(filter_hbox);
491 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
492 g_signal_connect(filter_bt, "clicked",
493 G_CALLBACK(display_filter_construct_cb), &args);
494 g_signal_connect(filter_bt, "destroy",
495 G_CALLBACK(filter_button_destroy_cb), NULL);
496 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
497 gtk_widget_show(filter_bt);
498 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
500 filter_te = gtk_entry_new();
501 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
502 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
503 g_signal_connect(filter_te, "changed",
504 G_CALLBACK(filter_te_syntax_check_cb), NULL);
505 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
506 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
507 g_signal_connect(file_open_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
508 colorize_filter_te_as_empty(filter_te);
509 gtk_entry_set_text(GTK_ENTRY(filter_te), display_filter->str);
510 gtk_widget_show(filter_te);
511 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
513 g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te);
515 /* resolve buttons */
516 m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution");
517 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
518 gbl_resolv_flags.mac_name);
519 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
520 gtk_widget_show(m_resolv_cb);
522 t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution");
523 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
524 gbl_resolv_flags.transport_name);
525 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
526 gtk_widget_show(t_resolv_cb);
528 n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution");
529 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
530 gbl_resolv_flags.network_name);
531 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
532 gtk_widget_show(n_resolv_cb);
534 e_resolv_cb = gtk_check_button_new_with_mnemonic("Use _external network name resolver");
535 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e_resolv_cb),
536 gbl_resolv_flags.use_external_net_name_resolver);
537 gtk_box_pack_start(GTK_BOX(main_vb), e_resolv_cb, FALSE, FALSE, 0);
538 gtk_widget_show(e_resolv_cb);
541 prev = preview_new();
542 g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev);
543 gtk_widget_show_all(prev);
544 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
546 g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
547 G_CALLBACK(file_open_entry_changed), file_open_w);
548 file_open_entry_changed(file_open_w, file_open_w);
550 g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY,
551 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
553 cf_name = file_selection_run(file_open_w);
554 if (cf_name == NULL) {
555 /* User cancelled or closed the dialog. */
559 g_string_printf(file_name, "%s", cf_name);
561 g_string_printf(display_filter, "%s", gtk_entry_get_text(GTK_ENTRY(filter_te)));
563 /* Set the global resolving variable */
564 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_resolv_cb)))
565 gbl_resolv_flags.mac_name = TRUE;
567 gbl_resolv_flags.mac_name = FALSE;
568 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(n_resolv_cb)))
569 gbl_resolv_flags.network_name = TRUE;
571 gbl_resolv_flags.network_name = FALSE;
572 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t_resolv_cb)))
573 gbl_resolv_flags.transport_name = TRUE;
575 gbl_resolv_flags.transport_name = FALSE;
576 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(e_resolv_cb)))
577 gbl_resolv_flags.use_external_net_name_resolver = TRUE;
579 gbl_resolv_flags.use_external_net_name_resolver = FALSE;
581 /* We've crossed the Rubicon; get rid of the file selection box. */
582 window_destroy(GTK_WIDGET(file_open_w));
586 #endif /* USE_WIN32_FILE_DIALOGS */
591 * <platform/>_open_file routines should upon entry...
592 * Set the path and fill in the filename if the path+filename is provided.
593 * Set the display filter if provided. Filter syntax should be checked.
594 * Set the name resolution check boxes to match the global settings.
595 * ...and upon exit...
596 * Return TRUE on "OK" and "FALSE" on "Cancel".
597 * Set the global name resolution preferences on "OK".
602 file_open_cmd(GtkWidget *w _U_)
604 GString *file_name = g_string_new("");
605 GString *display_filter = g_string_new("");
606 dfilter_t *rfcode = NULL;
610 * Loop until the user either selects a file or gives up.
613 #ifdef USE_WIN32_FILE_DIALOGS
614 if (win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), file_name, display_filter)) {
615 #else /* USE_WIN32_FILE_DIALOGS */
616 if (gtk_open_file(w, file_name, display_filter)) {
617 #endif /* USE_WIN32_FILE_DIALOGS */
619 /* apply our filter */
620 if (dfilter_compile(display_filter->str, &rfcode)) {
621 cf_set_rfcode(&cfile, rfcode);
623 /* Not valid. Tell the user, and go back and run the file
624 selection box again once they dismiss the alert. */
625 bad_dfilter_alert_box(top_level, display_filter->str);
629 /* Try to open the capture file. */
630 if (cf_open(&cfile, file_name->str, FALSE, &err) != CF_OK) {
631 /* We couldn't open it; don't dismiss the open dialog box,
632 just leave it around so that the user can, after they
633 dismiss the alert box popped up for the open error,
636 dfilter_free(rfcode);
641 switch (cf_read(&cfile, FALSE)) {
645 /* Just because we got an error, that doesn't mean we were unable
646 to read any of the file; we handle what we could get from the
650 case CF_READ_ABORTED:
651 /* The user bailed out of re-reading the capture file; the
652 capture file has been closed - just free the capture file name
653 string and return (without changing the last containing
655 g_string_free(file_name, TRUE);
656 g_string_free(display_filter, TRUE);
659 /* Save the name of the containing directory specified in the path name,
660 if any; we can write over cf_name, which is a good thing, given that
661 "get_dirname()" does write over its argument. */
662 set_last_open_dir(get_dirname(file_name->str));
664 g_string_free(file_name, TRUE);
665 g_string_free(display_filter, TRUE);
671 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
672 /* If there's unsaved data, let the user save it first.
673 If they cancel out of it, don't quit. */
674 if (do_file_close(&cfile, FALSE, " before opening a new capture file"))
675 file_open_cmd(widget);
678 /* Merge existing with another file */
680 file_merge_cmd(GtkWidget *w)
682 #ifdef USE_WIN32_FILE_DIALOGS
683 win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
684 new_packet_list_freeze();
685 new_packet_list_thaw();
686 #else /* USE_WIN32_FILE_DIALOGS */
687 GtkWidget *file_merge_w;
688 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
689 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
692 /* No Apply button, and "OK" just sets our text widget, it doesn't
693 activate it (i.e., it doesn't cause us to try to open the file). */
694 static construct_args_t args = {
695 "Wireshark: Read Filter",
701 const gchar *rfilter;
702 dfilter_t *rfcode = NULL;
706 cf_status_t merge_status;
707 char *in_filenames[2];
710 /* Default to saving all packets, in the file's current format. */
712 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
713 FILE_SELECTION_OPEN);
714 /* it's annoying, that the file chooser dialog is already shown here,
715 so we cannot use the correct gtk_window_set_default_size() to resize it */
716 gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
718 switch (prefs.gui_fileopen_style) {
720 case FO_STYLE_LAST_OPENED:
721 /* The user has specified that we should start out in the last directory
722 we looked in. If we've already opened a file, use its containing
723 directory, if we could determine it, as the directory, otherwise
724 use the "last opened" directory saved in the preferences file if
726 /* This is now the default behaviour in file_selection_new() */
729 case FO_STYLE_SPECIFIED:
730 /* The user has specified that we should always start out in a
731 specified directory; if they've specified that directory,
732 start out by showing the files in that dir. */
733 if (prefs.gui_fileopen_dir[0] != '\0')
734 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
738 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
739 file_selection_set_extra_widget(file_merge_w, main_hb);
740 gtk_widget_show(main_hb);
742 /* Container for each row of widgets */
743 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
744 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
745 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
746 gtk_widget_show(main_vb);
749 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
750 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
751 gtk_widget_show(ft_hb);
753 ft_lb = gtk_label_new("Merged output file type:");
754 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
755 gtk_widget_show(ft_lb);
757 ft_combo_box = ws_combo_box_new_text_and_pointer();
759 /* Generate the list of file types we can save. */
760 set_file_type_list(ft_combo_box, &cfile, FALSE);
761 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
762 gtk_widget_show(ft_combo_box);
763 g_object_set_data(G_OBJECT(file_merge_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
764 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
766 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
767 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
768 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
769 gtk_widget_show(filter_hbox);
771 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
772 g_signal_connect(filter_bt, "clicked",
773 G_CALLBACK(display_filter_construct_cb), &args);
774 g_signal_connect(filter_bt, "destroy",
775 G_CALLBACK(filter_button_destroy_cb), NULL);
776 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
777 gtk_widget_show(filter_bt);
778 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
780 filter_te = gtk_entry_new();
781 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
782 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
783 g_signal_connect(filter_te, "changed",
784 G_CALLBACK(filter_te_syntax_check_cb), NULL);
785 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
786 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
787 g_signal_connect(file_merge_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
788 colorize_filter_te_as_empty(filter_te);
789 gtk_widget_show(filter_te);
790 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
792 g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te);
794 prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL,
795 "Prepend packets to existing file");
796 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.");
797 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
798 gtk_widget_show(prepend_rb);
800 chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically");
801 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.");
802 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
803 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
804 gtk_widget_show(chrono_rb);
806 append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file");
807 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.");
808 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
809 gtk_widget_show(append_rb);
812 prev = preview_new();
813 g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev);
814 gtk_widget_show_all(prev);
815 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
817 g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
818 G_CALLBACK(file_open_entry_changed), file_merge_w);
819 file_open_entry_changed(file_merge_w, file_merge_w);
821 g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY,
822 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
825 * Loop until the user either selects a file or gives up.
828 cf_name = file_selection_run(file_merge_w);
829 if (cf_name == NULL) {
830 /* User cancelled or closed the dialog. */
834 /* Get the specified read filter and try to compile it. */
835 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
836 if (!dfilter_compile(rfilter, &rfcode)) {
837 /* Not valid. Tell the user, and go back and run the file
838 selection box again once they dismiss the alert. */
839 bad_dfilter_alert_box(file_merge_w, rfilter);
844 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
845 g_assert_not_reached(); /* Programming error: somehow nothing is active */
847 file_type = GPOINTER_TO_INT(ptr);
849 /* Try to merge or append the two files */
851 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(chrono_rb))) {
852 /* chronological order */
853 in_filenames[0] = cfile.filename;
854 in_filenames[1] = cf_name;
855 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
856 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prepend_rb))) {
858 in_filenames[0] = cf_name;
859 in_filenames[1] = cfile.filename;
860 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
864 in_filenames[0] = cfile.filename;
865 in_filenames[1] = cf_name;
866 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
872 if (merge_status != CF_OK) {
874 dfilter_free(rfcode);
881 /* We've crossed the Rubicon; get rid of the file selection box. */
882 window_destroy(GTK_WIDGET(file_merge_w));
884 /* Try to open the merged capture file. */
885 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
886 /* We couldn't open it; fail. */
888 dfilter_free(rfcode);
894 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
895 it closed the previous capture file, and thus destroyed any
896 previous read filter attached to "cf"). */
897 cfile.rfcode = rfcode;
899 switch (cf_read(&cfile, FALSE)) {
903 /* Just because we got an error, that doesn't mean we were unable
904 to read any of the file; we handle what we could get from the
908 case CF_READ_ABORTED:
909 /* The user bailed out of re-reading the capture file; the
910 capture file has been closed - just free the capture file name
911 string and return (without changing the last containing
916 /* Save the name of the containing directory specified in the path name,
917 if any; we can write over cf_merged_name, which is a good thing, given that
918 "get_dirname()" does write over its argument. */
919 s = get_dirname(tmpname);
920 set_last_open_dir(s);
923 #endif /* USE_WIN32_FILE_DIALOGS */
927 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
928 /* If there's unsaved data, let the user save it first.
929 If they cancel out of it, don't merge. */
930 GtkWidget *msg_dialog;
931 gchar *display_basename;
934 if (prefs.gui_ask_unsaved) {
935 if (cfile.is_tempfile || cfile.unsaved_changes) {
936 /* This is a temporary capture file or has unsaved changes; ask the
937 user whether to save the capture. */
938 if (cfile.is_tempfile) {
939 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
940 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
941 GTK_MESSAGE_QUESTION,
943 "Do you want to save the captured packets before merging another capture file into it?");
945 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
946 "A temporary capture file can't be merged.");
949 * Format the message.
951 display_basename = g_filename_display_basename(cfile.filename);
952 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
953 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
954 GTK_MESSAGE_QUESTION,
956 "Do you want to save the changes you've made "
957 "to the capture file \"%s\" before merging another capture file into it?",
959 g_free(display_basename);
960 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
961 "The changes must be saved before the files are merged.");
965 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
966 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
967 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
968 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
970 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
971 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
972 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
973 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
975 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
977 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
978 gtk_widget_destroy(msg_dialog);
982 case GTK_RESPONSE_ACCEPT:
983 /* Save the file but don't close it */
984 do_file_save(&cfile, FALSE);
987 case GTK_RESPONSE_CANCEL:
988 case GTK_RESPONSE_NONE:
989 case GTK_RESPONSE_DELETE_EVENT:
991 /* Don't do the merge. */
998 file_merge_cmd(widget);
1003 do_capture_stop(capture_file *cf)
1005 /* Stop the capture (complete with UI updates). */
1006 capture_stop_cb(NULL, NULL);
1008 /* Now run the main loop until the capture stops and we finish
1009 reading it; we need to run the main loop so we respond to
1010 messages on the sync pipe and the sync pipe being closed. */
1011 while (cf->state == FILE_READ_IN_PROGRESS)
1012 gtk_main_iteration();
1017 do_file_close(capture_file *cf, gboolean from_quit, const char *before_what)
1019 GtkWidget *msg_dialog;
1020 gchar *display_basename;
1022 gboolean capture_in_progress;
1024 if (cf->state == FILE_CLOSED)
1025 return TRUE; /* already closed, nothing to do */
1028 if (cf->state == FILE_READ_IN_PROGRESS) {
1029 /* This is true if we're reading a capture file *or* if we're doing
1030 a live capture. If we're reading a capture file, the main loop
1031 is busy reading packets, and only accepting input from the
1032 progress dialog, so we can't get here, so this means we're
1034 capture_in_progress = TRUE;
1037 capture_in_progress = FALSE;
1039 if (prefs.gui_ask_unsaved) {
1040 if (cf->is_tempfile || capture_in_progress || cf->unsaved_changes) {
1041 /* This is a temporary capture file, or there's a capture in
1042 progress, or the file has unsaved changes; ask the user whether
1043 to save the data. */
1044 if (cf->is_tempfile) {
1045 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1046 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1047 GTK_MESSAGE_QUESTION,
1049 capture_in_progress ?
1050 "Do you want to stop the capture and save the captured packets%s?" :
1051 "Do you want to save the captured packets%s?",
1054 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1055 "Your captured packets will be lost if you don't save them.");
1058 * Format the message.
1060 display_basename = g_filename_display_basename(cf->filename);
1061 if (capture_in_progress) {
1062 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1063 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1064 GTK_MESSAGE_QUESTION,
1066 "Do you want to stop the capture and save the captured packets%s?",
1069 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1070 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1071 GTK_MESSAGE_QUESTION,
1073 "Do you want to save the changes you've made "
1074 "to the capture file \"%s\"%s?",
1075 display_basename, before_what);
1077 g_free(display_basename);
1078 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1079 capture_in_progress ?
1080 "Your captured packets will be lost if you don't save them." :
1081 "Your changes will be lost if you don't save them.");
1085 /* If this is from a Quit operation, use "quit and don't save"
1086 rather than just "don't save". */
1087 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1089 (cf->state == FILE_READ_IN_PROGRESS ?
1090 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1091 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1092 (capture_in_progress ?
1093 WIRESHARK_STOCK_STOP_DONT_SAVE :
1094 WIRESHARK_STOCK_DONT_SAVE)),
1095 GTK_RESPONSE_REJECT);
1096 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1097 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1098 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1099 (capture_in_progress ?
1100 WIRESHARK_STOCK_STOP_SAVE :
1102 GTK_RESPONSE_ACCEPT);
1104 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1105 (capture_in_progress ?
1106 WIRESHARK_STOCK_STOP_SAVE :
1108 GTK_RESPONSE_ACCEPT);
1109 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1110 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1111 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1113 (capture_in_progress ?
1114 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1115 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1116 (capture_in_progress ?
1117 WIRESHARK_STOCK_STOP_DONT_SAVE :
1118 WIRESHARK_STOCK_DONT_SAVE)),
1119 GTK_RESPONSE_REJECT);
1121 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
1123 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1124 gtk_widget_destroy(msg_dialog);
1128 case GTK_RESPONSE_ACCEPT:
1130 /* If there's a capture in progress, we have to stop the capture
1131 and then do the save. */
1132 if (capture_in_progress)
1133 do_capture_stop(cf);
1135 /* Save the file and close it */
1136 do_file_save(cf, TRUE);
1139 case GTK_RESPONSE_REJECT:
1141 /* If there's a capture in progress; we have to stop the capture
1142 and then do the close. */
1143 if (capture_in_progress)
1144 do_capture_stop(cf);
1146 /* Just close the file, discarding changes */
1150 case GTK_RESPONSE_CANCEL:
1151 case GTK_RESPONSE_NONE:
1152 case GTK_RESPONSE_DELETE_EVENT:
1154 /* Don't close the file (and don't stop any capture in progress). */
1155 return FALSE; /* file not closed */
1159 /* unchanged file, just close it */
1163 /* User asked not to be bothered by those prompts, just close it.
1164 XXX - should that apply only to saving temporary files? */
1166 /* If there's a capture in progress, we have to stop the capture
1167 and then do the close. */
1168 if (capture_in_progress)
1169 do_capture_stop(cf);
1173 return TRUE; /* file closed */
1178 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1179 do_file_close(&cfile, FALSE, "");
1184 SAVE_WITHOUT_COMMENTS,
1185 SAVE_IN_ANOTHER_FORMAT,
1187 } check_savability_t;
1189 #define RESPONSE_DISCARD_COMMENTS_AND_SAVE 1
1190 #define RESPONSE_SAVE_IN_ANOTHER_FORMAT 2
1192 static check_savability_t
1193 check_save_with_comments(capture_file *cf)
1195 GtkWidget *msg_dialog;
1198 /* Do we have any comments? */
1199 if (!cf_has_comments(cf)) {
1200 /* No. Let the save happen; no comments to delete. */
1204 /* OK, we have comments. Can we write them out in the file's format?
1206 XXX - for now, we "know" that pcap-ng is the only format for which
1207 we support comments. We should really ask Wiretap what the
1208 format in question supports (and handle different types of
1209 comments, some but not all of which some file formats might
1211 if (cf->cd_t == WTAP_FILE_PCAPNG) {
1212 /* Yes - the file is a pcap-ng file. Let the save happen; we can
1213 save the comments, so no need to delete them. */
1217 /* Is pcap-ng one of the formats in which we can write this file? */
1218 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, cf->linktypes)) {
1219 /* Yes. Ooffer the user a choice of "Save in a format that
1220 supports comments", "Discard comments and save in the
1221 file's own format", or "Cancel", meaning "don't bother
1222 saving the file at all". */
1223 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1224 GTK_DIALOG_DESTROY_WITH_PARENT,
1225 GTK_MESSAGE_QUESTION,
1227 "The capture has comments, but the file's format "
1228 "doesn't support comments. Do you want to save the capture "
1229 "in a format that supports comments, or discard the comments "
1230 "and save in the file's format?");
1232 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1233 "Discard comments and save",
1234 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1236 GTK_RESPONSE_CANCEL,
1237 "Save in another format",
1238 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1241 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1242 "Save in another format",
1243 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1245 GTK_RESPONSE_CANCEL,
1246 "Discard comments and save",
1247 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1250 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1251 RESPONSE_SAVE_IN_ANOTHER_FORMAT);
1253 /* No. Offer the user a choice of "Discard comments and
1254 save in the file's format" or "Cancel". */
1255 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1256 GTK_DIALOG_DESTROY_WITH_PARENT,
1257 GTK_MESSAGE_QUESTION,
1259 "The capture has comments, but no file format in which it "
1260 "can be saved supports comments. Do you want to discard "
1261 "the comments and save in the file's format?");
1263 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1264 "Discard comments and save",
1265 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1267 GTK_RESPONSE_CANCEL,
1270 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1272 GTK_RESPONSE_CANCEL,
1273 "Discard comments and save",
1274 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1277 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1278 GTK_RESPONSE_CANCEL);
1281 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1282 gtk_widget_destroy(msg_dialog);
1286 case RESPONSE_SAVE_IN_ANOTHER_FORMAT:
1287 /* Let the user select another format. */
1288 return SAVE_IN_ANOTHER_FORMAT;
1290 case RESPONSE_DISCARD_COMMENTS_AND_SAVE:
1291 /* Save without the comments and, if that succeeds, delete the
1293 return SAVE_WITHOUT_COMMENTS;
1295 case GTK_RESPONSE_CANCEL:
1296 case GTK_RESPONSE_NONE:
1297 case GTK_RESPONSE_DELETE_EVENT:
1305 * Save the capture file in question, prompting the user for a file
1306 * name to save to if necessary.
1309 do_file_save(capture_file *cf, gboolean dont_reopen)
1312 gboolean discard_comments;
1313 cf_write_status_t status;
1315 if (cf->is_tempfile) {
1316 /* This is a temporary capture file, so saving it means saving
1317 it to a permanent file. Prompt the user for a location
1318 to which to save it. Don't require that the file format
1319 support comments - if it's a temporary capture file, it's
1320 probably pcap-ng, which supports comments and, if it's
1321 not pcap-ng, let the user decide what they want to do
1322 if they've added comments. */
1323 do_file_save_as(cf, FALSE, dont_reopen);
1325 if (cf->unsaved_changes) {
1326 /* This is not a temporary capture file, but it has unsaved
1327 changes, so saving it means doing a "safe save" on top
1328 of the existing file, in the same format - no UI needed
1329 unless the file has comments and the file's format doesn't
1332 If the file has comments, does the file's format support them?
1333 If not, ask the user whether they want to discard the comments
1334 or choose a different format. */
1335 switch (check_save_with_comments(cf)) {
1338 /* The file can be saved in the specified format as is;
1339 just drive on and save in the format they selected. */
1340 discard_comments = FALSE;
1343 case SAVE_WITHOUT_COMMENTS:
1344 /* The file can't be saved in the specified format as is,
1345 but it can be saved without the comments, and the user
1346 said "OK, discard the comments", so save it in the
1347 format they specified without the comments. */
1348 discard_comments = TRUE;
1351 case SAVE_IN_ANOTHER_FORMAT:
1352 /* There are file formats in which we can save this that
1353 support comments, and the user said not to delete the
1354 comments. Do a "Save As" so the user can select
1355 one of those formats and choose a file name. */
1356 do_file_save_as(cf, TRUE, dont_reopen);
1360 /* The user said "forget it". Just return. */
1364 /* Squelch warnings that discard_comments is being used
1366 g_assert_not_reached();
1370 /* XXX - cf->filename might get freed out from under us, because
1371 the code path through which cf_save_packets() goes currently
1372 closes the current file and then opens and reloads the saved file,
1373 so make a copy and free it later. */
1374 fname = g_strdup(cf->filename);
1375 status = cf_save_packets(cf, fname, cf->cd_t, cf->iscompressed,
1376 discard_comments, dont_reopen);
1380 /* The save succeeded; we're done.
1381 If we discarded comments, redraw the packet list to reflect
1382 any packets that no longer have comments. */
1383 if (discard_comments)
1384 new_packet_list_queue_draw();
1387 case CF_WRITE_ERROR:
1388 /* The write failed.
1389 XXX - OK, what do we do now? Let them try a
1390 "Save As", in case they want to try to save to a
1391 different directory r file system? */
1394 case CF_WRITE_ABORTED:
1395 /* The write was aborted; just drive on. */
1400 /* Otherwise just do nothing. */
1405 file_save_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1406 do_file_save(&cfile, FALSE);
1409 /* Attach a list of the valid 'save as' file types to a combo_box by
1410 checking what Wiretap supports. Make the default type the first
1411 in the list. If must_supprt_comments is true, restrict the list
1412 to those formats that support comments (currently, just pcap-ng).
1414 Returns the default file type. */
1416 set_file_type_list(GtkWidget *combo_box, capture_file *cf,
1417 gboolean must_support_comments)
1419 GArray *savable_file_types;
1422 int default_ft = -1;
1424 savable_file_types = wtap_get_savable_file_types(cf->cd_t, cf->linktypes);
1426 if (savable_file_types != NULL) {
1427 /* OK, we have at least one file type we can save this file as.
1428 (If we didn't, we shouldn't have gotten here in the first
1429 place.) Add them all to the combo box. */
1430 for (i = 0; i < savable_file_types->len; i++) {
1431 ft = g_array_index(savable_file_types, int, i);
1432 if (must_support_comments) {
1433 if (ft != WTAP_FILE_PCAPNG)
1436 if (default_ft == -1)
1437 default_ft = ft; /* first file type is the default */
1438 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(combo_box),
1439 wtap_file_type_string(ft),
1440 GINT_TO_POINTER(ft));
1442 g_array_free(savable_file_types, TRUE);
1449 file_select_file_type_cb(GtkWidget *w, gpointer parent_arg)
1451 GtkWidget *parent = parent_arg;
1454 GtkWidget *compressed_cb;
1456 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(parent), E_COMPRESSED_CB_KEY);
1457 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr)) {
1458 /* XXX - this can happen when we clear the list of file types
1459 and then reconstruct it. */
1460 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1461 gtk_widget_set_sensitive(compressed_cb, FALSE);
1464 new_file_type = GPOINTER_TO_INT(ptr);
1466 if (!wtap_dump_can_compress(new_file_type)) {
1467 /* Can't compress this file type; turn off compression and make
1468 the compression checkbox insensitive. */
1469 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1470 gtk_widget_set_sensitive(compressed_cb, FALSE);
1472 gtk_widget_set_sensitive(compressed_cb, TRUE);
1475 static check_savability_t
1476 check_save_as_with_comments(capture_file *cf, GtkWidget *file_chooser_w,
1477 GtkWidget *ft_combo_box)
1480 int selected_file_type;
1481 GtkWidget *msg_dialog;
1483 GtkWidget *compressed_cb;
1484 gboolean compressed;
1486 /* Do we have any comments? */
1487 if (!cf_has_comments(cf)) {
1488 /* No. Let the save happen; no comments to delete. */
1492 /* OK, we have comments. Can we write them out in the selected
1494 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1495 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1497 selected_file_type = GPOINTER_TO_INT(ptr);
1499 /* XXX - for now, we "know" that pcap-ng is the only format for which
1500 we support comments. We should really ask Wiretap what the
1501 format in question supports (and handle different types of
1502 comments, some but not all of which some file formats might
1504 if (selected_file_type == WTAP_FILE_PCAPNG) {
1505 /* Yes - they selected pcap-ng. Let the save happen; we can
1506 save the comments, so no need to delete them. */
1509 /* No. Is pcap-ng one of the formats in which we can write this file? */
1510 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, cf->linktypes)) {
1511 /* Yes. Offer the user a choice of "Save in a format that
1512 supports comments", "Discard comments and save in the
1513 format you selected", or "Cancel", meaning "don't bother
1514 saving the file at all". */
1515 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_chooser_w),
1516 GTK_DIALOG_DESTROY_WITH_PARENT,
1517 GTK_MESSAGE_QUESTION,
1519 "The capture has comments, but the file format you chose "
1520 "doesn't support comments. Do you want to save the capture "
1521 "in a format that supports comments, or discard the comments "
1522 "and save in the format you chose?");
1524 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1525 "Discard comments and save",
1526 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1528 GTK_RESPONSE_CANCEL,
1529 "Save in another format",
1530 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1533 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1534 "Save in another format",
1535 RESPONSE_SAVE_IN_ANOTHER_FORMAT,
1537 GTK_RESPONSE_CANCEL,
1538 "Discard comments and save",
1539 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1542 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1543 RESPONSE_SAVE_IN_ANOTHER_FORMAT);
1545 /* No. Offer the user a choice of "Discard comments and
1546 save in the format you selected" or "Cancel". */
1547 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_chooser_w),
1548 GTK_DIALOG_DESTROY_WITH_PARENT,
1549 GTK_MESSAGE_QUESTION,
1551 "The capture has comments, but no file format in which it "
1552 "can be saved supports comments. Do you want to discard "
1553 "the comments and save in the format you chose?");
1555 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1556 "Discard comments and save",
1557 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1559 GTK_RESPONSE_CANCEL,
1562 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1564 GTK_RESPONSE_CANCEL,
1565 "Discard comments and save",
1566 RESPONSE_DISCARD_COMMENTS_AND_SAVE,
1569 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog),
1570 GTK_RESPONSE_CANCEL);
1573 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1574 gtk_widget_destroy(msg_dialog);
1578 case RESPONSE_SAVE_IN_ANOTHER_FORMAT:
1579 /* OK, the only other format we support is pcap-ng. Make that
1580 the one and only format in the combo box, and return to
1581 let the user continue with the dialog.
1583 XXX - removing all the formats from the combo box will clear
1584 the compressed checkbox; get the current value and restore
1587 XXX - we know pcap-ng can be compressed; if we ever end up
1588 supporting saving comments in a format that *can't* be
1589 compressed, such as NetMon format, we must check this. */
1590 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(file_chooser_w),
1591 E_COMPRESSED_CB_KEY);
1592 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1593 ws_combo_box_clear_text_and_pointer(GTK_COMBO_BOX(ft_combo_box));
1594 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box),
1595 wtap_file_type_string(WTAP_FILE_PCAPNG),
1596 GINT_TO_POINTER(WTAP_FILE_PCAPNG));
1597 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), compressed);
1599 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
1600 return SAVE_IN_ANOTHER_FORMAT;
1602 case RESPONSE_DISCARD_COMMENTS_AND_SAVE:
1603 /* Save without the comments and, if that succeeds, delete the
1605 return SAVE_WITHOUT_COMMENTS;
1607 case GTK_RESPONSE_CANCEL:
1608 case GTK_RESPONSE_NONE:
1609 case GTK_RESPONSE_DELETE_EVENT:
1617 do_file_save_as(capture_file *cf, gboolean must_support_comments,
1618 gboolean dont_reopen)
1620 #ifdef USE_WIN32_FILE_DIALOGS
1621 if (win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)),
1622 cf, must_support_comments, dont_reopen)) {
1623 /* They discarded comments, so redraw the packet details window
1624 to reflect any packets that no longer have comments. */
1625 new_packet_list_queue_draw();
1627 #else /* USE_WIN32_FILE_DIALOGS */
1628 GtkWidget *file_save_as_w;
1629 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *compressed_cb;
1632 gboolean discard_comments;
1634 /* Default to saving in the file's current format. */
1636 /* build the file selection */
1637 file_save_as_w = file_selection_new("Wireshark: Save Capture File As",
1638 FILE_SELECTION_SAVE);
1639 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_save_as_w),
1642 /* Container for each row of widgets */
1644 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1645 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1646 file_selection_set_extra_widget(file_save_as_w, main_vb);
1647 gtk_widget_show(main_vb);
1650 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1651 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1652 gtk_widget_show(ft_hb);
1654 ft_lb = gtk_label_new("File type:");
1655 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1656 gtk_widget_show(ft_lb);
1658 ft_combo_box = ws_combo_box_new_text_and_pointer();
1660 /* Generate the list of file types we can save. */
1661 default_ft = set_file_type_list(ft_combo_box, cf, must_support_comments);
1662 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1663 gtk_widget_show(ft_combo_box);
1664 g_object_set_data(G_OBJECT(file_save_as_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1666 /* compressed - if the file is currently compressed, and the default
1667 file type supports compression, turn the checkbox on */
1668 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1669 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1670 if (cf->iscompressed && wtap_dump_can_compress(default_ft))
1671 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), TRUE);
1672 gtk_widget_show(compressed_cb);
1673 g_object_set_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY, compressed_cb);
1675 /* Ok: now "select" the default filetype which invokes file_select_file_type_cb */
1676 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_select_file_type_cb), file_save_as_w);
1677 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1680 * Loop until the user either selects a file or gives up.
1683 cf_name = file_selection_run(file_save_as_w);
1684 if (cf_name == NULL) {
1685 /* User cancelled or closed the dialog. */
1689 /* If the file has comments, does the format the user selected
1690 support them? If not, ask the user whether they want to
1691 discard the comments or choose a different format. */
1692 switch (check_save_as_with_comments(cf, file_save_as_w, ft_combo_box)) {
1695 /* The file can be saved in the specified format as is;
1696 just drive on and save in the format they selected. */
1697 discard_comments = FALSE;
1700 case SAVE_WITHOUT_COMMENTS:
1701 /* The file can't be saved in the specified format as is,
1702 but it can be saved without the comments, and the user
1703 said "OK, discard the comments", so save it in the
1704 format they specified without the comments. */
1705 discard_comments = TRUE;
1708 case SAVE_IN_ANOTHER_FORMAT:
1709 /* There are file formats in which we can save this that
1710 support comments, and the user said not to delete the
1711 comments. The combo box of file formats has had the
1712 formats that don't support comments trimmed from it,
1713 so run the dialog again, to let the user decide
1714 whether to save in one of those formats or give up. */
1719 /* The user said "forget it". Just get rid of the dialog box
1721 window_destroy(file_save_as_w);
1726 /* If the file exists and it's user-immutable or not writable,
1727 ask the user whether they want to override that. */
1728 if (!file_target_unwritable_ui(file_save_as_w, cf_name)) {
1729 /* They don't. Let them try another file name or cancel. */
1735 /* Attempt to save the file */
1737 switch (file_save_as_cb(file_save_as_w, discard_comments, dont_reopen)) {
1740 /* The save succeeded; we're done.
1741 If we discarded comments, redraw the packet list to reflect
1742 any packets that no longer have comments. */
1743 if (discard_comments)
1744 new_packet_list_queue_draw();
1747 case CF_WRITE_ERROR:
1748 /* The save failed; let the user try again. */
1751 case CF_WRITE_ABORTED:
1752 /* The user aborted the save; just return. */
1756 #endif /* USE_WIN32_FILE_DIALOGS */
1760 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1762 do_file_save_as(&cfile, FALSE, FALSE);
1765 /* all tests ok, we only have to save the file */
1766 /* (and probably continue with a pending operation) */
1767 static cf_write_status_t
1768 file_save_as_cb(GtkWidget *fs, gboolean discard_comments,
1769 gboolean dont_reopen)
1771 GtkWidget *ft_combo_box;
1772 GtkWidget *compressed_cb;
1777 gboolean compressed;
1778 cf_write_status_t status;
1780 /* Hide the file chooser while doing the save. */
1781 gtk_widget_hide(fs);
1783 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1785 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1786 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1788 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1789 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1791 file_type = GPOINTER_TO_INT(ptr);
1792 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1794 /* Write out all the packets to the file with the specified name. */
1795 status = cf_save_packets(&cfile, cf_name, file_type, compressed,
1796 discard_comments, dont_reopen);
1800 /* The write succeeded; get rid of the file selection box. */
1801 /* cf_save_packets() might already closed our dialog! */
1804 /* Save the directory name for future file dialogs. */
1805 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1806 set_last_open_dir(dirname);
1809 case CF_WRITE_ERROR:
1810 /* The write failed.
1811 just leave the file selection box around so that the user can,
1812 after they dismiss the alert box popped up for the error, try
1816 case CF_WRITE_ABORTED:
1817 /* The write was aborted; just get rid of the file selection
1827 file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1829 #ifdef USE_WIN32_FILE_DIALOGS
1830 win32_export_specified_packets_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
1831 #else /* USE_WIN32_FILE_DIALOGS */
1832 GtkWidget *file_export_specified_packets_w;
1833 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *range_tb,
1835 packet_range_t range;
1837 gchar *display_basename;
1838 GtkWidget *msg_dialog;
1840 /* Default to writing out all displayed packets, in the file's current format. */
1842 /* init the packet range */
1843 packet_range_init(&range);
1844 range.process_filtered = TRUE;
1845 range.include_dependents = TRUE;
1847 /* build the file selection */
1848 file_export_specified_packets_w = file_selection_new("Wireshark: Export Specified Packets",
1849 FILE_SELECTION_SAVE);
1850 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_export_specified_packets_w),
1853 /* Container for each row of widgets */
1855 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1856 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1857 file_selection_set_extra_widget(file_export_specified_packets_w, main_vb);
1858 gtk_widget_show(main_vb);
1860 /*** Packet Range frame ***/
1861 range_fr = gtk_frame_new("Packet Range");
1862 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1863 gtk_widget_show(range_fr);
1866 range_tb = range_new(&range, TRUE);
1867 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1868 gtk_widget_show(range_tb);
1871 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1872 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1873 gtk_widget_show(ft_hb);
1875 ft_lb = gtk_label_new("File type:");
1876 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1877 gtk_widget_show(ft_lb);
1879 ft_combo_box = ws_combo_box_new_text_and_pointer();
1881 /* Generate the list of file types we can save. */
1882 set_file_type_list(ft_combo_box, &cfile, FALSE);
1883 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1884 gtk_widget_show(ft_combo_box);
1885 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1887 /* dynamic values in the range frame */
1888 range_update_dynamics(range_tb);
1891 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1892 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1893 gtk_widget_show(compressed_cb);
1894 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_COMPRESSED_CB_KEY, compressed_cb);
1896 /* Ok: now "select" the default filetype which invokes file_select_file_type_cb */
1897 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_select_file_type_cb), file_export_specified_packets_w);
1898 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1901 * Loop until the user either selects a file or gives up.
1904 cf_name = file_selection_run(file_export_specified_packets_w);
1905 if (cf_name == NULL) {
1906 /* User cancelled or closed the dialog. */
1910 /* Check whether the range is valid. */
1911 if (!range_check_validity_modal(file_export_specified_packets_w, &range)) {
1912 /* The range isn't valid; the user was told that, and dismissed
1913 the dialog telling them that, so let them fix the range
1914 and try again, or cancel. */
1920 * Check that we're not going to save on top of the current
1922 * We do it here so we catch all cases ...
1923 * Unfortunately, the file requester gives us an absolute file
1924 * name and the read file name may be relative (if supplied on
1925 * the command line). From Joerg Mayer.
1927 if (files_identical(cfile.filename, cf_name)) {
1928 display_basename = g_filename_display_basename(cf_name);
1929 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_export_specified_packets_w),
1930 GTK_DIALOG_DESTROY_WITH_PARENT,
1933 "The file \"%s\" is the capture file from which you're exporting the packets.",
1935 g_free(display_basename);
1936 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1937 "You cannot export packets on top of the current capture file.");
1938 gtk_dialog_run(GTK_DIALOG(msg_dialog));
1939 gtk_widget_destroy(msg_dialog);
1945 /* If the file exists and it's user-immutable or not writable,
1946 ask the user whether they want to override that. */
1947 if (!file_target_unwritable_ui(file_export_specified_packets_w, cf_name)) {
1948 /* They don't. Let them try another file name or cancel. */
1954 /* attempt to export the packets */
1956 switch (file_export_specified_packets_cb(file_export_specified_packets_w,
1960 /* The save succeeded; we're done. */
1963 case CF_WRITE_ERROR:
1964 /* The save failed; let the user try again */
1967 case CF_WRITE_ABORTED:
1968 /* The user aborted the save; just return. */
1972 #endif /* USE_WIN32_FILE_DIALOGS */
1975 /* all tests ok, we only have to write out the packets */
1976 /* (and probably continue with a pending operation) */
1977 static cf_write_status_t
1978 file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range)
1980 GtkWidget *ft_combo_box;
1981 GtkWidget *compressed_cb;
1986 gboolean compressed;
1987 cf_write_status_t status;
1989 /* Hide the file chooser while we're doing the export. */
1990 gtk_widget_hide(fs);
1992 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1994 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1995 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1997 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1998 g_assert_not_reached(); /* Programming error: somehow nothing is active */
2000 file_type = GPOINTER_TO_INT(ptr);
2001 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
2003 /* Write out the specified packets to the file with the specified name. */
2004 status = cf_export_specified_packets(&cfile, cf_name, range, file_type,
2009 /* The write succeeded; get rid of the file selection box. */
2010 /* cf_export_specified_packets() might already closed our dialog! */
2011 window_destroy(GTK_WIDGET(fs));
2013 /* Save the directory name for future file dialogs.
2014 XXX - should there be separate ones for "Save As" and
2015 "Export Specified Packets"? */
2016 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2017 set_last_open_dir(dirname);
2020 case CF_WRITE_ERROR:
2021 /* The write failed.
2022 just leave the file selection box around so that the user can,
2023 after they dismiss the alert box popped up for the error, try
2027 case CF_WRITE_ABORTED:
2028 /* The write was aborted; just get rid of the file selection
2037 /* Reload a file using the current read and display filters */
2039 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
2043 /******************** Color Filters *********************************/
2045 * Keep a static pointer to the current "Color Export" window, if
2046 * any, so that if somebody tries to do "Export"
2047 * while there's already a "Color Export" window up, we just pop
2048 * up the existing one, rather than creating a new one.
2050 static GtkWidget *file_color_import_w;
2052 /* sets the file path to the global color filter file.
2053 WARNING: called by both the import and the export dialog.
2056 color_global_cb(GtkWidget *widget _U_, gpointer data)
2058 GtkWidget *fs_widget = (GtkWidget *)data;
2061 /* decide what file to open (from dfilter code) */
2062 path = get_datafile_path("colorfilters");
2064 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
2069 /* Import color filters */
2071 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
2073 #ifdef USE_WIN32_FILE_DIALOGS
2074 win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
2075 #else /* USE_WIN32_FILE_DIALOGS */
2076 GtkWidget *main_vb, *cfglobal_but;
2079 /* No Apply button, and "OK" just sets our text widget, it doesn't
2080 activate it (i.e., it doesn't cause us to try to open the file). */
2082 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
2083 FILE_SELECTION_OPEN);
2085 /* Container for each row of widgets */
2086 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2087 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2088 file_selection_set_extra_widget(file_color_import_w, main_vb);
2089 gtk_widget_show(main_vb);
2091 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2092 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
2093 g_signal_connect(cfglobal_but, "clicked",
2094 G_CALLBACK(color_global_cb), file_color_import_w);
2095 gtk_widget_show(cfglobal_but);
2098 * Loop until the user either selects a file or gives up.
2101 cf_name = file_selection_run(file_color_import_w);
2102 if (cf_name == NULL) {
2103 /* User cancelled or closed the dialog. */
2107 /* Try to open the color filter file. */
2108 if (!color_filters_import(cf_name, color_filters)) {
2109 /* We couldn't open it; don't dismiss the open dialog box,
2110 just leave it around so that the user can, after they
2111 dismiss the alert box popped up for the open error,
2117 /* We've crossed the Rubicon; get rid of the file selection box. */
2118 window_destroy(GTK_WIDGET(file_color_import_w));
2120 /* Save the name of the containing directory specified in the path name,
2121 if any; we can write over cf_name, which is a good thing, given that
2122 "get_dirname()" does write over its argument. */
2123 s = get_dirname(cf_name);
2124 set_last_open_dir(s);
2129 #endif /* USE_WIN32_FILE_DIALOGS */
2133 * Set the "Export only selected filters" toggle button as appropriate for
2134 * the current output file type and count of selected filters.
2136 * Called when the "Export" dialog box is created and when the selected
2140 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
2142 /* We can request that only the selected filters be saved only if
2143 there *are* selected filters. */
2144 if (color_selected_count() != 0)
2145 gtk_widget_set_sensitive(cfselect_cb, TRUE);
2147 /* Force the "Export only selected filters" toggle to "false", turn
2148 off the flag it controls. */
2149 color_selected = FALSE;
2150 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2151 gtk_widget_set_sensitive(cfselect_cb, FALSE);
2156 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
2158 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
2162 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
2164 #ifdef USE_WIN32_FILE_DIALOGS
2165 win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
2166 #else /* USE_WIN32_FILE_DIALOGS */
2167 GtkWidget *file_color_export_w;
2168 GtkWidget *main_vb, *cfglobal_but;
2169 GtkWidget *cfselect_cb;
2173 color_selected = FALSE;
2175 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
2176 FILE_SELECTION_SAVE);
2177 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_color_export_w),
2180 /* Container for each row of widgets */
2181 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2182 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2183 file_selection_set_extra_widget(file_color_export_w, main_vb);
2184 gtk_widget_show(main_vb);
2186 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
2187 gtk_container_add(GTK_CONTAINER(main_vb), cfselect_cb);
2188 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2189 g_signal_connect(cfselect_cb, "toggled",
2190 G_CALLBACK(color_toggle_selected_cb), NULL);
2191 gtk_widget_show(cfselect_cb);
2192 color_set_export_selected_sensitive(cfselect_cb);
2194 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2195 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
2196 g_signal_connect(cfglobal_but, "clicked",
2197 G_CALLBACK(color_global_cb), file_color_export_w);
2198 gtk_widget_show(cfglobal_but);
2201 * Loop until the user either selects a file or gives up.
2204 cf_name = file_selection_run(file_color_export_w);
2205 if (cf_name == NULL) {
2206 /* User cancelled or closed the dialog. */
2211 /* If the file exists and it's user-immutable or not writable,
2212 ask the user whether they want to override that. */
2213 if (!file_target_unwritable_ui(file_color_export_w, cf_name)) {
2214 /* They don't. Let them try another file name or cancel. */
2220 /* Write out the filters (all, or only the ones that are currently
2221 displayed or selected) to the file with the specified name. */
2222 if (!color_filters_export(cf_name, filter_list, color_selected)) {
2223 /* The write failed; don't dismiss the open dialog box,
2224 just leave it around so that the user can, after they
2225 dismiss the alert box popped up for the error, try again. */
2230 /* The write succeeded; get rid of the file selection box. */
2231 window_destroy(GTK_WIDGET(file_color_export_w));
2233 /* Save the directory name for future file dialogs. */
2234 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2235 set_last_open_dir(dirname);
2238 #endif /* USE_WIN32_FILE_DIALOGS */
2247 * indent-tabs-mode: nil
2250 * ex: set shiftwidth=2 tabstop=8 expandtab:
2251 * :indentSize=2:tabSize=8:noTabs=true: