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"
44 #include "../color_filters.h"
47 #include <wsutil/file_util.h>
49 #include "ui/alert_box.h"
50 #include "ui/last_open_dir.h"
51 #include "ui/recent.h"
52 #include "ui/simple_dialog.h"
53 #include "ui/ui_util.h"
55 #include "ui/gtk/gtkglobals.h"
56 #include "ui/gtk/keys.h"
57 #include "ui/gtk/filter_dlg.h"
58 #include "ui/gtk/gui_utils.h"
59 #include "ui/gtk/dlg_utils.h"
60 #include "ui/gtk/file_dlg.h"
61 #include "ui/gtk/capture_file_dlg.h"
62 #include "ui/gtk/drag_and_drop.h"
63 #include "ui/gtk/main.h"
64 #include "ui/gtk/color_dlg.h"
65 #include "ui/gtk/new_packet_list.h"
67 #include "ui/gtk/capture_dlg.h"
69 #include "ui/gtk/stock_icons.h"
70 #include "ui/gtk/range_utils.h"
71 #include "ui/gtk/filter_autocomplete.h"
74 #include <gdk/gdkwin32.h>
76 #include "ui/win32/file_dlg_win32.h"
80 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
81 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
82 static void file_merge_ok_cb(GtkWidget *w, gpointer fs);
83 static void file_merge_destroy_cb(GtkWidget *win, gpointer user_data);
84 static void do_file_save(capture_file *cf, gboolean dont_reopen);
85 static void do_file_save_as(capture_file *cf);
86 static void file_save_as_cb(GtkWidget *fs);
87 static void file_save_as_select_file_type_cb(GtkWidget *w, gpointer data);
88 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
89 static void file_export_specified_packets_cb(GtkWidget *w, gpointer fs);
90 static void file_export_specified_packets_select_file_type_cb(GtkWidget *w, gpointer data);
91 static void file_export_specified_packets_ok_cb(GtkWidget *w, gpointer fs);
92 static void file_export_specified_packets_destroy_cb(GtkWidget *win, gpointer user_data);
93 static void file_color_import_ok_cb(GtkWidget *w, gpointer filter_list);
94 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
95 static void file_color_export_ok_cb(GtkWidget *w, gpointer filter_list);
96 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
97 static void set_file_type_list(GtkWidget *combo_box, capture_file *cf);
99 #define E_FILE_TYPE_COMBO_BOX_KEY "file_type_combo_box"
100 #define E_COMPRESSED_CB_KEY "compressed_cb"
102 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
103 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
104 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
106 #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key"
107 #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key"
108 #define E_MERGE_APPEND_KEY "merge_dlg_append_key"
111 #define PREVIEW_TABLE_KEY "preview_table_key"
112 #define PREVIEW_FILENAME_KEY "preview_filename_key"
113 #define PREVIEW_FORMAT_KEY "preview_format_key"
114 #define PREVIEW_SIZE_KEY "preview_size_key"
115 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
116 #define PREVIEW_PACKETS_KEY "preview_packets_key"
117 #define PREVIEW_FIRST_KEY "preview_first_key"
121 * Keep a static pointer to the current "Save Capture File As" window, if
122 * any, so that if somebody tries to do "File:Save" or "File:Save As"
123 * while there's already a "Save Capture File As" window up, we just pop
124 * up the existing one, rather than creating a new one.
126 static GtkWidget *file_save_as_w;
129 * Keep a static pointer to the current "Export Specified Packets" window, if
130 * any, so that if somebody tries to do "File:Export Specified Packets"
131 * while there's already a "Export Specified Packets" window up, we just pop
132 * up the existing one, rather than creating a new one.
134 static GtkWidget *file_export_specified_packets_w;
136 /* XXX - can we make these not be static? */
137 static packet_range_t range;
138 static gboolean color_selected;
139 static GtkWidget *range_tb;
141 #define PREVIEW_STR_MAX 200
144 /* set a new filename for the preview widget */
146 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
149 gchar *display_basename;
153 gchar string_buff[PREVIEW_STR_MAX];
157 /* init preview labels */
158 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
159 gtk_label_set_text(GTK_LABEL(label), "-");
160 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
161 gtk_label_set_text(GTK_LABEL(label), "-");
162 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
163 gtk_label_set_text(GTK_LABEL(label), "-");
164 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
165 gtk_label_set_text(GTK_LABEL(label), "-");
166 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
167 gtk_label_set_text(GTK_LABEL(label), "-");
168 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
169 gtk_label_set_text(GTK_LABEL(label), "-");
175 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
176 display_basename = g_filename_display_basename(cf_name);
177 gtk_label_set_text(GTK_LABEL(label), display_basename);
178 g_free(display_basename);
180 if (test_for_directory(cf_name) == EISDIR) {
181 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
182 gtk_label_set_text(GTK_LABEL(label), "directory");
186 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
188 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
189 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
190 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
192 gtk_label_set_text(GTK_LABEL(label), "error opening file");
197 /* Find the size of the file. */
198 filesize = wtap_file_size(wth, &err);
199 if (filesize == -1) {
200 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
204 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize);
205 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
206 gtk_label_set_text(GTK_LABEL(label), string_buff);
209 g_strlcpy(string_buff, wtap_file_type_string(wtap_file_type(wth)), PREVIEW_STR_MAX);
210 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
211 gtk_label_set_text(GTK_LABEL(label), string_buff);
217 /* do a preview run on the currently selected capture file */
219 preview_do(GtkWidget *prev, wtap *wth)
222 unsigned int elapsed_time;
228 const struct wtap_pkthdr *phdr;
229 double start_time = 0; /* seconds, with nsec resolution */
230 double stop_time = 0; /* seconds, with nsec resolution */
232 unsigned int packets = 0;
233 gboolean is_breaked = FALSE;
234 gchar string_buff[PREVIEW_STR_MAX];
240 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
241 phdr = wtap_phdr(wth);
242 cur_time = wtap_nstime_to_sec(&phdr->ts);
244 start_time = cur_time;
245 stop_time = cur_time;
247 if (cur_time < start_time) {
248 start_time = cur_time;
250 if (cur_time > stop_time){
251 stop_time = cur_time;
255 if(packets%1000 == 0) {
256 /* do we have a timeout? */
258 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
266 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
267 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
268 gtk_label_set_text(GTK_LABEL(label), string_buff);
275 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
277 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
279 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
280 gtk_label_set_text(GTK_LABEL(label), string_buff);
283 ti_time = (long)start_time;
284 ti_tm = localtime( &ti_time );
286 g_snprintf(string_buff, PREVIEW_STR_MAX,
287 "%04d-%02d-%02d %02d:%02d:%02d",
288 ti_tm->tm_year + 1900,
295 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
297 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
298 gtk_label_set_text(GTK_LABEL(label), string_buff);
301 elapsed_time = (unsigned int)(stop_time-start_time);
302 if(elapsed_time/86400) {
303 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
304 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
306 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
307 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
310 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
312 label = (GtkWidget *)g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
313 gtk_label_set_text(GTK_LABEL(label), string_buff);
319 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
320 simply use the same layout as in GTK2.0 */
322 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
324 GtkWidget *prev = GTK_WIDGET (data);
326 gboolean have_preview;
328 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
330 have_preview = preview_set_filename(prev, cf_name);
335 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
340 /* the filename text entry changed */
342 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
344 GtkWidget *prev = (GtkWidget *)g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY);
346 gboolean have_preview;
349 /* get the filename */
350 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
352 /* set the filename to the preview */
353 wth = preview_set_filename(prev, cf_name);
354 have_preview = (wth != NULL);
358 /* make the preview widget sensitive */
359 gtk_widget_set_sensitive(prev, have_preview);
362 * XXX - if the Open button isn't sensitive, you can't type into
363 * the location bar and select the file or directory you've typed.
366 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1791
368 * It's not as if allowing users to click Open when they've
369 * selected a file that's not a valid capture file will cause
370 * anything worse than an error dialog, so we'll leave the Open
371 * button sensitive for now. Perhaps making it sensitive if
372 * cf_name is NULL would also work, although I don't know whether
373 * there are any cases where it would be non-null when you've
374 * typed in the location bar.
376 * XXX - Bug 1791 also notes that, with the line removed, Bill
377 * Meier "somehow managed to get the file chooser window somewhat
378 * wedged in that neither the cancel or open buttons were responsive".
379 * That seems a bit odd, given that, without this line, we're not
380 * monkeying with the Open button's sensitivity, but...
383 /* make the open/save/... dialog button sensitive */
385 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
388 /* do the actual preview */
390 preview_do(prev, wth);
394 /* copied from summary_dlg.c */
396 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
401 if(strlen(value) != 0) {
402 indent = g_strdup_printf(" %s", title);
404 indent = g_strdup(title);
406 label = gtk_label_new(indent);
408 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
409 gtk_widget_set_sensitive(label, sensitive);
410 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
412 label = gtk_label_new(value);
413 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
414 gtk_widget_set_sensitive(label, sensitive);
415 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
423 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
425 return add_string_to_table_sensitive(list, row, title, value, TRUE);
433 GtkWidget *table, *label;
436 table = gtk_table_new(1, 2, FALSE);
437 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
438 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
441 label = add_string_to_table(table, &row, "Filename:", "-");
442 gtk_widget_set_size_request(label, DEF_WIDTH/3, -1);
443 g_object_set_data(G_OBJECT(table), PREVIEW_FILENAME_KEY, label);
444 label = add_string_to_table(table, &row, "Format:", "-");
445 g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label);
446 label = add_string_to_table(table, &row, "Size:", "-");
447 g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label);
448 label = add_string_to_table(table, &row, "Packets:", "-");
449 g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label);
450 label = add_string_to_table(table, &row, "First Packet:", "-");
451 g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label);
452 label = add_string_to_table(table, &row, "Elapsed time:", "-");
453 g_object_set_data(G_OBJECT(table), PREVIEW_ELAPSED_KEY, label);
459 * Keep a static pointer to the current "Open Capture File" window, if
460 * any, so that if somebody tries to do "File:Open" while there's already
461 * an "Open Capture File" window up, we just pop up the existing one,
462 * rather than creating a new one.
464 static GtkWidget *file_open_w;
468 file_open_cmd(GtkWidget *w)
471 win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
473 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
474 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
475 /* No Apply button, and "OK" just sets our text widget, it doesn't
476 activate it (i.e., it doesn't cause us to try to open the file). */
477 static construct_args_t args = {
478 "Wireshark: Read Filter",
484 if (file_open_w != NULL) {
485 /* There's already an "Open Capture File" dialog box; reactivate it. */
486 reactivate_window(file_open_w);
490 file_open_w = file_selection_new("Wireshark: Open Capture File",
491 FILE_SELECTION_OPEN);
492 /* it's annoying, that the file chooser dialog is already shown here,
493 so we cannot use the correct gtk_window_set_default_size() to resize it */
494 gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT);
496 switch (prefs.gui_fileopen_style) {
498 case FO_STYLE_LAST_OPENED:
499 /* The user has specified that we should start out in the last directory
500 we looked in. If we've already opened a file, use its containing
501 directory, if we could determine it, as the directory, otherwise
502 use the "last opened" directory saved in the preferences file if
504 /* This is now the default behaviour in file_selection_new() */
507 case FO_STYLE_SPECIFIED:
508 /* The user has specified that we should always start out in a
509 specified directory; if they've specified that directory,
510 start out by showing the files in that dir. */
511 if (prefs.gui_fileopen_dir[0] != '\0')
512 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
517 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
518 file_selection_set_extra_widget(file_open_w, main_hb);
519 gtk_widget_show(main_hb);
521 /* Container for each row of widgets */
522 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
523 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
524 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
525 gtk_widget_show(main_vb);
528 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
529 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
530 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
531 gtk_widget_show(filter_hbox);
533 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
534 g_signal_connect(filter_bt, "clicked",
535 G_CALLBACK(display_filter_construct_cb), &args);
536 g_signal_connect(filter_bt, "destroy",
537 G_CALLBACK(filter_button_destroy_cb), NULL);
538 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
539 gtk_widget_show(filter_bt);
540 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
542 filter_te = gtk_entry_new();
543 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
544 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
545 g_signal_connect(filter_te, "changed",
546 G_CALLBACK(filter_te_syntax_check_cb), NULL);
547 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
548 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
549 g_signal_connect(file_open_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
550 colorize_filter_te_as_empty(filter_te);
551 gtk_widget_show(filter_te);
552 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
554 g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te);
556 /* resolve buttons */
557 m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution");
558 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
559 gbl_resolv_flags & RESOLV_MAC);
560 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
561 g_object_set_data(G_OBJECT(file_open_w),
562 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
563 gtk_widget_show(m_resolv_cb);
565 n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution");
566 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
567 gbl_resolv_flags & RESOLV_NETWORK);
568 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
569 gtk_widget_show(n_resolv_cb);
570 g_object_set_data(G_OBJECT(file_open_w), E_FILE_N_RESOLVE_KEY, n_resolv_cb);
571 t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution");
572 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
573 gbl_resolv_flags & RESOLV_TRANSPORT);
574 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
575 gtk_widget_show(t_resolv_cb);
576 g_object_set_data(G_OBJECT(file_open_w), E_FILE_T_RESOLVE_KEY, t_resolv_cb);
578 g_signal_connect(file_open_w, "destroy",
579 G_CALLBACK(file_open_destroy_cb), NULL);
582 prev = preview_new();
583 g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev);
584 gtk_widget_show_all(prev);
585 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
587 g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
588 G_CALLBACK(file_open_entry_changed), file_open_w);
589 file_open_entry_changed(file_open_w, file_open_w);
591 g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY,
592 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
593 if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
595 file_open_ok_cb(file_open_w, file_open_w);
597 else window_destroy(file_open_w);
602 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
603 /* If there's unsaved data, let the user save it first.
604 If they cancel out of it, don't quit. */
605 if (do_file_close(&cfile, FALSE, " before opening a new capture file"))
606 file_open_cmd(widget);
609 /* user pressed "open" button */
611 file_open_ok_cb(GtkWidget *w, gpointer fs) {
613 const gchar *rfilter;
614 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
615 dfilter_t *rfcode = NULL;
618 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
619 filter_te = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY);
620 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
621 if (!dfilter_compile(rfilter, &rfcode)) {
622 bad_dfilter_alert_box(rfilter);
627 /* Perhaps the user specified a directory instead of a file.
628 Check whether they did. */
629 if (test_for_directory(cf_name) == EISDIR) {
630 /* It's a directory - set the file selection box to display that
631 directory, don't try to open the directory as a capture file. */
632 set_last_open_dir(cf_name);
634 file_selection_set_current_folder(fs, get_last_open_dir());
638 /* Try to open the capture file. */
639 if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
640 /* We couldn't open it; don't dismiss the open dialog box,
641 just leave it around so that the user can, after they
642 dismiss the alert box popped up for the open error,
645 dfilter_free(rfcode);
648 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
649 * as this will prevent the user from closing the now existing error
650 * message, simply close the dialog (this is the best we can do here). */
652 window_destroy(file_open_w);
657 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
658 it closed the previous capture file, and thus destroyed any
659 previous read filter attached to "cf"). */
660 cfile.rfcode = rfcode;
662 /* Set the global resolving variable */
663 gbl_resolv_flags = prefs.name_resolve;
664 m_resolv_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_FILE_M_RESOLVE_KEY);
665 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
666 gbl_resolv_flags |= RESOLV_MAC;
668 gbl_resolv_flags &= ~RESOLV_MAC;
669 n_resolv_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_FILE_N_RESOLVE_KEY);
670 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
671 gbl_resolv_flags |= RESOLV_NETWORK;
673 gbl_resolv_flags &= ~RESOLV_NETWORK;
674 t_resolv_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_FILE_T_RESOLVE_KEY);
675 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
676 gbl_resolv_flags |= RESOLV_TRANSPORT;
678 gbl_resolv_flags &= ~RESOLV_TRANSPORT;
680 /* We've crossed the Rubicon; get rid of the file selection box. */
681 window_destroy(GTK_WIDGET (fs));
683 switch (cf_read(&cfile, FALSE)) {
687 /* Just because we got an error, that doesn't mean we were unable
688 to read any of the file; we handle what we could get from the
692 case CF_READ_ABORTED:
693 /* The user bailed out of re-reading the capture file; the
694 capture file has been closed - just free the capture file name
695 string and return (without changing the last containing
701 /* Save the name of the containing directory specified in the path name,
702 if any; we can write over cf_name, which is a good thing, given that
703 "get_dirname()" does write over its argument. */
704 s = get_dirname(cf_name);
705 set_last_open_dir(s);
711 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
713 /* Note that we no longer have a "Open Capture File" dialog box. */
718 * Keep a static pointer to the current "Merge Capture File" window, if
719 * any, so that if somebody tries to do "File:Merge" while there's already
720 * an "Merge Capture File" window up, we just pop up the existing one,
721 * rather than creating a new one.
723 static GtkWidget *file_merge_w;
725 /* Merge existing with another file */
727 file_merge_cmd(GtkWidget *w)
730 win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
731 new_packet_list_freeze();
732 new_packet_list_thaw();
734 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
735 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
738 /* No Apply button, and "OK" just sets our text widget, it doesn't
739 activate it (i.e., it doesn't cause us to try to open the file). */
740 static construct_args_t args = {
741 "Wireshark: Read Filter",
747 if (file_merge_w != NULL) {
748 /* There's already an "Merge Capture File" dialog box; reactivate it. */
749 reactivate_window(file_merge_w);
753 /* Default to saving all packets, in the file's current format. */
755 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
756 FILE_SELECTION_OPEN);
757 /* it's annoying, that the file chooser dialog is already shown here,
758 so we cannot use the correct gtk_window_set_default_size() to resize it */
759 gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
761 switch (prefs.gui_fileopen_style) {
763 case FO_STYLE_LAST_OPENED:
764 /* The user has specified that we should start out in the last directory
765 we looked in. If we've already opened a file, use its containing
766 directory, if we could determine it, as the directory, otherwise
767 use the "last opened" directory saved in the preferences file if
769 /* This is now the default behaviour in file_selection_new() */
772 case FO_STYLE_SPECIFIED:
773 /* The user has specified that we should always start out in a
774 specified directory; if they've specified that directory,
775 start out by showing the files in that dir. */
776 if (prefs.gui_fileopen_dir[0] != '\0')
777 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
781 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
782 file_selection_set_extra_widget(file_merge_w, main_hb);
783 gtk_widget_show(main_hb);
785 /* Container for each row of widgets */
786 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
787 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
788 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
789 gtk_widget_show(main_vb);
793 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
794 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
795 gtk_widget_show(ft_hb);
797 ft_lb = gtk_label_new("Merged output file type:");
798 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
799 gtk_widget_show(ft_lb);
801 ft_combo_box = ws_combo_box_new_text_and_pointer();
803 /* Generate the list of file types we can save. */
804 set_file_type_list(ft_combo_box, &cfile);
805 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
806 gtk_widget_show(ft_combo_box);
807 g_object_set_data(G_OBJECT(file_merge_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
808 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0); /* No callback */
810 filter_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
811 gtk_container_set_border_width(GTK_CONTAINER(filter_hbox), 0);
812 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
813 gtk_widget_show(filter_hbox);
815 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
816 g_signal_connect(filter_bt, "clicked",
817 G_CALLBACK(display_filter_construct_cb), &args);
818 g_signal_connect(filter_bt, "destroy",
819 G_CALLBACK(filter_button_destroy_cb), NULL);
820 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
821 gtk_widget_show(filter_bt);
822 gtk_widget_set_tooltip_text(filter_bt, "Open the \"Display Filter\" dialog, to edit/apply filters");
824 filter_te = gtk_entry_new();
825 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
826 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
827 g_signal_connect(filter_te, "changed",
828 G_CALLBACK(filter_te_syntax_check_cb), NULL);
829 g_object_set_data(G_OBJECT(filter_hbox), E_FILT_AUTOCOMP_PTR_KEY, NULL);
830 g_signal_connect(filter_te, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
831 g_signal_connect(file_merge_w, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
832 colorize_filter_te_as_empty(filter_te);
833 gtk_widget_show(filter_te);
834 gtk_widget_set_tooltip_text(filter_te, "Enter a display filter.");
836 g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te);
838 prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL,
839 "Prepend packets to existing file");
840 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.");
841 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
842 g_object_set_data(G_OBJECT(file_merge_w),
843 E_MERGE_PREPEND_KEY, prepend_rb);
844 gtk_widget_show(prepend_rb);
846 chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically");
847 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.");
848 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
849 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
850 gtk_widget_show(chrono_rb);
851 g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_CHRONO_KEY, chrono_rb);
853 append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file");
854 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.");
855 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
856 gtk_widget_show(append_rb);
857 g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_APPEND_KEY, append_rb);
859 g_signal_connect(file_merge_w, "destroy",
860 G_CALLBACK(file_merge_destroy_cb), NULL);
863 prev = preview_new();
864 g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev);
865 gtk_widget_show_all(prev);
866 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
868 g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
869 G_CALLBACK(file_open_entry_changed), file_merge_w);
870 file_open_entry_changed(file_merge_w, file_merge_w);
872 g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY,
873 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
874 if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
876 file_merge_ok_cb(file_merge_w, file_merge_w);
878 else window_destroy(file_merge_w);
883 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
884 /* If there's unsaved data, let the user save it first.
885 If they cancel out of it, don't merge. */
886 GtkWidget *msg_dialog;
887 gchar *display_basename;
890 if (prefs.gui_ask_unsaved) {
891 if (cfile.is_tempfile || cfile.unsaved_changes) {
892 /* This is a temporary capture file or has unsaved changes; ask the
893 user whether to save the capture. */
894 if (cfile.is_tempfile) {
895 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
896 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
897 GTK_MESSAGE_QUESTION,
899 "Do you want to save the captured packets before merging another capture file into it?");
901 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
902 "A temporary capture file can't be merged.");
905 * Format the message.
907 display_basename = g_filename_display_basename(cfile.filename);
908 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
909 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
910 GTK_MESSAGE_QUESTION,
912 "Do you want to save the changes you've made "
913 "to the capture file \"%s\" before merging another capture file into it?",
915 g_free(display_basename);
916 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
917 "The changes must be saved before the files are merged.");
921 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
922 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
923 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
924 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
926 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
927 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
928 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
929 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
931 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
933 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
934 gtk_widget_destroy(msg_dialog);
938 case GTK_RESPONSE_ACCEPT:
939 /* Save the file but don't close it */
940 do_file_save(&cfile, FALSE);
943 case GTK_RESPONSE_CANCEL:
944 case GTK_RESPONSE_NONE:
945 case GTK_RESPONSE_DELETE_EVENT:
947 /* Don't do the merge. */
954 file_merge_cmd(widget);
959 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
961 const gchar *rfilter;
962 GtkWidget *ft_combo_box, *filter_te, *rb;
963 dfilter_t *rfcode = NULL;
965 cf_status_t merge_status;
966 char *in_filenames[2];
972 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
973 filter_te = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY);
974 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
975 if (!dfilter_compile(rfilter, &rfcode)) {
976 bad_dfilter_alert_box(rfilter);
981 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_FILE_TYPE_COMBO_BOX_KEY);
982 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
983 g_assert_not_reached(); /* Programming error: somehow nothing is active */
985 file_type = GPOINTER_TO_INT(ptr);
987 /* Perhaps the user specified a directory instead of a file.
988 Check whether they did. */
989 if (test_for_directory(cf_name) == EISDIR) {
990 /* It's a directory - set the file selection box to display that
991 directory, don't try to open the directory as a capture file. */
992 set_last_open_dir(cf_name);
994 file_selection_set_current_folder(fs, get_last_open_dir());
998 /* merge or append the two files */
999 rb = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_MERGE_CHRONO_KEY);
1001 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1002 /* chronological order */
1003 in_filenames[0] = cfile.filename;
1004 in_filenames[1] = cf_name;
1005 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
1007 rb = (GtkWidget *)g_object_get_data(G_OBJECT(w), E_MERGE_PREPEND_KEY);
1008 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1010 in_filenames[0] = cf_name;
1011 in_filenames[1] = cfile.filename;
1012 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
1016 in_filenames[0] = cfile.filename;
1017 in_filenames[1] = cf_name;
1018 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type,
1025 if (merge_status != CF_OK) {
1027 dfilter_free(rfcode);
1034 /* We've crossed the Rubicon; get rid of the file selection box. */
1035 window_destroy(GTK_WIDGET (fs));
1037 /* Try to open the merged capture file. */
1038 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
1039 /* We couldn't open it; don't dismiss the open dialog box,
1040 just leave it around so that the user can, after they
1041 dismiss the alert box popped up for the open error,
1044 dfilter_free(rfcode);
1046 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1047 * as this will prevent the user from closing the now existing error
1048 * message, simply close the dialog (this is the best we can do here). */
1050 window_destroy(file_open_w);
1055 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
1056 it closed the previous capture file, and thus destroyed any
1057 previous read filter attached to "cf"). */
1058 cfile.rfcode = rfcode;
1060 switch (cf_read(&cfile, FALSE)) {
1064 /* Just because we got an error, that doesn't mean we were unable
1065 to read any of the file; we handle what we could get from the
1069 case CF_READ_ABORTED:
1070 /* The user bailed out of re-reading the capture file; the
1071 capture file has been closed - just free the capture file name
1072 string and return (without changing the last containing
1077 /* Save the name of the containing directory specified in the path name,
1078 if any; we can write over cf_merged_name, which is a good thing, given that
1079 "get_dirname()" does write over its argument. */
1080 s = get_dirname(tmpname);
1081 set_last_open_dir(s);
1085 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1087 /* Note that we no longer have a "Merge Capture File" dialog box. */
1088 file_merge_w = NULL;
1092 do_file_close(capture_file *cf, gboolean from_quit, const char *before_what)
1094 GtkWidget *msg_dialog;
1095 gchar *display_basename;
1097 gboolean capture_in_progress;
1099 if (cf->state == FILE_CLOSED)
1100 return TRUE; /* already closed, nothing to do */
1103 if (cf->state == FILE_READ_IN_PROGRESS) {
1104 /* This is true if we're reading a capture file *or* if we're doing
1105 a live capture. If we're reading a capture file, the main loop
1106 is busy reading packets, and only accepting input from the
1107 progress dialog, so we can't get here, so this means we're
1109 capture_in_progress = TRUE;
1112 capture_in_progress = FALSE;
1114 if (prefs.gui_ask_unsaved) {
1115 if (cf->is_tempfile || capture_in_progress || cf->unsaved_changes) {
1116 /* This is a temporary capture file, or there's a capture in
1117 progress, or the file has unsaved changes; ask the user whether
1118 to save the data. */
1119 if (cf->is_tempfile) {
1120 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1121 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1122 GTK_MESSAGE_QUESTION,
1124 capture_in_progress ?
1125 "Do you want to stop the capture and save the captured packets%s?" :
1126 "Do you want to save the captured packets%s?",
1129 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1130 "Your captured packets will be lost if you don't save them.");
1133 * Format the message.
1135 display_basename = g_filename_display_basename(cf->filename);
1136 if (capture_in_progress) {
1137 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1138 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1139 GTK_MESSAGE_QUESTION,
1141 "Do you want to stop the capture and save the captured packets%s?",
1144 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(top_level),
1145 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1146 GTK_MESSAGE_QUESTION,
1148 "Do you want to save the changes you've made "
1149 "to the capture file \"%s\"%s?",
1150 display_basename, before_what);
1152 g_free(display_basename);
1153 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1154 capture_in_progress ?
1155 "Your captured packets will be lost if you don't save them." :
1156 "Your changes will be lost if you don't save them.");
1160 /* If this is from a Quit operation, use "quit and don't save"
1161 rather than just "don't save". */
1162 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1164 (cf->state == FILE_READ_IN_PROGRESS ?
1165 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1166 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1167 (capture_in_progress ?
1168 WIRESHARK_STOCK_STOP_DONT_SAVE :
1169 WIRESHARK_STOCK_DONT_SAVE)),
1170 GTK_RESPONSE_REJECT);
1171 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1172 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1173 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1174 (capture_in_progress ?
1175 WIRESHARK_STOCK_STOP_SAVE :
1177 GTK_RESPONSE_ACCEPT);
1179 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1180 (capture_in_progress ?
1181 WIRESHARK_STOCK_STOP_SAVE :
1183 GTK_RESPONSE_ACCEPT);
1184 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1185 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1186 gtk_dialog_add_button(GTK_DIALOG(msg_dialog),
1188 (capture_in_progress ?
1189 WIRESHARK_STOCK_STOP_QUIT_DONT_SAVE :
1190 WIRESHARK_STOCK_QUIT_DONT_SAVE) :
1191 (capture_in_progress ?
1192 WIRESHARK_STOCK_STOP_DONT_SAVE :
1193 WIRESHARK_STOCK_DONT_SAVE)),
1194 GTK_RESPONSE_REJECT);
1196 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_ACCEPT);
1198 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1199 gtk_widget_destroy(msg_dialog);
1203 case GTK_RESPONSE_ACCEPT:
1205 /* If there's a capture in progress, we have to stop the capture
1206 and then do the save. */
1207 if (capture_in_progress)
1208 capture_stop_cb(NULL, NULL);
1210 /* Save the file and close it */
1211 do_file_save(cf, TRUE);
1214 case GTK_RESPONSE_REJECT:
1216 /* If there's a capture in progress; we have to stop the capture
1217 and then do the close. */
1218 if (capture_in_progress)
1219 capture_stop_cb(NULL, NULL);
1221 /* Just close the file, discarding changes */
1225 case GTK_RESPONSE_CANCEL:
1226 case GTK_RESPONSE_NONE:
1227 case GTK_RESPONSE_DELETE_EVENT:
1229 /* Don't close the file (and don't stop any capture in progress). */
1230 return FALSE; /* file not closed */
1234 /* unchanged file, just close it */
1238 /* User asked not to be bothered by those prompts, just close it.
1239 XXX - should that apply only to saving temporary files? */
1241 /* If there's a capture in progress, we have to stop the capture
1242 and then do the close. */
1243 if (capture_in_progress)
1244 capture_stop_cb(NULL, NULL);
1248 return TRUE; /* file closed */
1253 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1254 do_file_close(&cfile, FALSE, "");
1258 * Save the capture file in question, prompting the user for a file
1259 * name to save to if necessary.
1262 do_file_save(capture_file *cf, gboolean dont_reopen)
1266 if (cf->is_tempfile) {
1267 /* This is a temporary capture file, so saving it means saving
1268 it to a permanent file. Prompt the user for a location
1269 to which to save it. */
1270 do_file_save_as(cf);
1272 if (cf->unsaved_changes) {
1273 /* This is not a temporary capture file, but it has unsaved
1274 changes, so saving it means doing a "safe save" on top
1275 of the existing file, in the same format - no UI needed. */
1276 /* XXX - cf->filename might get freed out from under us, because
1277 the code path through which cf_save_packets() goes currently
1278 closes the current file and then opens and reloads the saved file,
1279 so make a copy and free it later. */
1280 fname = g_strdup(cf->filename);
1281 cf_save_packets(cf, fname, cf->cd_t, cf->iscompressed, dont_reopen);
1284 /* Otherwise just do nothing. */
1289 file_save_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1290 do_file_save(&cfile, FALSE);
1293 /* Attach a list of the valid 'save as' file types to a combo_box by
1294 checking what Wiretap supports. Make the default type the first
1298 set_file_type_list(GtkWidget *combo_box, capture_file *cf)
1300 GArray *savable_file_types;
1304 savable_file_types = wtap_get_savable_file_types(cf->cd_t, cf->lnk_t);
1306 if (savable_file_types != NULL) {
1307 /* OK, we have at least one file type we can save this file as.
1308 (If we didn't, we shouldn't have gotten here in the first
1309 place.) Add them all to the combo box. */
1310 for (i = 0; i < savable_file_types->len; i++) {
1311 ft = g_array_index(savable_file_types, int, i);
1312 ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(combo_box),
1313 wtap_file_type_string(ft),
1314 GINT_TO_POINTER(ft));
1316 g_array_free(savable_file_types, TRUE);
1321 file_save_as_select_file_type_cb(GtkWidget *w, gpointer data _U_)
1325 GtkWidget *compressed_cb;
1327 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr)) {
1328 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1330 new_file_type = GPOINTER_TO_INT(ptr);
1332 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY);
1333 if (!wtap_dump_can_compress(new_file_type)) {
1334 /* Can't compress this file type; turn off compression and make
1335 the compression checkbox insensitive. */
1336 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1337 gtk_widget_set_sensitive(compressed_cb, FALSE);
1339 gtk_widget_set_sensitive(compressed_cb, TRUE);
1344 do_file_save_as(capture_file *cf)
1347 win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
1349 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *compressed_cb;
1350 GtkWidget *msg_dialog;
1351 gchar *display_basename;
1356 if (file_save_as_w != NULL) {
1357 /* There's already an "Save Capture File As" dialog box; reactivate it. */
1358 reactivate_window(file_save_as_w);
1362 /* Default to saving in the file's current format. */
1364 /* build the file selection */
1365 file_save_as_w = file_selection_new ("Wireshark: Save Capture File As",
1366 FILE_SELECTION_SAVE);
1368 /* Container for each row of widgets */
1370 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1371 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1372 file_selection_set_extra_widget(file_save_as_w, main_vb);
1373 gtk_widget_show(main_vb);
1377 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1378 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1379 gtk_widget_show(ft_hb);
1381 ft_lb = gtk_label_new("File type:");
1382 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1383 gtk_widget_show(ft_lb);
1385 ft_combo_box = ws_combo_box_new_text_and_pointer();
1387 /* Generate the list of file types we can save. */
1388 set_file_type_list(ft_combo_box, cf);
1389 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1390 gtk_widget_show(ft_combo_box);
1391 g_object_set_data(G_OBJECT(file_save_as_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1394 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1395 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1396 gtk_widget_show(compressed_cb);
1397 g_object_set_data(G_OBJECT(file_save_as_w), E_COMPRESSED_CB_KEY, compressed_cb);
1398 /* Ok: now "select" the default filetype which invokes file_save_as_select_file_type_cb */
1399 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_save_as_select_file_type_cb), NULL);
1400 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1402 g_signal_connect(file_save_as_w, "destroy",
1403 G_CALLBACK(file_save_as_destroy_cb), NULL);
1406 * Loop until the user either selects a file or gives up.
1409 if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) != GTK_RESPONSE_ACCEPT) {
1410 /* They clicked "Cancel" or closed the dialog or.... */
1411 window_destroy(file_save_as_w);
1415 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_save_as_w));
1417 /* Perhaps the user specified a directory instead of a file.
1418 Check whether they did. */
1419 if (test_for_directory(cf_name) == EISDIR) {
1420 /* It's a directory - set the file selection box to display that
1421 directory, and go back and re-run it. */
1422 set_last_open_dir(cf_name);
1424 file_selection_set_current_folder(file_save_as_w, get_last_open_dir());
1429 * Check that the from file is not the same as to file
1430 * We do it here so we catch all cases ...
1431 * Unfortunately, the file requester gives us an absolute file
1432 * name and the read file name may be relative (if supplied on
1433 * the command line). From Joerg Mayer.
1435 if (files_identical(cf->filename, cf_name)) {
1436 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1437 "%sCapture file: \"%s\" identical to loaded file!%s\n\n"
1438 "Please choose a different filename.",
1439 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1442 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1443 * as this will prevent the user from closing the now existing error
1444 * message, simply close the dialog (this is the best we can do here). */
1446 window_destroy(GTK_WIDGET(file_save_as_w));
1451 /* it the file doesn't exist, simply try to save it */
1452 if (!file_exists(cf_name)) {
1453 gtk_widget_hide(GTK_WIDGET(file_save_as_w));
1455 file_save_as_cb(file_save_as_w);
1460 * The file exists. Ask the user if they want to overwrite it.
1462 * XXX - what if it's a symlink? TextEdit just blindly replaces
1463 * symlinks with files if you save over them, but gedit appears
1464 * to replace the *target* of the symlink. (To find the target,
1465 * use realpath() - it dates back to the SUSv2 and may be even
1468 display_basename = g_filename_display_basename(cf_name);
1469 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_save_as_w),
1470 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1471 GTK_MESSAGE_QUESTION,
1473 "A file named \"%s\" already exists. Do you want to replace it?",
1475 g_free(display_basename);
1476 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1477 "A file or folder with the same name already exists in that folder. "
1478 "Replacing it will overwrite its current contents.");
1480 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1482 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1483 "Replace", GTK_RESPONSE_ACCEPT,
1485 "Replace", GTK_RESPONSE_ACCEPT,
1486 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1489 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_CANCEL);
1491 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1492 gtk_widget_destroy(msg_dialog);
1494 if (response != GTK_RESPONSE_ACCEPT) {
1495 /* The user doesn't want to overwrite this file; let them choose
1501 /* Check whether the file has all the write permission bits clear
1502 and, on systems that have the 4.4-Lite file flags, whether it
1503 has the "user immutable" flag set. Treat both of those as an
1504 indication that the user wants to protect the file from
1505 casual overwriting, and ask the user if they want to override
1508 (Linux's "immutable" flag, as fetched and set by the appropriate
1509 ioctls (FS_IOC_GETFLAGS/FS_IOC_SETFLAGS in newer kernels,
1510 EXT2_IOC_GETFLAGS/EXT2_IOC_SETFLAGS in older kernels - non-ext2
1511 file systems that support those ioctls use the same values as ext2
1512 does), appears to be more like the *BSD/OS X "system immutable"
1513 flag, as it can be set only by the superuser or by processes with
1514 CAP_LINUX_IMMUTABLE, so it sounds as if it's not intended for
1515 arbitrary users to set or clear. */
1516 if (ws_stat64(cf_name, &statbuf) != -1) {
1517 /* OK, we have the permission bits and, if HAVE_ST_FLAGS is defined,
1518 the flags. (If we don't, we don't worry about it.) */
1519 #ifdef HAVE_ST_FLAGS
1520 if (statbuf.st_flags & UF_IMMUTABLE) {
1521 display_basename = g_filename_display_basename(cf_name);
1522 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_save_as_w),
1523 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1524 GTK_MESSAGE_QUESTION,
1527 /* Stuff in the OS X UI calls files with the "user immutable" bit
1528 "locked"; pre-OS X Mac software might have had that notion and
1529 called it "locked". */
1530 "The file \"%s\" is locked.",
1531 #else /* __APPLE__ */
1532 /* Just call it "immutable" in *BSD. */
1533 "The file \"%s\" is immutable.",
1534 #endif /* __APPLE__ */
1536 g_free(display_basename);
1538 #endif /* HAVE_ST_FLAGS */
1539 if ((statbuf.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0) {
1540 display_basename = g_filename_display_basename(cf_name);
1541 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(file_save_as_w),
1542 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1543 GTK_MESSAGE_QUESTION,
1545 "The file \"%s\" is read-only.",
1547 g_free(display_basename);
1549 /* No problem, just drive on. */
1552 if (msg_dialog != NULL) {
1553 /* OK, ask the user if they want to overwrite the file. */
1554 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
1555 "Do you want to overwrite it anyway?");
1557 gtk_dialog_add_buttons(GTK_DIALOG(msg_dialog),
1558 "Overwrite", GTK_RESPONSE_ACCEPT,
1559 "Don't overwrite", GTK_RESPONSE_REJECT,
1561 gtk_dialog_set_default_response(GTK_DIALOG(msg_dialog), GTK_RESPONSE_REJECT);
1563 response = gtk_dialog_run(GTK_DIALOG(msg_dialog));
1564 gtk_widget_destroy(msg_dialog);
1566 if (response != GTK_RESPONSE_ACCEPT) {
1567 /* The user doesn't want to overwrite this file; let them choose
1573 #ifdef HAVE_ST_FLAGS
1574 /* OK, they want to overwrite the file. If it has the "user
1575 immutable" flag, we have to turn that off first, so we
1576 can move the file. */
1577 if (statbuf.st_flags & UF_IMMUTABLE) {
1578 /* If this fails, the attempt to save will fail, so just
1579 let that happen and pop up a "you lose" dialog. */
1580 chflags(cf_name, statbuf.st_flags & ~UF_IMMUTABLE);
1587 gtk_widget_hide(GTK_WIDGET(file_save_as_w));
1588 file_save_as_cb(file_save_as_w);
1595 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1597 do_file_save_as(&cfile);
1600 /* all tests ok, we only have to save the file */
1601 /* (and probably continue with a pending operation) */
1603 file_save_as_cb(GtkWidget *fs) {
1604 GtkWidget *ft_combo_box;
1605 GtkWidget *compressed_cb;
1610 gboolean compressed;
1612 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1614 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1615 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1617 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1618 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1620 file_type = GPOINTER_TO_INT(ptr);
1621 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1623 /* Write out all the packets to the file with the specified name. */
1624 if (cf_save_packets(&cfile, cf_name, file_type, compressed, FALSE) != CF_OK) {
1625 /* The write failed; don't dismiss the open dialog box,
1626 just leave it around so that the user can, after they
1627 dismiss the alert box popped up for the error, try again. */
1629 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1630 * as this will prevent the user from closing the now existing error
1631 * message, simply close the dialog (this is the best we can do here). */
1633 window_destroy(GTK_WIDGET (fs));
1637 /* The write succeeded; get rid of the file selection box. */
1638 /* cf_save_packets() might already closed our dialog! */
1640 window_destroy(GTK_WIDGET (fs));
1642 /* Save the directory name for future file dialogs. */
1643 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1644 set_last_open_dir(dirname);
1650 file_save_as_destroy(void)
1653 window_destroy(file_save_as_w);
1657 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1659 /* Note that we no longer have a "Save Capture File As" dialog box. */
1660 file_save_as_w = NULL;
1664 * Update various dynamic parts of the range controls; called from outside
1665 * the file dialog code whenever the packet counts change.
1668 file_export_specified_packets_update_dynamics(void)
1670 if (file_export_specified_packets_w == NULL) {
1671 /* We don't currently have a "Export Specified Packets..." dialog box up. */
1675 range_update_dynamics(range_tb);
1679 file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1682 win32_export_specified_packets_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
1684 GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *compressed_cb;
1686 if (file_export_specified_packets_w != NULL) {
1687 /* There's already an "Export Specified Packets" dialog box; reactivate it. */
1688 reactivate_window(file_export_specified_packets_w);
1692 /* Default to writing out all displayed packets, in the file's current format. */
1694 /* init the packet range */
1695 packet_range_init(&range);
1696 range.process_filtered = TRUE;
1697 range.include_dependents = TRUE;
1699 /* build the file selection */
1700 file_export_specified_packets_w = file_selection_new ("Wireshark: Export Specified Packets",
1701 FILE_SELECTION_SAVE);
1703 /* Container for each row of widgets */
1705 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1706 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1707 file_selection_set_extra_widget(file_export_specified_packets_w, main_vb);
1708 gtk_widget_show(main_vb);
1710 /*** Packet Range frame ***/
1711 range_fr = gtk_frame_new("Packet Range");
1712 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1713 gtk_widget_show(range_fr);
1716 range_tb = range_new(&range, TRUE);
1717 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1718 gtk_widget_show(range_tb);
1721 ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
1722 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1723 gtk_widget_show(ft_hb);
1725 ft_lb = gtk_label_new("File type:");
1726 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1727 gtk_widget_show(ft_lb);
1729 ft_combo_box = ws_combo_box_new_text_and_pointer();
1731 /* Generate the list of file types we can save. */
1732 set_file_type_list(ft_combo_box, &cfile);
1733 gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
1734 gtk_widget_show(ft_combo_box);
1735 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_FILE_TYPE_COMBO_BOX_KEY, ft_combo_box);
1737 /* dynamic values in the range frame */
1738 range_update_dynamics(range_tb);
1741 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1742 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1743 gtk_widget_show(compressed_cb);
1744 g_object_set_data(G_OBJECT(file_export_specified_packets_w), E_COMPRESSED_CB_KEY, compressed_cb);
1746 /* Ok: now "select" the default filetype which invokes file_export_specified_packets_select_file_type_cb */
1747 g_signal_connect(ft_combo_box, "changed", G_CALLBACK(file_export_specified_packets_select_file_type_cb), NULL);
1748 ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
1750 g_signal_connect(file_export_specified_packets_w, "destroy",
1751 G_CALLBACK(file_export_specified_packets_destroy_cb), NULL);
1753 if (gtk_dialog_run(GTK_DIALOG(file_export_specified_packets_w)) == GTK_RESPONSE_ACCEPT) {
1754 file_export_specified_packets_ok_cb(file_export_specified_packets_w, file_export_specified_packets_w);
1756 window_destroy(file_export_specified_packets_w);
1762 file_export_specified_packets_select_file_type_cb(GtkWidget *w, gpointer data _U_)
1766 GtkWidget *compressed_cb;
1768 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr)) {
1769 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1771 new_file_type = GPOINTER_TO_INT(ptr);
1773 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(file_export_specified_packets_w), E_COMPRESSED_CB_KEY);
1774 if (!wtap_dump_can_compress(new_file_type)) {
1775 /* Can't compress this file type; turn off compression and make
1776 the compression checkbox insensitive. */
1777 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compressed_cb), FALSE);
1778 gtk_widget_set_sensitive(compressed_cb, FALSE);
1780 gtk_widget_set_sensitive(compressed_cb, TRUE);
1784 file_export_specified_packets_exists_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
1788 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data));
1793 file_export_specified_packets_cb(NULL, data);
1795 case(ESD_BTN_CANCEL):
1796 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1797 * as this will prevent the user from closing the now existing error
1798 * message, simply close the dialog (this is the best we can do here). */
1799 if (file_export_specified_packets_w)
1800 window_destroy(file_export_specified_packets_w);
1803 g_assert_not_reached();
1808 /* user pressed "Export Specified Packets" dialog "Ok" button */
1810 file_export_specified_packets_ok_cb(GtkWidget *w _U_, gpointer fs) {
1814 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1816 /* Perhaps the user specified a directory instead of a file.
1817 Check whether they did. */
1818 if (test_for_directory(cf_name) == EISDIR) {
1819 /* It's a directory - set the file selection box to display that
1820 directory, and leave the selection box displayed. */
1821 set_last_open_dir(cf_name);
1823 file_selection_set_current_folder(fs, get_last_open_dir());
1827 /* Check whether the range is valid. */
1828 if (!range_check_validity(&range)) {
1829 /* The range isn't valid; don't dismiss the open dialog box,
1830 just leave it around so that the user can, after they
1831 dismiss the alert box popped up for the error, try again. */
1833 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1834 * as this will prevent the user from closing the now existing error
1835 * message, simply close the dialog (this is the best we can do here). */
1837 window_destroy(GTK_WIDGET (fs));
1843 * Check that the from file is not the same as to file
1844 * We do it here so we catch all cases ...
1845 * Unfortunately, the file requester gives us an absolute file
1846 * name and the read file name may be relative (if supplied on
1847 * the command line). From Joerg Mayer.
1849 if (files_identical(cfile.filename, cf_name)) {
1850 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1851 "%sCapture file: \"%s\" identical to loaded file!%s\n\n"
1852 "Please choose a different filename.",
1853 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1855 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1856 * as this will prevent the user from closing the now existing error
1857 * message, simply close the dialog (this is the best we can do here). */
1858 if (file_export_specified_packets_w)
1859 window_destroy(GTK_WIDGET (fs));
1864 /* don't show the dialog while saving (or asking) */
1865 gtk_widget_hide(GTK_WIDGET (fs));
1867 /* it the file doesn't exist, simply try to write the packets to it */
1868 if (!file_exists(cf_name)) {
1869 file_export_specified_packets_cb(NULL, fs);
1874 /* The file exists. Ask the user if they want to overwrite it. */
1875 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
1877 "A file named \"%s\" already exists. Do you want to replace it?"
1879 "A file or folder with the same name already exists in that folder. "
1880 "Replacing it will overwrite its current contents.",
1881 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1882 simple_dialog_set_cb(dialog, file_export_specified_packets_exists_answered_cb, fs);
1887 /* all tests ok, we only have to write out the packets */
1888 /* (and probably continue with a pending operation) */
1890 file_export_specified_packets_cb(GtkWidget *w _U_, gpointer fs) {
1891 GtkWidget *ft_combo_box;
1892 GtkWidget *compressed_cb;
1897 gboolean compressed;
1899 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
1901 compressed_cb = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_COMPRESSED_CB_KEY);
1902 ft_combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(fs), E_FILE_TYPE_COMBO_BOX_KEY);
1904 if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
1905 g_assert_not_reached(); /* Programming error: somehow nothing is active */
1907 file_type = GPOINTER_TO_INT(ptr);
1908 compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
1910 /* Write out the specified packets to the file with the specified name. */
1911 if (cf_export_specified_packets(&cfile, cf_name, &range, file_type,
1912 compressed) != CF_OK) {
1913 /* The write failed; don't dismiss the open dialog box,
1914 just leave it around so that the user can, after they
1915 dismiss the alert box popped up for the error, try again. */
1917 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1918 * as this will prevent the user from closing the now existing error
1919 * message, simply close the dialog (this is the best we can do here). */
1920 if (file_export_specified_packets_w)
1921 window_destroy(GTK_WIDGET (fs));
1925 /* The write succeeded; get rid of the file selection box. */
1926 /* cf_export_specified_packets() might already closed our dialog! */
1927 if (file_export_specified_packets_w)
1928 window_destroy(GTK_WIDGET (fs));
1930 /* Save the directory name for future file dialogs.
1931 XXX - should there be separate ones for "Save As" and
1932 "Export Specified Packets"? */
1933 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1934 set_last_open_dir(dirname);
1939 file_export_specified_packets_destroy(void)
1941 if (file_export_specified_packets_w)
1942 window_destroy(file_export_specified_packets_w);
1946 file_export_specified_packets_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1948 /* Note that we no longer have a "Export Specified Packets" dialog box. */
1949 file_export_specified_packets_w = NULL;
1952 /* Reload a file using the current read and display filters */
1954 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1958 /******************** Color Filters *********************************/
1960 * Keep a static pointer to the current "Color Export" window, if
1961 * any, so that if somebody tries to do "Export"
1962 * while there's already a "Color Export" window up, we just pop
1963 * up the existing one, rather than creating a new one.
1965 static GtkWidget *file_color_import_w;
1967 /* sets the file path to the global color filter file.
1968 WARNING: called by both the import and the export dialog.
1971 color_global_cb(GtkWidget *widget _U_, gpointer data)
1973 GtkWidget *fs_widget = (GtkWidget *)data;
1976 /* decide what file to open (from dfilter code) */
1977 path = get_datafile_path("colorfilters");
1979 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1984 /* Import color filters */
1986 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
1989 win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
1991 GtkWidget *main_vb, *cfglobal_but;
1993 /* No Apply button, and "OK" just sets our text widget, it doesn't
1994 activate it (i.e., it doesn't cause us to try to open the file). */
1996 if (file_color_import_w != NULL) {
1997 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1998 reactivate_window(file_color_import_w);
2002 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
2003 FILE_SELECTION_OPEN);
2005 /* Container for each row of widgets */
2006 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2007 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2008 file_selection_set_extra_widget(file_color_import_w, main_vb);
2009 gtk_widget_show(main_vb);
2012 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2013 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
2014 g_signal_connect(cfglobal_but, "clicked",
2015 G_CALLBACK(color_global_cb), file_color_import_w);
2016 gtk_widget_show(cfglobal_but);
2018 g_signal_connect(file_color_import_w, "destroy",
2019 G_CALLBACK(file_color_import_destroy_cb), NULL);
2022 if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
2024 file_color_import_ok_cb(file_color_import_w, color_filters);
2026 else window_destroy(file_color_import_w);
2031 file_color_import_ok_cb(GtkWidget *w, gpointer color_filters) {
2033 GtkWidget *fs = gtk_widget_get_toplevel(w);
2035 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
2037 /* Perhaps the user specified a directory instead of a file.
2038 Check whether they did. */
2039 if (test_for_directory(cf_name) == EISDIR) {
2040 /* It's a directory - set the file selection box to display that
2041 directory, don't try to open the directory as a color filter file. */
2042 set_last_open_dir(cf_name);
2044 file_selection_set_current_folder(fs, get_last_open_dir());
2048 /* Try to open the color filter file. */
2050 if (!color_filters_import(cf_name, color_filters)) {
2051 /* We couldn't open it; don't dismiss the open dialog box,
2052 just leave it around so that the user can, after they
2053 dismiss the alert box popped up for the open error,
2056 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
2057 * as this will prevent the user from closing the now existing error
2058 * message, simply close the dialog (this is the best we can do here). */
2059 window_destroy(GTK_WIDGET (fs));
2064 /* We've crossed the Rubicon; get rid of the file selection box. */
2065 window_destroy(GTK_WIDGET (fs));
2067 /* Save the name of the containing directory specified in the path name,
2068 if any; we can write over cf_name, which is a good thing, given that
2069 "get_dirname()" does write over its argument. */
2070 s = get_dirname(cf_name);
2071 set_last_open_dir(s);
2077 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
2079 /* Note that we no longer have a "Open Capture File" dialog box. */
2080 file_color_import_w = NULL;
2083 static GtkWidget *file_color_export_w;
2085 * Set the "Export only selected filters" toggle button as appropriate for
2086 * the current output file type and count of selected filters.
2088 * Called when the "Export" dialog box is created and when the selected
2092 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
2094 if (file_color_export_w == NULL) {
2095 /* We don't currently have an "Export" dialog box up. */
2099 /* We can request that only the selected filters be saved only if
2100 there *are* selected filters. */
2101 if (color_selected_count() != 0)
2102 gtk_widget_set_sensitive(cfselect_cb, TRUE);
2104 /* Force the "Export only selected filters" toggle to "false", turn
2105 off the flag it controls. */
2106 color_selected = FALSE;
2107 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2108 gtk_widget_set_sensitive(cfselect_cb, FALSE);
2113 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
2115 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
2119 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
2122 win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
2124 GtkWidget *main_vb, *cfglobal_but;
2125 GtkWidget *cfselect_cb;
2127 if (file_color_export_w != NULL) {
2128 /* There's already an "Color Filter Export" dialog box; reactivate it. */
2129 reactivate_window(file_color_export_w);
2133 color_selected = FALSE;
2135 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
2136 FILE_SELECTION_SAVE);
2138 /* Container for each row of widgets */
2139 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
2140 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
2141 file_selection_set_extra_widget(file_color_export_w, main_vb);
2142 gtk_widget_show(main_vb);
2144 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
2145 gtk_container_add(GTK_CONTAINER(main_vb), cfselect_cb);
2146 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
2147 g_signal_connect(cfselect_cb, "toggled",
2148 G_CALLBACK(color_toggle_selected_cb), NULL);
2149 gtk_widget_show(cfselect_cb);
2150 color_set_export_selected_sensitive(cfselect_cb);
2152 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
2153 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
2154 g_signal_connect(cfglobal_but, "clicked",
2155 G_CALLBACK(color_global_cb), file_color_export_w);
2156 gtk_widget_show(cfglobal_but);
2158 g_signal_connect(file_color_export_w, "destroy",
2159 G_CALLBACK(file_color_export_destroy_cb), NULL);
2161 if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
2163 file_color_export_ok_cb(file_color_export_w, filter_list);
2165 else window_destroy(file_color_export_w);
2170 file_color_export_ok_cb(GtkWidget *w, gpointer filter_list) {
2173 GtkWidget *fs = gtk_widget_get_toplevel(w);
2175 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
2177 /* Perhaps the user specified a directory instead of a file.
2178 Check whether they did. */
2179 if (test_for_directory(cf_name) == EISDIR) {
2180 /* It's a directory - set the file selection box to display that
2181 directory, and leave the selection box displayed. */
2182 set_last_open_dir(cf_name);
2184 file_selection_set_current_folder(fs, get_last_open_dir());
2188 /* Write out the filters (all, or only the ones that are currently
2189 displayed or selected) to the file with the specified name. */
2191 if (!color_filters_export(cf_name, filter_list, color_selected))
2193 /* The write failed; don't dismiss the open dialog box,
2194 just leave it around so that the user can, after they
2195 dismiss the alert box popped up for the error, try again. */
2198 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
2199 * as this will prevent the user from closing the now existing error
2200 * message, simply close the dialog (this is the best we can do here). */
2201 window_destroy(GTK_WIDGET (fs));
2206 /* The write succeeded; get rid of the file selection box. */
2207 window_destroy(GTK_WIDGET (fs));
2209 /* Save the directory name for future file dialogs. */
2210 dirname = get_dirname(cf_name); /* Overwrites cf_name */
2211 set_last_open_dir(dirname);
2216 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
2218 file_color_export_w = NULL;