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/main_menu.h"
62 #include "gtk/recent.h"
63 #include "gtk/color_dlg.h"
65 #include "gtk/capture_dlg.h"
67 #include "gtk/stock_icons.h"
68 #include "gtk/range_utils.h"
71 #include <gdk/gdkwin32.h>
73 #include "gtk/file_dlg_win32.h"
77 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
78 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
79 static void file_merge_ok_cb(GtkWidget *w, gpointer fs);
80 static void file_merge_destroy_cb(GtkWidget *win, gpointer user_data);
81 static void select_file_type_cb(GtkWidget *w, gpointer data);
82 static void file_save_as_ok_cb(GtkWidget *w, gpointer fs);
83 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
84 static void file_color_import_ok_cb(GtkWidget *w, gpointer filter_list);
85 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
86 static void file_color_export_ok_cb(GtkWidget *w, gpointer filter_list);
87 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
88 static void set_file_type_list(GtkWidget *option_menu);
90 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
91 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
92 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
94 #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key"
95 #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key"
96 #define E_MERGE_APPEND_KEY "merge_dlg_append_key"
99 #define PREVIEW_TABLE_KEY "preview_table_key"
100 #define PREVIEW_FILENAME_KEY "preview_filename_key"
101 #define PREVIEW_FORMAT_KEY "preview_format_key"
102 #define PREVIEW_SIZE_KEY "preview_size_key"
103 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
104 #define PREVIEW_PACKETS_KEY "preview_packets_key"
105 #define PREVIEW_FIRST_KEY "preview_first_key"
109 * Keep a static pointer to the current "Save Capture File As" window, if
110 * any, so that if somebody tries to do "File:Save" or "File:Save As"
111 * while there's already a "Save Capture File As" window up, we just pop
112 * up the existing one, rather than creating a new one.
114 static GtkWidget *file_save_as_w;
116 /* XXX - can we make these not be static? */
117 static packet_range_t range;
118 static gboolean color_selected;
120 static GtkWidget *cfselect_cb;
121 static GtkWidget *ft_om;
122 static GtkWidget *range_tb;
124 #define PREVIEW_STR_MAX 200
127 /* set a new filename for the preview widget */
129 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
135 gchar string_buff[PREVIEW_STR_MAX];
139 /* init preview labels */
140 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
141 gtk_label_set_text(GTK_LABEL(label), "-");
142 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
143 gtk_label_set_text(GTK_LABEL(label), "-");
144 label = g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
145 gtk_label_set_text(GTK_LABEL(label), "-");
146 label = g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
147 gtk_label_set_text(GTK_LABEL(label), "-");
148 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
149 gtk_label_set_text(GTK_LABEL(label), "-");
150 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
151 gtk_label_set_text(GTK_LABEL(label), "-");
157 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FILENAME_KEY);
158 gtk_label_set_text(GTK_LABEL(label), get_basename(cf_name));
160 if (test_for_directory(cf_name) == EISDIR) {
161 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
162 gtk_label_set_text(GTK_LABEL(label), "directory");
166 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
168 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
169 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
170 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
172 gtk_label_set_text(GTK_LABEL(label), "error opening file");
177 /* Find the size of the file. */
178 filesize = wtap_file_size(wth, &err);
179 if (filesize == -1) {
180 gtk_label_set_text(GTK_LABEL(label), "error getting file size");
184 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" G_GINT64_MODIFIER "d bytes", filesize);
185 label = g_object_get_data(G_OBJECT(prev), PREVIEW_SIZE_KEY);
186 gtk_label_set_text(GTK_LABEL(label), string_buff);
189 g_snprintf(string_buff, PREVIEW_STR_MAX, "%s", wtap_file_type_string(wtap_file_type(wth)));
190 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FORMAT_KEY);
191 gtk_label_set_text(GTK_LABEL(label), string_buff);
197 /* do a preview run on the currently selected capture file */
199 preview_do(GtkWidget *prev, wtap *wth)
202 unsigned int elapsed_time;
208 const struct wtap_pkthdr *phdr;
209 double start_time = 0; /* seconds, with nsec resolution */
210 double stop_time = 0; /* seconds, with nsec resolution */
212 unsigned int packets = 0;
213 gboolean is_breaked = FALSE;
214 gchar string_buff[PREVIEW_STR_MAX];
220 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
221 phdr = wtap_phdr(wth);
222 cur_time = wtap_nstime_to_sec(&phdr->ts);
224 start_time = cur_time;
225 stop_time = cur_time;
227 if (cur_time < start_time) {
228 start_time = cur_time;
230 if (cur_time > stop_time){
231 stop_time = cur_time;
236 /* do we have a timeout? */
238 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
246 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
247 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
248 gtk_label_set_text(GTK_LABEL(label), string_buff);
255 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
257 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
259 label = g_object_get_data(G_OBJECT(prev), PREVIEW_PACKETS_KEY);
260 gtk_label_set_text(GTK_LABEL(label), string_buff);
263 ti_time = (long)start_time;
264 ti_tm = localtime( &ti_time );
266 g_snprintf(string_buff, PREVIEW_STR_MAX,
267 "%04d-%02d-%02d %02d:%02d:%02d",
268 ti_tm->tm_year + 1900,
275 g_snprintf(string_buff, PREVIEW_STR_MAX, "?");
277 label = g_object_get_data(G_OBJECT(prev), PREVIEW_FIRST_KEY);
278 gtk_label_set_text(GTK_LABEL(label), string_buff);
281 elapsed_time = (unsigned int)(stop_time-start_time);
282 if(elapsed_time/86400) {
283 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
284 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
286 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
287 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
290 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
292 label = g_object_get_data(G_OBJECT(prev), PREVIEW_ELAPSED_KEY);
293 gtk_label_set_text(GTK_LABEL(label), string_buff);
299 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
300 simply use the same layout as in GTK2.0 */
302 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
304 GtkWidget *prev = GTK_WIDGET (data);
306 gboolean have_preview;
308 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
310 have_preview = preview_set_filename(prev, cf_name);
315 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
320 /* the filename text entry changed */
322 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
324 GtkWidget *prev = g_object_get_data(G_OBJECT(file_sel), PREVIEW_TABLE_KEY);
325 const gchar* cf_name;
326 gboolean have_preview;
329 /* get the filename */
330 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
332 /* set the filename to the preview */
333 wth = preview_set_filename(prev, cf_name);
334 have_preview = (wth != NULL);
336 /* make the preview widget sensitive */
337 gtk_widget_set_sensitive(prev, have_preview);
339 /* make the open/save/... dialog button sensitive */
341 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
343 /* do the actual preview */
345 preview_do(prev, wth);
349 /* copied from summary_dlg.c */
351 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
356 if(strlen(value) != 0) {
357 indent = g_strdup_printf(" %s", title);
359 indent = g_strdup(title);
361 label = gtk_label_new(indent);
363 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
364 gtk_widget_set_sensitive(label, sensitive);
365 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
367 label = gtk_label_new(value);
368 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
369 gtk_widget_set_sensitive(label, sensitive);
370 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
378 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
380 return add_string_to_table_sensitive(list, row, title, value, TRUE);
388 GtkWidget *table, *label;
391 table = gtk_table_new(1, 2, FALSE);
392 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
393 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
396 label = add_string_to_table(table, &row, "Filename:", "-");
397 gtk_widget_set_size_request(label, DEF_WIDTH/3, -1);
398 g_object_set_data(G_OBJECT(table), PREVIEW_FILENAME_KEY, label);
399 label = add_string_to_table(table, &row, "Format:", "-");
400 g_object_set_data(G_OBJECT(table), PREVIEW_FORMAT_KEY, label);
401 label = add_string_to_table(table, &row, "Size:", "-");
402 g_object_set_data(G_OBJECT(table), PREVIEW_SIZE_KEY, label);
403 label = add_string_to_table(table, &row, "Packets:", "-");
404 g_object_set_data(G_OBJECT(table), PREVIEW_PACKETS_KEY, label);
405 label = add_string_to_table(table, &row, "First Packet:", "-");
406 g_object_set_data(G_OBJECT(table), PREVIEW_FIRST_KEY, label);
407 label = add_string_to_table(table, &row, "Elapsed time:", "-");
408 g_object_set_data(G_OBJECT(table), PREVIEW_ELAPSED_KEY, label);
414 * Keep a static pointer to the current "Open Capture File" window, if
415 * any, so that if somebody tries to do "File:Open" while there's already
416 * an "Open Capture File" window up, we just pop up the existing one,
417 * rather than creating a new one.
419 static GtkWidget *file_open_w;
423 file_open_cmd(GtkWidget *w)
426 win32_open_file(GDK_WINDOW_HWND(top_level->window));
428 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
429 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
430 GtkTooltips *tooltips = gtk_tooltips_new();
431 /* No Apply button, and "OK" just sets our text widget, it doesn't
432 activate it (i.e., it doesn't cause us to try to open the file). */
433 static construct_args_t args = {
434 "Wireshark: Read Filter",
440 if (file_open_w != NULL) {
441 /* There's already an "Open Capture File" dialog box; reactivate it. */
442 reactivate_window(file_open_w);
446 file_open_w = file_selection_new("Wireshark: Open Capture File",
447 FILE_SELECTION_OPEN);
448 /* it's annoying, that the file chooser dialog is already shown here,
449 so we cannot use the correct gtk_window_set_default_size() to resize it */
450 gtk_widget_set_size_request(file_open_w, DEF_WIDTH, DEF_HEIGHT);
452 switch (prefs.gui_fileopen_style) {
454 case FO_STYLE_LAST_OPENED:
455 /* The user has specified that we should start out in the last directory
456 we looked in. If we've already opened a file, use its containing
457 directory, if we could determine it, as the directory, otherwise
458 use the "last opened" directory saved in the preferences file if
460 /* This is now the default behaviour in file_selection_new() */
463 case FO_STYLE_SPECIFIED:
464 /* The user has specified that we should always start out in a
465 specified directory; if they've specified that directory,
466 start out by showing the files in that dir. */
467 if (prefs.gui_fileopen_dir[0] != '\0')
468 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
473 main_hb = gtk_hbox_new(FALSE, 3);
474 file_selection_set_extra_widget(file_open_w, main_hb);
475 gtk_widget_show(main_hb);
477 /* Container for each row of widgets */
478 main_vb = gtk_vbox_new(FALSE, 3);
479 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
480 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
481 gtk_widget_show(main_vb);
484 filter_hbox = gtk_hbox_new(FALSE, 1);
485 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
486 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
487 gtk_widget_show(filter_hbox);
489 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
490 g_signal_connect(filter_bt, "clicked",
491 G_CALLBACK(display_filter_construct_cb), &args);
492 g_signal_connect(filter_bt, "destroy",
493 G_CALLBACK(filter_button_destroy_cb), NULL);
494 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
495 gtk_widget_show(filter_bt);
496 gtk_tooltips_set_tip(tooltips, filter_bt,
497 "Open the \"Display Filter\" dialog, to edit/apply filters", NULL);
499 filter_te = gtk_entry_new();
500 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
501 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
502 g_signal_connect(filter_te, "changed",
503 G_CALLBACK(filter_te_syntax_check_cb), NULL);
504 gtk_widget_show(filter_te);
505 gtk_tooltips_set_tip(tooltips, filter_te, "Enter a display filter.", NULL);
507 g_object_set_data(G_OBJECT(file_open_w), E_RFILTER_TE_KEY, filter_te);
509 /* resolve buttons */
510 m_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _MAC name resolution");
511 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
512 g_resolv_flags & RESOLV_MAC);
513 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
514 g_object_set_data(G_OBJECT(file_open_w),
515 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
516 gtk_widget_show(m_resolv_cb);
518 n_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _network name resolution");
519 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
520 g_resolv_flags & RESOLV_NETWORK);
521 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
522 gtk_widget_show(n_resolv_cb);
523 g_object_set_data(G_OBJECT(file_open_w), E_FILE_N_RESOLVE_KEY, n_resolv_cb);
524 t_resolv_cb = gtk_check_button_new_with_mnemonic("Enable _transport name resolution");
525 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
526 g_resolv_flags & RESOLV_TRANSPORT);
527 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
528 gtk_widget_show(t_resolv_cb);
529 g_object_set_data(G_OBJECT(file_open_w), E_FILE_T_RESOLVE_KEY, t_resolv_cb);
531 g_signal_connect(file_open_w, "destroy",
532 G_CALLBACK(file_open_destroy_cb), NULL);
535 prev = preview_new();
536 g_object_set_data(G_OBJECT(file_open_w), PREVIEW_TABLE_KEY, prev);
537 gtk_widget_show_all(prev);
538 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
540 g_signal_connect(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
541 G_CALLBACK(file_open_entry_changed), file_open_w);
542 file_open_entry_changed(file_open_w, file_open_w);
544 g_object_set_data(G_OBJECT(file_open_w), E_DFILTER_TE_KEY,
545 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
546 if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
548 file_open_ok_cb(file_open_w, file_open_w);
550 else window_destroy(file_open_w);
554 static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
558 /* save file first */
559 file_save_as_cmd(after_save_open_dialog, data);
561 case(ESD_BTN_DONT_SAVE):
565 case(ESD_BTN_CANCEL):
568 g_assert_not_reached();
573 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
576 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
577 /* user didn't saved his current file, ask him */
578 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
579 "%sSave capture file before opening a new one?%s\n\n"
580 "If you open a new capture file without saving, your capture data will be discarded.",
581 simple_dialog_primary_start(), simple_dialog_primary_end());
582 simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
584 /* unchanged file, just open a new one */
585 file_open_cmd(widget);
589 /* user pressed "open" button */
591 file_open_ok_cb(GtkWidget *w, gpointer fs) {
593 const gchar *rfilter;
594 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
595 dfilter_t *rfcode = NULL;
598 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
599 filter_te = g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY);
600 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
601 if (!dfilter_compile(rfilter, &rfcode)) {
602 bad_dfilter_alert_box(rfilter);
607 /* Perhaps the user specified a directory instead of a file.
608 Check whether they did. */
609 if (test_for_directory(cf_name) == EISDIR) {
610 /* It's a directory - set the file selection box to display that
611 directory, don't try to open the directory as a capture file. */
612 set_last_open_dir(cf_name);
614 file_selection_set_current_folder(fs, get_last_open_dir());
618 /* Try to open the capture file. */
619 if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
620 /* We couldn't open it; don't dismiss the open dialog box,
621 just leave it around so that the user can, after they
622 dismiss the alert box popped up for the open error,
625 dfilter_free(rfcode);
628 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
629 * as this will prevent the user from closing the now existing error
630 * message, simply close the dialog (this is the best we can do here). */
632 window_destroy(file_open_w);
637 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
638 it closed the previous capture file, and thus destroyed any
639 previous read filter attached to "cf"). */
640 cfile.rfcode = rfcode;
642 /* Set the global resolving variable */
643 g_resolv_flags = prefs.name_resolve;
644 m_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_M_RESOLVE_KEY);
645 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
646 g_resolv_flags |= RESOLV_MAC;
648 g_resolv_flags &= ~RESOLV_MAC;
649 n_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_N_RESOLVE_KEY);
650 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
651 g_resolv_flags |= RESOLV_NETWORK;
653 g_resolv_flags &= ~RESOLV_NETWORK;
654 t_resolv_cb = g_object_get_data(G_OBJECT(w), E_FILE_T_RESOLVE_KEY);
655 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
656 g_resolv_flags |= RESOLV_TRANSPORT;
658 g_resolv_flags &= ~RESOLV_TRANSPORT;
660 /* We've crossed the Rubicon; get rid of the file selection box. */
661 window_destroy(GTK_WIDGET (fs));
663 switch (cf_read(&cfile)) {
667 /* Just because we got an error, that doesn't mean we were unable
668 to read any of the file; we handle what we could get from the
672 case CF_READ_ABORTED:
673 /* The user bailed out of re-reading the capture file; the
674 capture file has been closed - just free the capture file name
675 string and return (without changing the last containing
681 /* Save the name of the containing directory specified in the path name,
682 if any; we can write over cf_name, which is a good thing, given that
683 "get_dirname()" does write over its argument. */
684 s = get_dirname(cf_name);
685 set_last_open_dir(s);
686 gtk_widget_grab_focus(packet_list);
692 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
694 /* Note that we no longer have a "Open Capture File" dialog box. */
699 * Keep a static pointer to the current "Merge Capture File" window, if
700 * any, so that if somebody tries to do "File:Merge" while there's already
701 * an "Merge Capture File" window up, we just pop up the existing one,
702 * rather than creating a new one.
704 static GtkWidget *file_merge_w;
706 /* Merge existing with another file */
708 file_merge_cmd(GtkWidget *w)
711 win32_merge_file(GDK_WINDOW_HWND(top_level->window));
712 packet_list_freeze();
715 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *filter_hbox,
716 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
718 GtkTooltips *tooltips = gtk_tooltips_new();
719 /* No Apply button, and "OK" just sets our text widget, it doesn't
720 activate it (i.e., it doesn't cause us to try to open the file). */
721 static construct_args_t args = {
722 "Wireshark: Read Filter",
728 if (file_merge_w != NULL) {
729 /* There's already an "Merge Capture File" dialog box; reactivate it. */
730 reactivate_window(file_merge_w);
734 /* Default to saving all packets, in the file's current format. */
735 filetype = cfile.cd_t;
737 file_merge_w = file_selection_new("Wireshark: Merge with Capture File",
738 FILE_SELECTION_OPEN);
739 /* it's annoying, that the file chooser dialog is already shown here,
740 so we cannot use the correct gtk_window_set_default_size() to resize it */
741 gtk_widget_set_size_request(file_merge_w, DEF_WIDTH, DEF_HEIGHT);
743 switch (prefs.gui_fileopen_style) {
745 case FO_STYLE_LAST_OPENED:
746 /* The user has specified that we should start out in the last directory
747 we looked in. If we've already opened a file, use its containing
748 directory, if we could determine it, as the directory, otherwise
749 use the "last opened" directory saved in the preferences file if
751 /* This is now the default behaviour in file_selection_new() */
754 case FO_STYLE_SPECIFIED:
755 /* The user has specified that we should always start out in a
756 specified directory; if they've specified that directory,
757 start out by showing the files in that dir. */
758 if (prefs.gui_fileopen_dir[0] != '\0')
759 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
763 main_hb = gtk_hbox_new(FALSE, 3);
764 file_selection_set_extra_widget(file_merge_w, main_hb);
765 gtk_widget_show(main_hb);
767 /* Container for each row of widgets */
768 main_vb = gtk_vbox_new(FALSE, 3);
769 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
770 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
771 gtk_widget_show(main_vb);
775 ft_hb = gtk_hbox_new(FALSE, 3);
776 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
777 gtk_widget_show(ft_hb);
779 ft_lb = gtk_label_new("Merged output file type:");
780 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
781 gtk_widget_show(ft_lb);
783 ft_om = gtk_option_menu_new();
785 /* Generate the list of file types we can save. */
786 set_file_type_list(ft_om);
787 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
788 gtk_widget_show(ft_om);
790 filter_hbox = gtk_hbox_new(FALSE, 1);
791 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
792 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
793 gtk_widget_show(filter_hbox);
795 filter_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
796 g_signal_connect(filter_bt, "clicked",
797 G_CALLBACK(display_filter_construct_cb), &args);
798 g_signal_connect(filter_bt, "destroy",
799 G_CALLBACK(filter_button_destroy_cb), NULL);
800 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
801 gtk_widget_show(filter_bt);
802 gtk_tooltips_set_tip(tooltips, filter_bt,
803 "Open the \"Display Filter\" dialog, to edit/apply filters", NULL);
805 filter_te = gtk_entry_new();
806 g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
807 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
808 g_signal_connect(filter_te, "changed",
809 G_CALLBACK(filter_te_syntax_check_cb), NULL);
810 gtk_widget_show(filter_te);
811 gtk_tooltips_set_tip(tooltips, filter_te, "Enter a display filter.", NULL);
813 g_object_set_data(G_OBJECT(file_merge_w), E_RFILTER_TE_KEY, filter_te);
815 prepend_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL,
816 "Prepend packets to existing file");
817 gtk_tooltips_set_tip(tooltips, prepend_rb,
818 "The resulting file contains the packets from the selected, followed by the packets from the currently loaded file,"
819 " the packet timestamps will be ignored.", NULL);
820 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
821 g_object_set_data(G_OBJECT(file_merge_w),
822 E_MERGE_PREPEND_KEY, prepend_rb);
823 gtk_widget_show(prepend_rb);
825 chrono_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Merge packets chronologically");
826 gtk_tooltips_set_tip(tooltips, chrono_rb,
827 "The resulting file contains all the packets from the currently loaded and the selected file,"
828 " sorted by the packet timestamps.", NULL);
829 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
830 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
831 gtk_widget_show(chrono_rb);
832 g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_CHRONO_KEY, chrono_rb);
834 append_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(prepend_rb), "Append packets to existing file");
835 gtk_tooltips_set_tip(tooltips, append_rb,
836 "The resulting file contains the packets from the currently loaded, followed by the packets from the selected file,"
837 " the packet timestamps will be ignored.", NULL);
838 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(append_rb),
839 g_resolv_flags & RESOLV_TRANSPORT);
840 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
841 gtk_widget_show(append_rb);
842 g_object_set_data(G_OBJECT(file_merge_w), E_MERGE_APPEND_KEY, append_rb);
844 g_signal_connect(file_merge_w, "destroy",
845 G_CALLBACK(file_merge_destroy_cb), NULL);
848 prev = preview_new();
849 g_object_set_data(G_OBJECT(file_merge_w), PREVIEW_TABLE_KEY, prev);
850 gtk_widget_show_all(prev);
851 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
853 g_signal_connect(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
854 G_CALLBACK(file_open_entry_changed), file_merge_w);
855 file_open_entry_changed(file_merge_w, file_merge_w);
857 g_object_set_data(G_OBJECT(file_merge_w), E_DFILTER_TE_KEY,
858 g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY));
859 if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
861 file_merge_ok_cb(file_merge_w, file_merge_w);
863 else window_destroy(file_merge_w);
867 static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
871 /* save file first */
872 file_save_as_cmd(after_save_merge_dialog, data);
874 case(ESD_BTN_CANCEL):
877 g_assert_not_reached();
882 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
885 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
886 /* user didn't saved his current file, ask him */
887 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
888 "%sSave the capture file before merging to another one?%s\n\n"
889 "A temporary capture file can't be merged.",
890 simple_dialog_primary_start(), simple_dialog_primary_end());
891 simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
893 /* unchanged file, just start to merge */
894 file_merge_cmd(widget);
900 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
902 const gchar *rfilter;
903 GtkWidget *filter_te, *rb;
904 dfilter_t *rfcode = NULL;
906 cf_status_t merge_status;
907 char *in_filenames[2];
910 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
911 filter_te = g_object_get_data(G_OBJECT(w), E_RFILTER_TE_KEY);
912 rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
913 if (!dfilter_compile(rfilter, &rfcode)) {
914 bad_dfilter_alert_box(rfilter);
919 /* Perhaps the user specified a directory instead of a file.
920 Check whether they did. */
921 if (test_for_directory(cf_name) == EISDIR) {
922 /* It's a directory - set the file selection box to display that
923 directory, don't try to open the directory as a capture file. */
924 set_last_open_dir(cf_name);
926 file_selection_set_current_folder(fs, get_last_open_dir());
930 /* merge or append the two files */
931 rb = g_object_get_data(G_OBJECT(w), E_MERGE_CHRONO_KEY);
933 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
934 /* chronological order */
935 in_filenames[0] = cfile.filename;
936 in_filenames[1] = cf_name;
937 merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype, FALSE);
939 rb = g_object_get_data(G_OBJECT(w), E_MERGE_PREPEND_KEY);
940 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
942 in_filenames[0] = cf_name;
943 in_filenames[1] = cfile.filename;
944 merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype,
948 in_filenames[0] = cfile.filename;
949 in_filenames[1] = cf_name;
950 merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype,
957 if (merge_status != CF_OK) {
959 dfilter_free(rfcode);
966 /* We've crossed the Rubicon; get rid of the file selection box. */
967 window_destroy(GTK_WIDGET (fs));
969 /* Try to open the merged capture file. */
970 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
971 /* We couldn't open it; don't dismiss the open dialog box,
972 just leave it around so that the user can, after they
973 dismiss the alert box popped up for the open error,
976 dfilter_free(rfcode);
978 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
979 * as this will prevent the user from closing the now existing error
980 * message, simply close the dialog (this is the best we can do here). */
982 window_destroy(file_open_w);
987 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
988 it closed the previous capture file, and thus destroyed any
989 previous read filter attached to "cf"). */
990 cfile.rfcode = rfcode;
992 switch (cf_read(&cfile)) {
996 /* Just because we got an error, that doesn't mean we were unable
997 to read any of the file; we handle what we could get from the
1001 case CF_READ_ABORTED:
1002 /* The user bailed out of re-reading the capture file; the
1003 capture file has been closed - just free the capture file name
1004 string and return (without changing the last containing
1009 /* Save the name of the containing directory specified in the path name,
1010 if any; we can write over cf_merged_name, which is a good thing, given that
1011 "get_dirname()" does write over its argument. */
1012 s = get_dirname(tmpname);
1013 set_last_open_dir(s);
1014 gtk_widget_grab_focus(packet_list);
1018 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1020 /* Note that we no longer have a "Merge Capture File" dialog box. */
1021 file_merge_w = NULL;
1025 static void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1029 /* save file first */
1030 file_save_as_cmd(after_save_close_file, NULL);
1032 case(ESD_BTN_DONT_SAVE):
1035 case(ESD_BTN_CANCEL):
1038 g_assert_not_reached();
1044 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1047 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1048 /* user didn't saved his current file, ask him */
1049 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1050 "%sSave capture file before closing it?%s\n\n"
1051 "If you close without saving, your capture data will be discarded.",
1052 simple_dialog_primary_start(), simple_dialog_primary_end());
1054 simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
1056 /* unchanged file, just close it */
1062 file_save_cmd_cb(GtkWidget *w, gpointer data) {
1063 /* If the file's already been saved, do nothing. */
1064 if (cfile.user_saved)
1067 /* Do a "Save As". */
1068 file_save_as_cmd_cb(w, data);
1072 can_save_with_wiretap(int ft)
1074 /* To save a file with Wiretap, Wiretap has to handle that format,
1075 and its code to handle that format must be able to write a file
1076 with this file's encapsulation type. */
1077 return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
1081 /* Generate a list of the file types we can save this file as, by
1082 checking what Wiretap supports. */
1084 set_file_type_list(GtkWidget *option_menu)
1086 GtkWidget *ft_menu, *ft_menu_item;
1089 gint item_to_select;
1091 /* Default to the first supported file type, if the file's current
1092 type isn't supported. */
1093 item_to_select = -1;
1095 ft_menu = gtk_menu_new();
1097 /* Check all file types. */
1099 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
1100 if (can_save_with_wiretap(ft)) {
1101 /* OK, we can write it out in this type. */
1102 ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
1103 if (ft == filetype) {
1104 /* Default to the same format as the file, if it's supported. */
1105 item_to_select = index;
1107 g_signal_connect(ft_menu_item, "activate", G_CALLBACK(select_file_type_cb),
1108 GINT_TO_POINTER(ft));
1109 gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
1110 gtk_widget_show(ft_menu_item);
1115 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
1116 if (item_to_select >= 0) {
1117 /* Select the current File format in the menu */
1118 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
1119 select_file_type_cb(NULL, GINT_TO_POINTER(filetype));
1123 * Manually call the signal handler to activate the first menu item
1124 * since gtk_option_menu_set_history() doesn't do it for us. The first two
1125 * entries in the wiretap file types are placeholders so we start at #2, which
1126 * is the normal libpcap format.
1128 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), 0);
1129 select_file_type_cb(NULL, GINT_TO_POINTER(WTAP_FILE_PCAP));
1134 select_file_type_cb(GtkWidget *w _U_, gpointer data)
1136 int new_filetype = GPOINTER_TO_INT(data);
1137 GtkWidget *compressed_cb;
1139 if (filetype != new_filetype) {
1140 filetype = new_filetype;
1141 compressed_cb = g_object_get_data(G_OBJECT(file_save_as_w), "compressed");
1143 gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(new_filetype));
1149 * Update various dynamic parts of the range controls; called from outside
1150 * the file dialog code whenever the packet counts change.
1153 file_save_update_dynamics(void)
1155 if (file_save_as_w == NULL) {
1156 /* We don't currently have a "Save As..." dialog box up. */
1160 range_update_dynamics(range_tb);
1164 action_after_save_e action_after_save_g;
1165 gpointer action_after_save_data_g;
1169 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
1172 win32_save_as_file(GDK_WINDOW_HWND(top_level->window), action_after_save, action_after_save_data);
1174 GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr, *compressed_cb;
1175 GtkTooltips *tooltips;
1177 if (file_save_as_w != NULL) {
1178 /* There's already an "Save Capture File As" dialog box; reactivate it. */
1179 reactivate_window(file_save_as_w);
1183 /* Default to saving all packets, in the file's current format. */
1184 filetype = cfile.cd_t;
1186 /* init the packet range */
1187 packet_range_init(&range);
1189 /* Enable tooltips */
1190 tooltips = gtk_tooltips_new();
1192 /* build the file selection */
1193 file_save_as_w = file_selection_new ("Wireshark: Save Capture File As",
1194 FILE_SELECTION_SAVE);
1196 /* as the dialog might already be gone, when using this values, we cannot
1197 * set data to the dialog object, but keep global values */
1198 action_after_save_g = action_after_save;
1199 action_after_save_data_g = action_after_save_data;
1201 /* Container for each row of widgets */
1203 main_vb = gtk_vbox_new(FALSE, 5);
1204 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1205 file_selection_set_extra_widget(file_save_as_w, main_vb);
1206 gtk_widget_show(main_vb);
1208 /*** Packet Range frame ***/
1209 range_fr = gtk_frame_new("Packet Range");
1210 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1211 gtk_widget_show(range_fr);
1214 range_tb = range_new(&range);
1215 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1216 gtk_widget_show(range_tb);
1219 ft_hb = gtk_hbox_new(FALSE, 3);
1220 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1221 gtk_widget_show(ft_hb);
1223 ft_lb = gtk_label_new("File type:");
1224 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1225 gtk_widget_show(ft_lb);
1227 ft_om = gtk_option_menu_new();
1229 /* Generate the list of file types we can save. */
1230 set_file_type_list(ft_om);
1231 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1232 gtk_widget_show(ft_om);
1234 /* dynamic values in the range frame */
1235 range_update_dynamics(range_tb);
1238 compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1239 gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1240 /* XXX - disable output compression for now, as this doesn't work with the
1241 * current optimization to simply copy a capture file if it's using the same
1242 * encapsulation ... */
1243 /* the rest of the implementation is just working fine :-( */
1244 /*gtk_widget_show(compressed_cb);*/
1245 g_object_set_data(G_OBJECT(file_save_as_w), "compressed", compressed_cb);
1246 gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(cfile.cd_t));
1248 g_signal_connect(file_save_as_w, "destroy",
1249 G_CALLBACK(file_save_as_destroy_cb), NULL);
1251 if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) {
1252 file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1254 window_destroy(file_save_as_w);
1260 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1262 file_save_as_cmd(after_save_no_action, NULL);
1266 /* all tests ok, we only have to save the file */
1267 /* (and probably continue with a pending operation) */
1269 file_save_as_cb(GtkWidget *w _U_, gpointer fs) {
1272 GtkWidget *compressed_cb;
1275 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1277 compressed_cb = g_object_get_data(G_OBJECT(file_save_as_w), "compressed");
1279 /* XXX - if the user requests to save to an already existing filename, */
1280 /* ask in a dialog if that's intended */
1281 /* currently, cf_save() will simply deny it */
1283 /* Write out the packets (all, or only the ones from the current
1284 range) to the file with the specified name. */
1285 if (cf_save(&cfile, cf_name, &range, filetype,
1286 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb))) != CF_OK) {
1287 /* The write failed; don't dismiss the open dialog box,
1288 just leave it around so that the user can, after they
1289 dismiss the alert box popped up for the error, try again. */
1291 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1292 * as this will prevent the user from closing the now existing error
1293 * message, simply close the dialog (this is the best we can do here). */
1295 window_destroy(GTK_WIDGET (fs));
1299 /* The write succeeded; get rid of the file selection box. */
1300 /* cf_save() might already closed our dialog! */
1302 window_destroy(GTK_WIDGET (fs));
1304 /* Save the directory name for future file dialogs. */
1305 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1306 set_last_open_dir(dirname);
1309 /* we have finished saving, do we have pending things to do? */
1310 switch(action_after_save_g) {
1311 case(after_save_no_action):
1313 case(after_save_open_dialog):
1314 file_open_cmd(action_after_save_data_g);
1316 case(after_save_open_recent_file):
1317 menu_open_recent_file_cmd(action_after_save_data_g);
1319 case(after_save_open_dnd_file):
1320 dnd_open_file_cmd(action_after_save_data_g);
1322 case(after_save_merge_dialog):
1323 file_merge_cmd(action_after_save_data_g);
1326 case(after_save_capture_dialog):
1327 capture_start_confirmed();
1330 case(after_save_close_file):
1333 case(after_save_exit):
1337 g_assert_not_reached();
1340 action_after_save_g = after_save_no_action;
1344 static void file_save_as_exists_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
1348 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data)));
1354 file_save_as_cb(NULL, data);
1356 case(ESD_BTN_CANCEL):
1357 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1358 * as this will prevent the user from closing the now existing error
1359 * message, simply close the dialog (this is the best we can do here). */
1361 window_destroy(file_save_as_w);
1364 g_assert_not_reached();
1369 /* user pressed "Save" dialog "Ok" button */
1371 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1375 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1377 /* Perhaps the user specified a directory instead of a file.
1378 Check whether they did. */
1379 if (test_for_directory(cf_name) == EISDIR) {
1380 /* It's a directory - set the file selection box to display that
1381 directory, and leave the selection box displayed. */
1382 set_last_open_dir(cf_name);
1384 file_selection_set_current_folder(fs, get_last_open_dir());
1388 /* Check whether the range is valid. */
1389 if (!range_check_validity(&range)) {
1390 /* The range isn't valid; don't dismiss the open dialog box,
1391 just leave it around so that the user can, after they
1392 dismiss the alert box popped up for the error, try again. */
1394 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1395 * as this will prevent the user from closing the now existing error
1396 * message, simply close the dialog (this is the best we can do here). */
1398 window_destroy(GTK_WIDGET (fs));
1404 * Check that the from file is not the same as to file
1405 * We do it here so we catch all cases ...
1406 * Unfortunately, the file requester gives us an absolute file
1407 * name and the read file name may be relative (if supplied on
1408 * the command line). From Joerg Mayer.
1410 if (files_identical(cfile.filename, cf_name)) {
1411 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1412 "%sCapture file: \"%s\" identical to loaded file!%s\n\n"
1413 "Please choose a different filename.",
1414 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1416 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1417 * as this will prevent the user from closing the now existing error
1418 * message, simply close the dialog (this is the best we can do here). */
1420 window_destroy(GTK_WIDGET (fs));
1425 /* don't show the dialog while saving (or asking) */
1426 gtk_widget_hide(GTK_WIDGET (fs));
1428 /* it the file doesn't exist, simply try to save it */
1429 if (!file_exists(cf_name)) {
1430 file_save_as_cb(NULL, fs);
1435 /* the file exists, ask the user to remove it first */
1436 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
1437 "%sA file named \"%s\" already exists.%s\n\n"
1438 "Do you want to replace it with the capture you are saving?",
1439 simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1440 simple_dialog_set_cb(dialog, file_save_as_exists_answered_cb, fs);
1446 file_save_as_destroy(void)
1449 window_destroy(file_save_as_w);
1453 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1455 /* Note that we no longer have a "Save Capture File As" dialog box. */
1456 file_save_as_w = NULL;
1459 /* Reload a file using the current read and display filters */
1461 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1465 /******************** Color Filters *********************************/
1467 * Keep a static pointer to the current "Color Export" window, if
1468 * any, so that if somebody tries to do "Export"
1469 * while there's already a "Color Export" window up, we just pop
1470 * up the existing one, rather than creating a new one.
1472 static GtkWidget *file_color_import_w;
1474 /* sets the file path to the global color filter file.
1475 WARNING: called by both the import and the export dialog.
1478 color_global_cb(GtkWidget *widget _U_, gpointer data)
1480 GtkWidget *fs_widget = data;
1483 /* decide what file to open (from dfilter code) */
1484 path = get_datafile_path("colorfilters");
1486 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1488 g_free((gchar *)path);
1491 /* Import color filters */
1493 file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
1496 win32_import_color_file(GDK_WINDOW_HWND(top_level->window), color_filters);
1498 GtkWidget *main_vb, *cfglobal_but;
1500 /* No Apply button, and "OK" just sets our text widget, it doesn't
1501 activate it (i.e., it doesn't cause us to try to open the file). */
1503 if (file_color_import_w != NULL) {
1504 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1505 reactivate_window(file_color_import_w);
1509 file_color_import_w = file_selection_new("Wireshark: Import Color Filters",
1510 FILE_SELECTION_OPEN);
1512 /* Container for each row of widgets */
1513 main_vb = gtk_vbox_new(FALSE, 3);
1514 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1515 file_selection_set_extra_widget(file_color_import_w, main_vb);
1516 gtk_widget_show(main_vb);
1519 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1520 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1521 g_signal_connect(cfglobal_but, "clicked",
1522 G_CALLBACK(color_global_cb), file_color_import_w);
1523 gtk_widget_show(cfglobal_but);
1525 g_signal_connect(file_color_import_w, "destroy",
1526 G_CALLBACK(file_color_import_destroy_cb), NULL);
1529 if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1531 file_color_import_ok_cb(file_color_import_w, color_filters);
1533 else window_destroy(file_color_import_w);
1538 file_color_import_ok_cb(GtkWidget *w, gpointer color_filters) {
1540 GtkWidget *fs = gtk_widget_get_toplevel(w);
1542 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1544 /* Perhaps the user specified a directory instead of a file.
1545 Check whether they did. */
1546 if (test_for_directory(cf_name) == EISDIR) {
1547 /* It's a directory - set the file selection box to display that
1548 directory, don't try to open the directory as a color filter file. */
1549 set_last_open_dir(cf_name);
1551 file_selection_set_current_folder(fs, get_last_open_dir());
1555 /* Try to open the color filter file. */
1557 if (!color_filters_import(cf_name, color_filters)) {
1558 /* We couldn't open it; don't dismiss the open dialog box,
1559 just leave it around so that the user can, after they
1560 dismiss the alert box popped up for the open error,
1563 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1564 * as this will prevent the user from closing the now existing error
1565 * message, simply close the dialog (this is the best we can do here). */
1567 window_destroy(GTK_WIDGET (fs));
1572 /* We've crossed the Rubicon; get rid of the file selection box. */
1573 window_destroy(GTK_WIDGET (fs));
1575 /* Save the name of the containing directory specified in the path name,
1576 if any; we can write over cf_name, which is a good thing, given that
1577 "get_dirname()" does write over its argument. */
1578 s = get_dirname(cf_name);
1579 set_last_open_dir(s);
1580 gtk_widget_grab_focus(packet_list);
1586 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1588 /* Note that we no longer have a "Open Capture File" dialog box. */
1589 file_color_import_w = NULL;
1592 static GtkWidget *file_color_export_w;
1594 * Set the "Export only selected filters" toggle button as appropriate for
1595 * the current output file type and count of selected filters.
1597 * Called when the "Export" dialog box is created and when the selected
1601 color_set_export_selected_sensitive(GtkWidget * cfselect_cb)
1603 if (file_color_export_w == NULL) {
1604 /* We don't currently have an "Export" dialog box up. */
1608 /* We can request that only the selected filters be saved only if
1609 there *are* selected filters. */
1610 if (color_selected_count() != 0)
1611 gtk_widget_set_sensitive(cfselect_cb, TRUE);
1613 /* Force the "Export only selected filters" toggle to "false", turn
1614 off the flag it controls. */
1615 color_selected = FALSE;
1616 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
1617 gtk_widget_set_sensitive(cfselect_cb, FALSE);
1622 color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
1624 color_selected = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1628 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
1631 win32_export_color_file(GDK_WINDOW_HWND(top_level->window), filter_list);
1633 GtkWidget *main_vb, *cfglobal_but;
1635 if (file_color_export_w != NULL) {
1636 /* There's already an "Color Filter Export" dialog box; reactivate it. */
1637 reactivate_window(file_color_export_w);
1641 /* Default to saving all packets, in the file's current format. */
1642 color_selected = FALSE;
1643 filetype = cfile.cd_t;
1645 file_color_export_w = file_selection_new("Wireshark: Export Color Filters",
1646 FILE_SELECTION_SAVE);
1648 /* Container for each row of widgets */
1649 main_vb = gtk_vbox_new(FALSE, 3);
1650 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1651 file_selection_set_extra_widget(file_color_export_w, main_vb);
1652 gtk_widget_show(main_vb);
1654 cfselect_cb = gtk_check_button_new_with_label("Export only selected filters");
1655 gtk_container_add(GTK_CONTAINER(main_vb), cfselect_cb);
1656 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfselect_cb), FALSE);
1657 g_signal_connect(cfselect_cb, "toggled",
1658 G_CALLBACK(color_toggle_selected_cb), NULL);
1659 gtk_widget_show(cfselect_cb);
1660 color_set_export_selected_sensitive(cfselect_cb);
1662 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1663 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1664 g_signal_connect(cfglobal_but, "clicked",
1665 G_CALLBACK(color_global_cb), file_color_export_w);
1666 gtk_widget_show(cfglobal_but);
1668 g_signal_connect(file_color_export_w, "destroy",
1669 G_CALLBACK(file_color_export_destroy_cb), NULL);
1671 if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1673 file_color_export_ok_cb(file_color_export_w, filter_list);
1675 else window_destroy(file_color_export_w);
1680 file_color_export_ok_cb(GtkWidget *w, gpointer filter_list) {
1683 GtkWidget *fs = gtk_widget_get_toplevel(w);
1685 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1687 /* Perhaps the user specified a directory instead of a file.
1688 Check whether they did. */
1689 if (test_for_directory(cf_name) == EISDIR) {
1690 /* It's a directory - set the file selection box to display that
1691 directory, and leave the selection box displayed. */
1692 set_last_open_dir(cf_name);
1694 file_selection_set_current_folder(fs, get_last_open_dir());
1698 /* Write out the filters (all, or only the ones that are currently
1699 displayed or selected) to the file with the specified name. */
1701 if (!color_filters_export(cf_name, filter_list, color_selected))
1703 /* The write failed; don't dismiss the open dialog box,
1704 just leave it around so that the user can, after they
1705 dismiss the alert box popped up for the error, try again. */
1708 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1709 * as this will prevent the user from closing the now existing error
1710 * message, simply close the dialog (this is the best we can do here). */
1712 window_destroy(GTK_WIDGET (fs));
1717 /* The write succeeded; get rid of the file selection box. */
1718 window_destroy(GTK_WIDGET (fs));
1720 /* Save the directory name for future file dialogs. */
1721 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1722 set_last_open_dir(dirname);
1727 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1729 file_color_export_w = NULL;