2 * Dialog boxes for handling capture files
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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"
43 #include "../alert_box.h"
44 #include "../simple_dialog.h"
46 #include "../ui_util.h"
47 #include "../color_filters.h"
50 #include <wsutil/file_util.h>
52 #include "gtk/gtkglobals.h"
54 #include "gtk/filter_dlg.h"
55 #include "gtk/gui_utils.h"
56 #include "gtk/dlg_utils.h"
57 #include "gtk/file_dlg.h"
58 #include "gtk/capture_file_dlg.h"
59 #include "gtk/drag_and_drop.h"
61 #include "gtk/menus.h"
62 #include "gtk/recent.h"
63 #include "gtk/color_dlg.h"
64 #include "gtk/new_packet_list.h"
66 #include "gtk/capture_dlg.h"
68 #include "gtk/stock_icons.h"
69 #include "gtk/range_utils.h"
70 #include "gtk/filter_autocomplete.h"
73 #include <gdk/gdkwin32.h>
75 #include "win32/file_dlg_win32.h"
79 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
80 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
81 static void file_merge_ok_cb(GtkWidget *w, gpointer fs);
82 static void file_merge_destroy_cb(GtkWidget *win, gpointer user_data);
83 static void file_save_as_select_file_type_cb(GtkWidget *w, gpointer data);
84 static void file_save_as_ok_cb(GtkWidget *w, gpointer fs);
85 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
86 static void file_color_import_ok_cb(GtkWidget *w, gpointer filter_list);
87 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
88 static void file_color_export_ok_cb(GtkWidget *w, gpointer filter_list);
89 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
90 static gint set_file_type_list(GtkWidget *combo_box, int default_file_type);
92 #define E_FILE_TYPE_COMBO_BOX_KEY "file_type_combo_box"
93 #define E_COMPRESSED_CB_KEY "compressed_cb"
95 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
96 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
97 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
99 #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key"
100 #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key"
101 #define E_MERGE_APPEND_KEY "merge_dlg_append_key"
104 #define PREVIEW_TABLE_KEY "preview_table_key"
105 #define PREVIEW_FILENAME_KEY "preview_filename_key"
106 #define PREVIEW_FORMAT_KEY "preview_format_key"
107 #define PREVIEW_SIZE_KEY "preview_size_key"
108 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
109 #define PREVIEW_PACKETS_KEY "preview_packets_key"
110 #define PREVIEW_FIRST_KEY "preview_first_key"
114 * Keep a static pointer to the current "Save Capture File As" window, if
115 * any, so that if somebody tries to do "File:Save" or "File:Save As"
116 * while there's already a "Save Capture File As" window up, we just pop
117 * up the existing one, rather than creating a new one.
119 static GtkWidget *file_save_as_w;
121 /* XXX - can we make these not be static? */
122 static packet_range_t range;
123 static gboolean color_selected;
124 static GtkWidget *range_tb;
126 #define PREVIEW_STR_MAX 200
129 /* set a new filename for the preview widget */
131 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
137 gchar string_buff[PREVIEW_STR_MAX];
141 /* init preview labels */
142 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
143 gtk_label_set_text(GTK_LABEL(label), "-");
144 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
145 gtk_label_set_text(GTK_LABEL(label), "-");
146 label = g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
147 gtk_label_set_text(GTK_LABEL(label), "-");
148 label = g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
149 gtk_label_set_text(GTK_LABEL(label), "-");
150 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
151 gtk_label_set_text(GTK_LABEL(label), "-");
152 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
153 gtk_label_set_text(GTK_LABEL(label), "-");
159 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
160 gtk_label_set_text(GTK_LABEL(label), get_basename(cf_name));
162 if (test_for_directory(cf_name) == EISDIR) {
163 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
164 gtk_label_set_text(GTK_LABEL(label), "directory");
168 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
170 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
171 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
172 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
174 gtk_label_set_text(GTK_LABEL(label), "error opening file");
179 /* Find the size of the file. */
180 filesize = wtap_file_size(wth, &err);
181 if (filesize == -1) {
182 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
186 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize);
187 label = g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
188 gtk_label_set_text(GTK_LABEL(label), string_buff);
191 g_strlcpy(string_buff, wtap_file_type_string(wtap_file_type(wth)), PREVIEW_STR_MAX);
192 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
193 gtk_label_set_text(GTK_LABEL(label), string_buff);
199 /* do a preview run on the currently selected capture file */
201 preview_do(GtkWidget *prev, wtap *wth)
204 unsigned int elapsed_time;
210 const struct wtap_pkthdr *phdr;
211 double start_time = 0; /* seconds, with nsec resolution */
212 double stop_time = 0; /* seconds, with nsec resolution */
214 unsigned int packets = 0;
215 gboolean is_breaked = FALSE;
216 gchar string_buff[PREVIEW_STR_MAX];
222 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
223 phdr = wtap_phdr(wth);
224 cur_time = wtap_nstime_to_sec(&phdr->ts);
226 start_time = cur_time;
227 stop_time = cur_time;
229 if (cur_time < start_time) {
230 start_time = cur_time;
232 if (cur_time > stop_time){
233 stop_time = cur_time;
237 if(packets%1000 == 0) {
238 /* do we have a timeout? */
240 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
248 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
249 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
250 gtk_label_set_text(GTK_LABEL(label), string_buff);
257 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
259 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
261 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
262 gtk_label_set_text(GTK_LABEL(label), string_buff);
265 ti_time = (long)start_time;
266 ti_tm = localtime( &ti_time );
268 g_snprintf(string_buff, PREVIEW_STR_MAX,
269 "%04d-%02d-%02d %02d:%02d:%02d",
270 ti_tm->tm_year + 1900,
277 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
279 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
280 gtk_label_set_text(GTK_LABEL(label), string_buff);
283 elapsed_time = (unsigned int)(stop_time-start_time);
284 if(elapsed_time/86400) {
285 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
286 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
288 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
289 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
292 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
294 label = g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
295 gtk_label_set_text(GTK_LABEL(label), string_buff);
301 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
302 simply use the same layout as in GTK2.0 */
304 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
306 GtkWidget *prev = GTK_WIDGET (data);
308 gboolean have_preview;
310 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
312 have_preview = preview_set_filename(prev, cf_name);
317 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
322 /* the filename text entry changed */
324 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
326 GtkWidget *prev = g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY);
328 gboolean have_preview;
331 /* get the filename */
332 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
334 /* set the filename to the preview */
335 wth = preview_set_filename(prev, cf_name);
336 have_preview = (wth != NULL);
340 /* make the preview widget sensitive */
341 gtk_widget_set_sensitive(prev, have_preview);
344 * XXX - if the Open button isn't sensitive, you can't type into
345 * the location bar and select the file or directory you've typed.
348 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1791
350 * It's not as if allowing users to click Open when they've
351 * selected a file that's not a valid capture file will cause
352 * anything worse than an error dialog, so we'll leave the Open
353 * button sensitive for now. Perhaps making it sensitive if
354 * cf_name is NULL would also work, although I don't know whether
355 * there are any cases where it would be non-null when you've
356 * typed in the location bar.
358 * XXX - Bug 1791 also notes that, with the line removed, Bill
359 * Meier "somehow managed to get the file chooser window somewhat
360 * wedged in that neither the cancel or open buttons were responsive".
361 * That seems a bit odd, given that, without this line, we're not
362 * monkeying with the Open button's sensitivity, but...
365 /* make the open/save/... dialog button sensitive */
367 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
370 /* do the actual preview */
372 preview_do(prev, wth);
376 /* copied from summary_dlg.c */
378 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
383 if(strlen(value) != 0) {
384 indent = g_strdup_printf(" %s", title);
386 indent = g_strdup(title);
388 label = gtk_label_new(indent);
390 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
391 gtk_widget_set_sensitive(label, sensitive);
392 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
394 label = gtk_label_new(value);
395 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
396 gtk_widget_set_sensitive(label, sensitive);
397 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
405 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
407 return add_string_to_table_sensitive(list, row, title, value, TRUE);
415 GtkWidget *table, *label;
418 table = gtk_table_new(1, 2, FALSE);
419 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
420 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
423 label = add_string_to_table(table, &row, "Filename:", "-");
424 gtk_widget_set_size_request(label, DEF_WIDTH/3, -1);
425 g_object_set_data(G_OBJECT(table), PREVIEW_FILENAME_KEY, label);
426 label = add_string_to_table(table, &row, "Format:", "-");
427 g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label);
428 label = add_string_to_table(table, &row, "Size:", "-");
429 g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label);
430 label = add_string_to_table(table, &row, "Packets:", "-");
431 g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label);
432 label = add_string_to_table(table, &row, "First Packet:", "-");
433 g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label);
434 label = add_string_to_table(table, &row, "Elapsed time:", "-");
435 g_object_set_data(G_OBJECT(table), PREVIEW_ELAPSED_KEY, label);
441 * Keep a static pointer to the current "Open Capture File" window, if
442 * any, so that if somebody tries to do "File:Open" while there's already
443 * an "Open Capture File" window up, we just pop up the existing one,
444 * rather than creating a new one.
446 static GtkWidget *file_open_w;
450 file_open_cmd(GtkWidget *w)
453 win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
455 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
456 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
457 /* No Apply button, and "OK" just sets our text widget, it doesn't
458 activate it (i.e., it doesn't cause us to try to open the file). */
459 static construct_args_t args = {
460 "Wireshark: Read Filter",
466 if (file_open_w != NULL) {
467 /* There's already an "Open Capture File" dialog box; reactivate it. */
468 reactivate_window(file_open_w);
472 file_open_w = file_selection_new("Wireshark: Open Capture File",
473 FILE_SELECTION_OPEN);
474 /* it's annoying, that the file chooser dialog is already shown here,
475 so we cannot use the correct gtk_window_set_default_size() to resize it */
476 gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT);
478 switch (prefs.gui_fileopen_style) {
480 case FO_STYLE_LAST_OPENED:
481 /* The user has specified that we should start out in the last directory
482 we looked in. If we've already opened a file, use its containing
483 directory, if we could determine it, as the directory, otherwise
484 use the "last opened" directory saved in the preferences file if
486 /* This is now the default behaviour in file_selection_new() */
489 case FO_STYLE_SPECIFIED:
490 /* The user has specified that we should always start out in a
491 specified directory; if they've specified that directory,
492 start out by showing the files in that dir. */
493 if (prefs.gui_fileopen_dir[0] != '\0')
494 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
499 main_hb = gtk_hbox_new(FALSE, 3);
500 file_selection_set_extra_widget(file_open_w, main_hb);
501 gtk_widget_show(main_hb);
503 /* Container for each row of widgets */
504 main_vb = gtk_vbox_new(FALSE, 3);
505 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
506 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
507 gtk_widget_show(main_vb);
510 filter_hbox = gtk_hbox_new(FALSE, 1);
511 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
512 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
513 gtk_widget_show(filter_hbox);
515 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
516 g_signal_connect(filter_bt, "clicked",
517 G_CALLBACK(display_filter_construct_cb), &args);
518 g_signal_connect(filter_bt, "destroy",
519 G_CALLBACK(filter_button_destroy_cb), NULL);
520 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
521 gtk_widget_show(filter_bt);
522 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
524 filter_te = gtk_entry_new();
525 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
526 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
527 g_signal_connect(filter_te, "changed",
528 G_CALLBACK(filter_te_syntax_check_cb), NULL);
529 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
530 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
531 g_signal_connect(file_open_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
532 colorize_filter_te_as_empty(filter_te);
533 gtk_widget_show(filter_te);
534 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
536 g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te);
538 /* resolve buttons */
539 m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution");
540 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
541 gbl_resolv_flags & RESOLV_MAC);
542 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
543 g_object_set_data(G_OBJECT(file_open_w),
544 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
545 gtk_widget_show(m_resolv_cb);
547 n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution");
548 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
549 gbl_resolv_flags & RESOLV_NETWORK);
550 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
551 gtk_widget_show(n_resolv_cb);
552 g_object_set_data(G_OBJECT(file_open_w), E_FILE_N_RESOLVE_KEY, n_resolv_cb);
553 t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution");
554 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
555 gbl_resolv_flags & RESOLV_TRANSPORT);
556 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
557 gtk_widget_show(t_resolv_cb);
558 g_object_set_data(G_OBJECT(file_open_w), E_FILE_T_RESOLVE_KEY, t_resolv_cb);
560 g_signal_connect(file_open_w, "destroy",
561 G_CALLBACK(file_open_destroy_cb), NULL);
564 prev = preview_new();
565 g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev);
566 gtk_widget_show_all(prev);
567 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
569 g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
570 G_CALLBACK(file_open_entry_changed), file_open_w);
571 file_open_entry_changed(file_open_w, file_open_w);
573 g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY,
574 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
575 if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
577 file_open_ok_cb(file_open_w, file_open_w);
579 else window_destroy(file_open_w);
583 static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
587 /* save file first */
588 file_save_as_cmd(after_save_open_dialog, data);
590 case(ESD_BTN_DONT_SAVE):
594 case(ESD_BTN_CANCEL):
597 g_assert_not_reached();
602 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
605 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
606 /* user didn't save his current file, ask him */
607 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
608 "%sSave capture file before opening a new one?%s\n\n"
609 "If you open a new capture file without saving, your capture data will be discarded.",
610 simple_dialog_primary_start(), simple_dialog_primary_end());
611 simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
613 /* unchanged file, just open a new one */
614 file_open_cmd(widget);
618 /* user pressed "open" button */
620 file_open_ok_cb(GtkWidget *w, gpointer fs) {
622 const gchar *rfilter;
623 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
624 dfilter_t *rfcode = NULL;
627 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
628 filter_te = g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY);
629 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
630 if (!dfilter_compile(rfilter, &rfcode)) {
631 bad_dfilter_alert_box(rfilter);
636 /* Perhaps the user specified a directory instead of a file.
637 Check whether they did. */
638 if (test_for_directory(cf_name) == EISDIR) {
639 /* It's a directory - set the file selection box to display that
640 directory, don't try to open the directory as a capture file. */
641 set_last_open_dir(cf_name);
643 file_selection_set_current_folder(fs, get_last_open_dir());
647 /* Try to open the capture file. */
648 if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
649 /* We couldn't open it; don't dismiss the open dialog box,
650 just leave it around so that the user can, after they
651 dismiss the alert box popped up for the open error,
654 dfilter_free(rfcode);
657 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
658 * as this will prevent the user from closing the now existing error
659 * message, simply close the dialog (this is the best we can do here). */
661 window_destroy(file_open_w);
666 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
667 it closed the previous capture file, and thus destroyed any
668 previous read filter attached to "cf"). */
669 cfile.rfcode = rfcode;
671 /* Set the global resolving variable */
672 gbl_resolv_flags = prefs.name_resolve;
673 m_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_M_RESOLVE_KEY);
674 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
675 gbl_resolv_flags |= RESOLV_MAC;
677 gbl_resolv_flags &= ~RESOLV_MAC;
678 n_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_N_RESOLVE_KEY);
679 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
680 gbl_resolv_flags |= RESOLV_NETWORK;
682 gbl_resolv_flags &= ~RESOLV_NETWORK;
683 t_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_T_RESOLVE_KEY);
684 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
685 gbl_resolv_flags |= RESOLV_TRANSPORT;
687 gbl_resolv_flags &= ~RESOLV_TRANSPORT;
689 /* We've crossed the Rubicon; get rid of the file selection box. */
690 window_destroy(GTK_WIDGET (fs));
692 switch (cf_read(&cfile, FALSE)) {
696 /* Just because we got an error, that doesn't mean we were unable
697 to read any of the file; we handle what we could get from the
701 case CF_READ_ABORTED:
702 /* The user bailed out of re-reading the capture file; the
703 capture file has been closed - just free the capture file name
704 string and return (without changing the last containing
710 /* Save the name of the containing directory specified in the path name,
711 if any; we can write over cf_name, which is a good thing, given that
712 "get_dirname()" does write over its argument. */
713 s = get_dirname(cf_name);
714 set_last_open_dir(s);
720 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
722 /* Note that we no longer have a "Open Capture File" dialog box. */
727 * Keep a static pointer to the current "Merge Capture File" window, if
728 * any, so that if somebody tries to do "File:Merge" while there's already
729 * an "Merge Capture File" window up, we just pop up the existing one,
730 * rather than creating a new one.
732 static GtkWidget *file_merge_w;
734 /* Merge existing with another file */
736 file_merge_cmd(GtkWidget *w)
739 win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
740 new_packet_list_freeze();
741 new_packet_list_thaw();
743 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
744 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
746 int combo_box_item_to_select;
747 /* No Apply button, and "OK" just sets our text widget, it doesn't
748 activate it (i.e., it doesn't cause us to try to open the file). */
749 static construct_args_t args = {
750 "Wireshark: Read Filter",
756 if (file_merge_w != NULL) {
757 /* There's already an "Merge Capture File" dialog box; reactivate it. */
758 reactivate_window(file_merge_w);
762 /* Default to saving all packets, in the file's current format. */
764 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
765 FILE_SELECTION_OPEN);
766 /* it's annoying, that the file chooser dialog is already shown here,
767 so we cannot use the correct gtk_window_set_default_size() to resize it */
768 gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
770 switch (prefs.gui_fileopen_style) {
772 case FO_STYLE_LAST_OPENED:
773 /* The user has specified that we should start out in the last directory
774 we looked in. If we've already opened a file, use its containing
775 directory, if we could determine it, as the directory, otherwise
776 use the "last opened" directory saved in the preferences file if
778 /* This is now the default behaviour in file_selection_new() */
781 case FO_STYLE_SPECIFIED:
782 /* The user has specified that we should always start out in a
783 specified directory; if they've specified that directory,
784 start out by showing the files in that dir. */
785 if (prefs.gui_fileopen_dir[0] != '\0')
786 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
790 main_hb = gtk_hbox_new(FALSE, 3);
791 file_selection_set_extra_widget(file_merge_w, main_hb);
792 gtk_widget_show(main_hb);
794 /* Container for each row of widgets */
795 main_vb = gtk_vbox_new(FALSE, 3);
796 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
797 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
798 gtk_widget_show(main_vb);
802 ft_hb = gtk_hbox_new(FALSE, 3);
803 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
804 gtk_widget_show(ft_hb);
806 ft_lb = gtk_label_new("Merged output file type:");
807 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
808 gtk_widget_show(ft_lb);
810 ft_combo_box = ws_combo_box_new_text_and_pointer();
812 /* Generate the list of file types we can save. */
813 combo_box_item_to_select = set_file_type_list(ft_combo_box, cfile.cd_t);
814 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
815 gtk_widget_show(ft_combo_box);
816 g_object_set_data(G_OBJECT(file_merge_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
817 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), combo_box_item_to_select); /* No callback */
819 filter_hbox = gtk_hbox_new(FALSE, 1);
820 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
821 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
822 gtk_widget_show(filter_hbox);
824 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
825 g_signal_connect(filter_bt, "clicked",
826 G_CALLBACK(display_filter_construct_cb), &args);
827 g_signal_connect(filter_bt, "destroy",
828 G_CALLBACK(filter_button_destroy_cb), NULL);
829 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
830 gtk_widget_show(filter_bt);
831 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
833 filter_te = gtk_entry_new();
834 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
835 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
836 g_signal_connect(filter_te, "changed",
837 G_CALLBACK(filter_te_syntax_check_cb), NULL);
838 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
839 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
840 g_signal_connect(file_merge_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
841 colorize_filter_te_as_empty(filter_te);
842 gtk_widget_show(filter_te);
843 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
845 g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te);
847 prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL,
848 "Prepend packets to existing file");
849 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.");
850 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
851 g_object_set_data(G_OBJECT(file_merge_w),
852 E_MERGE_PREPEND_KEY, prepend_rb);
853 gtk_widget_show(prepend_rb);
855 chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically");
856 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.");
857 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
858 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
859 gtk_widget_show(chrono_rb);
860 g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_CHRONO_KEY, chrono_rb);
862 append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file");
863 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.");
864 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
865 gtk_widget_show(append_rb);
866 g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_APPEND_KEY, append_rb);
868 g_signal_connect(file_merge_w, "destroy",
869 G_CALLBACK(file_merge_destroy_cb), NULL);
872 prev = preview_new();
873 g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev);
874 gtk_widget_show_all(prev);
875 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
877 g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
878 G_CALLBACK(file_open_entry_changed), file_merge_w);
879 file_open_entry_changed(file_merge_w, file_merge_w);
881 g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY,
882 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
883 if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
885 file_merge_ok_cb(file_merge_w, file_merge_w);
887 else window_destroy(file_merge_w);
891 static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
895 /* save file first */
896 file_save_as_cmd(after_save_merge_dialog, data);
898 case(ESD_BTN_CANCEL):
901 g_assert_not_reached();
906 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
909 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
910 /* user didn't saved his current file, ask him */
911 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
912 "%sSave the capture file before merging to another one?%s\n\n"
913 "A temporary capture file can't be merged.",
914 simple_dialog_primary_start(), simple_dialog_primary_end());
915 simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
917 /* unchanged file, just start to merge */
918 file_merge_cmd(widget);
924 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
926 const gchar *rfilter;
927 GtkWidget *ft_combo_box, *filter_te, *rb;
928 dfilter_t *rfcode = NULL;
930 cf_status_t merge_status;
931 char *in_filenames[2];
937 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
938 filter_te = g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY);
939 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
940 if (!dfilter_compile(rfilter, &rfcode)) {
941 bad_dfilter_alert_box(rfilter);
946 ft_combo_box = g_object_get_data(G_OBJECT(w), E_FILE_TYPE_COMBO_BOX_KEY);
947 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
948 g_assert_not_reached(); /* Programming error: somehow nothing is active */
950 file_type = GPOINTER_TO_INT(ptr);
952 /* Perhaps the user specified a directory instead of a file.
953 Check whether they did. */
954 if (test_for_directory(cf_name) == EISDIR) {
955 /* It's a directory - set the file selection box to display that
956 directory, don't try to open the directory as a capture file. */
957 set_last_open_dir(cf_name);
959 file_selection_set_current_folder(fs, get_last_open_dir());
963 /* merge or append the two files */
964 rb = g_object_get_data(G_OBJECT(w), E_MERGE_CHRONO_KEY);
966 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
967 /* chronological order */
968 in_filenames[0] = cfile.filename;
969 in_filenames[1] = cf_name;
970 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
972 rb = g_object_get_data(G_OBJECT(w), E_MERGE_PREPEND_KEY);
973 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
975 in_filenames[0] = cf_name;
976 in_filenames[1] = cfile.filename;
977 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
981 in_filenames[0] = cfile.filename;
982 in_filenames[1] = cf_name;
983 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
990 if (merge_status != CF_OK) {
992 dfilter_free(rfcode);
999 /* We've crossed the Rubicon; get rid of the file selection box. */
1000 window_destroy(GTK_WIDGET (fs));
1002 /* Try to open the merged capture file. */
1003 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
1004 /* We couldn't open it; don't dismiss the open dialog box,
1005 just leave it around so that the user can, after they
1006 dismiss the alert box popped up for the open error,
1009 dfilter_free(rfcode);
1011 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1012 * as this will prevent the user from closing the now existing error
1013 * message, simply close the dialog (this is the best we can do here). */
1015 window_destroy(file_open_w);
1020 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
1021 it closed the previous capture file, and thus destroyed any
1022 previous read filter attached to "cf"). */
1023 cfile.rfcode = rfcode;
1025 switch (cf_read(&cfile, FALSE)) {
1029 /* Just because we got an error, that doesn't mean we were unable
1030 to read any of the file; we handle what we could get from the
1034 case CF_READ_ABORTED:
1035 /* The user bailed out of re-reading the capture file; the
1036 capture file has been closed - just free the capture file name
1037 string and return (without changing the last containing
1042 /* Save the name of the containing directory specified in the path name,
1043 if any; we can write over cf_merged_name, which is a good thing, given that
1044 "get_dirname()" does write over its argument. */
1045 s = get_dirname(tmpname);
1046 set_last_open_dir(s);
1050 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1052 /* Note that we no longer have a "Merge Capture File" dialog box. */
1053 file_merge_w = NULL;
1057 static void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1061 /* save file first */
1062 file_save_as_cmd(after_save_close_file, NULL);
1064 case(ESD_BTN_DONT_SAVE):
1067 case(ESD_BTN_CANCEL):
1070 g_assert_not_reached();
1076 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1079 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1080 /* user didn't saved his current file, ask him */
1081 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1082 "%sSave capture file before closing it?%s\n\n"
1083 "If you close without saving, your capture data will be discarded.",
1084 simple_dialog_primary_start(), simple_dialog_primary_end());
1086 simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
1088 /* unchanged file, just close it */
1094 file_save_cmd_cb(GtkWidget *w, gpointer data) {
1095 /* If the file's already been saved, do nothing. */
1096 if (cfile.user_saved)
1099 /* Do a "Save As". */
1100 file_save_as_cmd_cb(w, data);
1104 can_save_with_wiretap(int ft)
1106 /* To save a file with Wiretap, Wiretap has to handle that format,
1107 and its code to handle that format must be able to write a file
1108 with this file's encapsulation type. */
1109 return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
1113 /* Attach a list of the valid 'save as' file types to a combo_box by
1114 checking what Wiretap supports.
1115 returns: index of default entry
1118 set_file_type_list(GtkWidget *combo_box, int default_file_type)
1122 gint item_to_select;
1124 /* Default to the first supported file type (which should be libpcap)
1125 if this file's current type isn't supported */
1128 /* Check all file types. */
1130 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
1131 if (can_save_with_wiretap(ft)) {
1132 /* OK, we can write it out in this type. */
1133 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(combo_box), wtap_file_type_string(ft), GINT_TO_POINTER(ft));
1134 if (ft == default_file_type) {
1135 /* Default to the same format as the file, if it's supported. */
1136 item_to_select = idx;
1142 return item_to_select;
1146 file_save_as_select_file_type_cb(GtkWidget *w, gpointer data _U_)
1150 GtkWidget *compressed_cb;
1152 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr)) {
1153 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1155 new_file_type = GPOINTER_TO_INT(ptr);
1157 compressed_cb = g_object_get_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY);
1158 gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(new_file_type));
1162 * Update various dynamic parts of the range controls; called from outside
1163 * the file dialog code whenever the packet counts change.
1166 file_save_update_dynamics(void)
1168 if (file_save_as_w == NULL) {
1169 /* We don't currently have a "Save As..." dialog box up. */
1173 range_update_dynamics(range_tb);
1177 action_after_save_e action_after_save_g;
1178 gpointer action_after_save_data_g;
1182 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
1185 win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), action_after_save, action_after_save_data);
1187 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *compressed_cb;
1188 gint combo_box_item_to_select;
1190 if (file_save_as_w != NULL) {
1191 /* There's already an "Save Capture File As" dialog box; reactivate it. */
1192 reactivate_window(file_save_as_w);
1196 /* Default to saving all packets, in the file's current format. */
1198 /* init the packet range */
1199 packet_range_init(&range);
1201 /* build the file selection */
1202 file_save_as_w = file_selection_new ("Wireshark: Save Capture File As",
1203 FILE_SELECTION_SAVE);
1205 /* as the dialog might already be gone, when using this values, we cannot
1206 * set data to the dialog object, but keep global values */
1207 action_after_save_g = action_after_save;
1208 action_after_save_data_g = action_after_save_data;
1210 /* Container for each row of widgets */
1212 main_vb = gtk_vbox_new(FALSE, 5);
1213 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1214 file_selection_set_extra_widget(file_save_as_w, main_vb);
1215 gtk_widget_show(main_vb);
1217 /*** Packet Range frame ***/
1218 range_fr = gtk_frame_new("Packet Range");
1219 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1220 gtk_widget_show(range_fr);
1223 range_tb = range_new(&range);
1224 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1225 gtk_widget_show(range_tb);
1228 ft_hb = gtk_hbox_new(FALSE, 3);
1229 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1230 gtk_widget_show(ft_hb);
1232 ft_lb = gtk_label_new("File type:");
1233 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1234 gtk_widget_show(ft_lb);
1236 ft_combo_box = ws_combo_box_new_text_and_pointer();
1238 /* Generate the list of file types we can save. */
1239 combo_box_item_to_select = set_file_type_list(ft_combo_box, cfile.cd_t);
1240 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1241 gtk_widget_show(ft_combo_box);
1242 g_object_set_data(G_OBJECT(file_save_as_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1244 /* dynamic values in the range frame */
1245 range_update_dynamics(range_tb);
1248 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1249 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1250 /* XXX - disable output compression for now, as this doesn't work with the
1251 * current optimization to simply copy a capture file if it's using the same
1252 * encapsulation ... */
1253 /* the rest of the implementation is just working fine :-( */
1255 gtk_widget_show(compressed_cb);
1257 g_object_set_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY, compressed_cb);
1258 /* Ok: now "select" the default filetype which invokes file_save_as_select_file_type_cb */
1259 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_save_as_select_file_type_cb), NULL);
1260 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), combo_box_item_to_select);
1262 g_signal_connect(file_save_as_w, "destroy",
1263 G_CALLBACK(file_save_as_destroy_cb), NULL);
1265 if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) {
1266 file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1268 window_destroy(file_save_as_w);
1274 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1276 file_save_as_cmd(after_save_no_action, NULL);
1280 /* all tests ok, we only have to save the file */
1281 /* (and probably continue with a pending operation) */
1283 file_save_as_cb(GtkWidget *w _U_, gpointer fs) {
1284 GtkWidget *ft_combo_box;
1285 GtkWidget *compressed_cb;
1291 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1293 compressed_cb = g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1294 ft_combo_box = g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1296 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1297 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1299 file_type = GPOINTER_TO_INT(ptr);
1301 /* XXX - if the user requests to save to an already existing filename, */
1302 /* ask in a dialog if that's intended */
1303 /* currently, cf_save() will simply deny it */
1305 /* Write out the packets (all, or only the ones from the current
1306 range) to the file with the specified name. */
1307 if (cf_save(&cfile, cf_name, &range, file_type,
1308 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb))) != CF_OK) {
1309 /* The write failed; don't dismiss the open dialog box,
1310 just leave it around so that the user can, after they
1311 dismiss the alert box popped up for the error, try again. */
1313 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1314 * as this will prevent the user from closing the now existing error
1315 * message, simply close the dialog (this is the best we can do here). */
1317 window_destroy(GTK_WIDGET (fs));
1321 /* The write succeeded; get rid of the file selection box. */
1322 /* cf_save() might already closed our dialog! */
1324 window_destroy(GTK_WIDGET (fs));
1326 /* Save the directory name for future file dialogs. */
1327 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1328 set_last_open_dir(dirname);
1331 /* we have finished saving, do we have pending things to do? */
1332 switch(action_after_save_g) {
1333 case(after_save_no_action):
1335 case(after_save_open_dialog):
1336 file_open_cmd(action_after_save_data_g);
1338 case(after_save_open_recent_file):
1339 menu_open_recent_file_cmd(action_after_save_data_g);
1341 case(after_save_open_dnd_file):
1342 dnd_open_file_cmd(action_after_save_data_g);
1344 case(after_save_merge_dialog):
1345 file_merge_cmd(action_after_save_data_g);
1348 case(after_save_capture_dialog):
1349 capture_start_confirmed();
1352 case(after_save_close_file):
1355 case(after_save_exit):
1359 g_assert_not_reached();
1362 action_after_save_g = after_save_no_action;
1366 static void file_save_as_exists_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
1370 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data));
1376 file_save_as_cb(NULL, data);
1378 case(ESD_BTN_CANCEL):
1379 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1380 * as this will prevent the user from closing the now existing error
1381 * message, simply close the dialog (this is the best we can do here). */
1383 window_destroy(file_save_as_w);
1386 g_assert_not_reached();
1392 /* user pressed "Save" dialog "Ok" button */
1394 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1398 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1400 /* Perhaps the user specified a directory instead of a file.
1401 Check whether they did. */
1402 if (test_for_directory(cf_name) == EISDIR) {
1403 /* It's a directory - set the file selection box to display that
1404 directory, and leave the selection box displayed. */
1405 set_last_open_dir(cf_name);
1407 file_selection_set_current_folder(fs, get_last_open_dir());
1411 /* Check whether the range is valid. */
1412 if (!range_check_validity(&range)) {
1413 /* The range isn't valid; don't dismiss the open dialog box,
1414 just leave it around so that the user can, after they
1415 dismiss the alert box popped up for the error, try again. */
1417 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1418 * as this will prevent the user from closing the now existing error
1419 * message, simply close the dialog (this is the best we can do here). */
1421 window_destroy(GTK_WIDGET (fs));
1427 * Check that the from file is not the same as to file
1428 * We do it here so we catch all cases ...
1429 * Unfortunately, the file requester gives us an absolute file
1430 * name and the read file name may be relative (if supplied on
1431 * the command line). From Joerg Mayer.
1433 if (files_identical(cfile.filename, cf_name)) {
1434 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1435 "%sCapture file: \"%s\" identical to loaded file!%s\n\n"
1436 "Please choose a different filename.",
1437 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1439 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1440 * as this will prevent the user from closing the now existing error
1441 * message, simply close the dialog (this is the best we can do here). */
1443 window_destroy(GTK_WIDGET (fs));
1448 /* don't show the dialog while saving (or asking) */
1449 gtk_widget_hide(GTK_WIDGET (fs));
1451 /* it the file doesn't exist, simply try to save it */
1452 if (!file_exists(cf_name)) {
1453 file_save_as_cb(NULL, fs);
1458 /* the file exists, ask the user to remove it first */
1459 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
1460 "%sA file named \"%s\" already exists.%s\n\n"
1461 "Do you want to replace it with the capture you are saving?",
1462 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1463 simple_dialog_set_cb(dialog, file_save_as_exists_answered_cb, fs);
1469 file_save_as_destroy(void)
1472 window_destroy(file_save_as_w);
1476 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1478 /* Note that we no longer have a "Save Capture File As" dialog box. */
1479 file_save_as_w = NULL;
1482 /* Reload a file using the current read and display filters */
1484 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1488 /******************** Color Filters *********************************/
1490 * Keep a static pointer to the current "Color Export" window, if
1491 * any, so that if somebody tries to do "Export"
1492 * while there's already a "Color Export" window up, we just pop
1493 * up the existing one, rather than creating a new one.
1495 static GtkWidget *file_color_import_w;
1497 /* sets the file path to the global color filter file.
1498 WARNING: called by both the import and the export dialog.
1501 color_global_cb(GtkWidget *widget _U_, gpointer data)
1503 GtkWidget *fs_widget = data;
1506 /* decide what file to open (from dfilter code) */
1507 path = get_datafile_path("colorfilters");
1509 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1514 /* Import color filters */
1516 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
1519 win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
1521 GtkWidget *main_vb, *cfglobal_but;
1523 /* No Apply button, and "OK" just sets our text widget, it doesn't
1524 activate it (i.e., it doesn't cause us to try to open the file). */
1526 if (file_color_import_w != NULL) {
1527 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1528 reactivate_window(file_color_import_w);
1532 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
1533 FILE_SELECTION_OPEN);
1535 /* Container for each row of widgets */
1536 main_vb = gtk_vbox_new(FALSE, 3);
1537 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1538 file_selection_set_extra_widget(file_color_import_w, main_vb);
1539 gtk_widget_show(main_vb);
1542 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1543 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1544 g_signal_connect(cfglobal_but, "clicked",
1545 G_CALLBACK(color_global_cb), file_color_import_w);
1546 gtk_widget_show(cfglobal_but);
1548 g_signal_connect(file_color_import_w, "destroy",
1549 G_CALLBACK(file_color_import_destroy_cb), NULL);
1552 if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1554 file_color_import_ok_cb(file_color_import_w, color_filters);
1556 else window_destroy(file_color_import_w);
1561 file_color_import_ok_cb(GtkWidget *w, gpointer color_filters) {
1563 GtkWidget *fs = gtk_widget_get_toplevel(w);
1565 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1567 /* Perhaps the user specified a directory instead of a file.
1568 Check whether they did. */
1569 if (test_for_directory(cf_name) == EISDIR) {
1570 /* It's a directory - set the file selection box to display that
1571 directory, don't try to open the directory as a color filter file. */
1572 set_last_open_dir(cf_name);
1574 file_selection_set_current_folder(fs, get_last_open_dir());
1578 /* Try to open the color filter file. */
1580 if (!color_filters_import(cf_name, color_filters)) {
1581 /* We couldn't open it; don't dismiss the open dialog box,
1582 just leave it around so that the user can, after they
1583 dismiss the alert box popped up for the open error,
1586 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1587 * as this will prevent the user from closing the now existing error
1588 * message, simply close the dialog (this is the best we can do here). */
1589 window_destroy(GTK_WIDGET (fs));
1594 /* We've crossed the Rubicon; get rid of the file selection box. */
1595 window_destroy(GTK_WIDGET (fs));
1597 /* Save the name of the containing directory specified in the path name,
1598 if any; we can write over cf_name, which is a good thing, given that
1599 "get_dirname()" does write over its argument. */
1600 s = get_dirname(cf_name);
1601 set_last_open_dir(s);
1607 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1609 /* Note that we no longer have a "Open Capture File" dialog box. */
1610 file_color_import_w = NULL;
1613 static GtkWidget *file_color_export_w;
1615 * Set the "Export only selected filters" toggle button as appropriate for
1616 * the current output file type and count of selected filters.
1618 * Called when the "Export" dialog box is created and when the selected
1622 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
1624 if (file_color_export_w == NULL) {
1625 /* We don't currently have an "Export" dialog box up. */
1629 /* We can request that only the selected filters be saved only if
1630 there *are* selected filters. */
1631 if (color_selected_count() != 0)
1632 gtk_widget_set_sensitive(cfselect_cb, TRUE);
1634 /* Force the "Export only selected filters" toggle to "false", turn
1635 off the flag it controls. */
1636 color_selected = FALSE;
1637 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
1638 gtk_widget_set_sensitive(cfselect_cb, FALSE);
1643 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
1645 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1649 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
1652 win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
1654 GtkWidget *main_vb, *cfglobal_but;
1655 GtkWidget *cfselect_cb;
1657 if (file_color_export_w != NULL) {
1658 /* There's already an "Color Filter Export" dialog box; reactivate it. */
1659 reactivate_window(file_color_export_w);
1663 color_selected = FALSE;
1665 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
1666 FILE_SELECTION_SAVE);
1668 /* Container for each row of widgets */
1669 main_vb = gtk_vbox_new(FALSE, 3);
1670 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1671 file_selection_set_extra_widget(file_color_export_w, main_vb);
1672 gtk_widget_show(main_vb);
1674 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
1675 gtk_container_add(GTK_CONTAINER(main_vb), cfselect_cb);
1676 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
1677 g_signal_connect(cfselect_cb, "toggled",
1678 G_CALLBACK(color_toggle_selected_cb), NULL);
1679 gtk_widget_show(cfselect_cb);
1680 color_set_export_selected_sensitive(cfselect_cb);
1682 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1683 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1684 g_signal_connect(cfglobal_but, "clicked",
1685 G_CALLBACK(color_global_cb), file_color_export_w);
1686 gtk_widget_show(cfglobal_but);
1688 g_signal_connect(file_color_export_w, "destroy",
1689 G_CALLBACK(file_color_export_destroy_cb), NULL);
1691 if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1693 file_color_export_ok_cb(file_color_export_w, filter_list);
1695 else window_destroy(file_color_export_w);
1700 file_color_export_ok_cb(GtkWidget *w, gpointer filter_list) {
1703 GtkWidget *fs = gtk_widget_get_toplevel(w);
1705 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1707 /* Perhaps the user specified a directory instead of a file.
1708 Check whether they did. */
1709 if (test_for_directory(cf_name) == EISDIR) {
1710 /* It's a directory - set the file selection box to display that
1711 directory, and leave the selection box displayed. */
1712 set_last_open_dir(cf_name);
1714 file_selection_set_current_folder(fs, get_last_open_dir());
1718 /* Write out the filters (all, or only the ones that are currently
1719 displayed or selected) to the file with the specified name. */
1721 if (!color_filters_export(cf_name, filter_list, color_selected))
1723 /* The write failed; don't dismiss the open dialog box,
1724 just leave it around so that the user can, after they
1725 dismiss the alert box popped up for the error, try again. */
1728 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1729 * as this will prevent the user from closing the now existing error
1730 * message, simply close the dialog (this is the best we can do here). */
1731 window_destroy(GTK_WIDGET (fs));
1736 /* The write succeeded; get rid of the file selection box. */
1737 window_destroy(GTK_WIDGET (fs));
1739 /* Save the directory name for future file dialogs. */
1740 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1741 set_last_open_dir(dirname);
1746 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1748 file_color_export_w = NULL;