2 * Dialog boxes for handling files
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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.
33 #include "packet-range.h"
34 #include <epan/filesystem.h>
37 #include "gtkglobals.h"
38 #include <epan/addr_resolv.h>
40 #include "filter_dlg.h"
42 #include "alert_box.h"
43 #include "simple_dialog.h"
45 #include "dlg_utils.h"
48 #include "compat_macros.h"
49 #include <epan/prefs.h>
52 #include "../ui_util.h"
53 #include "color_filters.h"
54 #include "gtk/color_dlg.h"
56 #include "capture_dlg.h"
57 #include "range_utils.h"
67 #include <io.h> /* open/close on win32 */
70 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
71 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
72 static void file_merge_ok_cb(GtkWidget *w, gpointer fs);
73 static void file_merge_destroy_cb(GtkWidget *win, gpointer user_data);
74 static void select_file_type_cb(GtkWidget *w, gpointer data);
75 static void file_save_as_ok_cb(GtkWidget *w, gpointer fs);
76 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
77 static void file_color_import_ok_cb(GtkWidget *w, gpointer fs);
78 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
79 static void file_color_export_ok_cb(GtkWidget *w, gpointer fs);
80 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
81 static void set_file_type_list(GtkWidget *option_menu);
83 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
84 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
85 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
87 #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key"
88 #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key"
89 #define E_MERGE_APPEND_KEY "merge_dlg_append_key"
91 #define ARGUMENT_CL "argument_cl"
94 #define PREVIEW_TABLE_KEY "preview_table_key"
95 #define PREVIEW_FILENAME_KEY "preview_filename_key"
96 #define PREVIEW_FORMAT_KEY "preview_format_key"
97 #define PREVIEW_SIZE_KEY "preview_size_key"
98 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
99 #define PREVIEW_PACKETS_KEY "preview_packets_key"
100 #define PREVIEW_FIRST_KEY "preview_first_key"
104 * Keep a static pointer to the current "Save Capture File As" window, if
105 * any, so that if somebody tries to do "File:Save" or "File:Save As"
106 * while there's already a "Save Capture File As" window up, we just pop
107 * up the existing one, rather than creating a new one.
109 static GtkWidget *file_save_as_w;
111 /* XXX - can we make these not be static? */
112 static packet_range_t range;
113 static gboolean color_marked;
115 static GtkWidget *cfmark_cb;
116 static GtkWidget *ft_om;
117 static GtkWidget *range_tb;
119 #ifdef HAVE_SYS_STAT_H
120 #include <sys/stat.h>
123 #define PREVIEW_STR_MAX 200
126 secs_usecs( guint32 s, guint32 us)
128 return (us / 1000000.0) + (double)s;
132 /* set a new filename for the preview widget */
134 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
141 gchar string_buff[PREVIEW_STR_MAX];
145 /* init preview labels */
146 label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
147 gtk_label_set_text(GTK_LABEL(label), "-");
148 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
149 gtk_label_set_text(GTK_LABEL(label), "-");
150 label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
151 gtk_label_set_text(GTK_LABEL(label), "-");
152 label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
153 gtk_label_set_text(GTK_LABEL(label), "-");
154 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
155 gtk_label_set_text(GTK_LABEL(label), "-");
156 label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
157 gtk_label_set_text(GTK_LABEL(label), "-");
163 label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
164 gtk_label_set_text(GTK_LABEL(label), get_basename((char *)cf_name));
166 if (test_for_directory(cf_name) == EISDIR) {
167 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
168 gtk_label_set_text(GTK_LABEL(label), "directory");
172 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
174 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
175 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
176 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
178 gtk_label_set_text(GTK_LABEL(label), "error opening file");
183 /* Find the size of the file. */
184 if (fstat(wtap_fd(wth), &cf_stat) < 0) {
190 filesize = cf_stat.st_size;
191 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" PRIu64 " bytes", filesize);
192 label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
193 gtk_label_set_text(GTK_LABEL(label), string_buff);
196 g_snprintf(string_buff, PREVIEW_STR_MAX, "%s", wtap_file_type_string(wtap_file_type(wth)));
197 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
198 gtk_label_set_text(GTK_LABEL(label), string_buff);
204 /* do a preview run on the currently selected capture file */
206 preview_do(GtkWidget *prev, wtap *wth)
209 unsigned int elapsed_time;
215 const struct wtap_pkthdr *phdr;
216 double start_time = 0; /* seconds, with msec resolution */
217 double stop_time = 0; /* seconds, with msec resolution */
219 unsigned int packets = 0;
220 gboolean is_breaked = FALSE;
221 gchar string_buff[PREVIEW_STR_MAX];
227 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
228 phdr = wtap_phdr(wth);
229 cur_time = secs_usecs(phdr->ts.tv_sec, phdr->ts.tv_usec);
231 start_time = cur_time;
232 stop_time = cur_time;
234 if (cur_time < start_time) {
235 start_time = cur_time;
237 if (cur_time > stop_time){
238 stop_time = cur_time;
243 /* do we have a timeout? */
245 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
253 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
254 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
255 gtk_label_set_text(GTK_LABEL(label), string_buff);
262 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
264 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
266 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
267 gtk_label_set_text(GTK_LABEL(label), string_buff);
270 ti_time = (long)start_time;
271 ti_tm = localtime( &ti_time );
272 g_snprintf(string_buff, PREVIEW_STR_MAX,
273 "%04d-%02d-%02d %02d:%02d:%02d",
274 ti_tm->tm_year + 1900,
280 label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
281 gtk_label_set_text(GTK_LABEL(label), string_buff);
284 elapsed_time = (unsigned int)(stop_time-start_time);
285 if(elapsed_time/86400) {
286 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
287 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
289 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
290 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
293 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
295 label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
296 gtk_label_set_text(GTK_LABEL(label), string_buff);
302 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
303 simply use the same layout as in GTK1 */
304 /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
306 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
308 GtkWidget *prev = GTK_WIDGET (data);
310 gboolean have_preview;
312 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
314 have_preview = preview_set_filename(prev, cf_name);
319 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
324 /* the filename text entry changed */
326 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
328 GtkWidget *prev = OBJECT_GET_DATA(file_sel, PREVIEW_TABLE_KEY);
329 const gchar* cf_name;
330 gboolean have_preview;
333 /* get the filename */
334 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
335 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
337 cf_name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_sel));
340 /* set the filename to the preview */
341 wth = preview_set_filename(prev, cf_name);
342 have_preview = (gboolean) wth;
344 /* make the preview widget sensitive */
345 gtk_widget_set_sensitive(prev, have_preview);
347 /* make the open/save/... dialog button sensitive */
348 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
349 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
351 gtk_widget_set_sensitive(GTK_FILE_SELECTION(file_sel)->ok_button, have_preview);
354 /* do the actual preview */
356 preview_do(prev, wth);
360 /* copied from summary_dlg.c */
362 add_string_to_table_sensitive(GtkWidget *list, guint *row, gchar *title, gchar *value, gboolean sensitive)
367 if(strlen(value) != 0) {
368 indent = g_strdup_printf(" %s", title);
370 indent = g_strdup(title);
372 label = gtk_label_new(indent);
374 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
375 gtk_widget_set_sensitive(label, sensitive);
376 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
378 label = gtk_label_new(value);
379 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
380 gtk_widget_set_sensitive(label, sensitive);
381 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
389 add_string_to_table(GtkWidget *list, guint *row, gchar *title, gchar *value)
391 return add_string_to_table_sensitive(list, row, title, value, TRUE);
399 GtkWidget *table, *label;
402 table = gtk_table_new(1, 2, FALSE);
403 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
404 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
407 label = add_string_to_table(table, &row, "Filename:", "-");
408 WIDGET_SET_SIZE(label, DEF_WIDTH/3, -1);
409 OBJECT_SET_DATA(table, PREVIEW_FILENAME_KEY, label);
410 label = add_string_to_table(table, &row, "Format:", "-");
411 OBJECT_SET_DATA(table, PREVIEW_FORMAT_KEY, label);
412 label = add_string_to_table(table, &row, "Size:", "-");
413 OBJECT_SET_DATA(table, PREVIEW_SIZE_KEY, label);
414 label = add_string_to_table(table, &row, "Packets:", "-");
415 OBJECT_SET_DATA(table, PREVIEW_PACKETS_KEY, label);
416 label = add_string_to_table(table, &row, "First Packet:", "-");
417 OBJECT_SET_DATA(table, PREVIEW_FIRST_KEY, label);
418 label = add_string_to_table(table, &row, "Elapsed time:", "-");
419 OBJECT_SET_DATA(table, PREVIEW_ELAPSED_KEY, label);
425 * Keep a static pointer to the current "Open Capture File" window, if
426 * any, so that if somebody tries to do "File:Open" while there's already
427 * an "Open Capture File" window up, we just pop up the existing one,
428 * rather than creating a new one.
430 static GtkWidget *file_open_w;
434 file_open_cmd(GtkWidget *w)
436 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
437 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
438 #if GTK_MAJOR_VERSION < 2
439 GtkAccelGroup *accel_group;
441 /* No Apply button, and "OK" just sets our text widget, it doesn't
442 activate it (i.e., it doesn't cause us to try to open the file). */
443 static construct_args_t args = {
444 "Ethereal: Read Filter",
449 if (file_open_w != NULL) {
450 /* There's already an "Open Capture File" dialog box; reactivate it. */
451 reactivate_window(file_open_w);
455 file_open_w = file_selection_new("Ethereal: Open Capture File",
456 FILE_SELECTION_OPEN);
457 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
458 /* it's annoying, that the file chooser dialog is already shown here,
459 so we cannot use the correct gtk_window_set_default_size() to resize it */
460 WIDGET_SET_SIZE(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
462 gtk_window_set_default_size(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
465 #if GTK_MAJOR_VERSION < 2
466 /* Accelerator group for the accelerators (or, as they're called in
467 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
468 Ctrl+<key> is an accelerator). */
469 accel_group = gtk_accel_group_new();
470 gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
473 switch (prefs.gui_fileopen_style) {
475 case FO_STYLE_LAST_OPENED:
476 /* The user has specified that we should start out in the last directory
477 we looked in. If we've already opened a file, use its containing
478 directory, if we could determine it, as the directory, otherwise
479 use the "last opened" directory saved in the preferences file if
481 /* This is now the default behaviour in file_selection_new() */
484 case FO_STYLE_SPECIFIED:
485 /* The user has specified that we should always start out in a
486 specified directory; if they've specified that directory,
487 start out by showing the files in that dir. */
488 if (prefs.gui_fileopen_dir[0] != '\0')
489 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
494 main_hb = gtk_hbox_new(FALSE, 3);
495 file_selection_set_extra_widget(file_open_w, main_hb);
496 gtk_widget_show(main_hb);
498 /* Container for each row of widgets */
499 main_vb = gtk_vbox_new(FALSE, 3);
500 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
501 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
502 gtk_widget_show(main_vb);
505 filter_hbox = gtk_hbox_new(FALSE, 1);
506 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
507 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
508 gtk_widget_show(filter_hbox);
510 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
511 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
512 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
513 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
514 gtk_widget_show(filter_bt);
516 filter_te = gtk_entry_new();
517 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
518 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
519 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
520 gtk_widget_show(filter_te);
522 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
523 OBJECT_SET_DATA(file_open_w, E_RFILTER_TE_KEY, filter_te);
525 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
526 E_RFILTER_TE_KEY, filter_te);
529 /* resolve buttons */
530 m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
531 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
532 g_resolv_flags & RESOLV_MAC);
533 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
534 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
535 OBJECT_SET_DATA(file_open_w,
536 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
538 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
539 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
541 gtk_widget_show(m_resolv_cb);
543 n_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _network name resolution", accel_group);
544 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
545 g_resolv_flags & RESOLV_NETWORK);
546 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
547 gtk_widget_show(n_resolv_cb);
548 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
549 OBJECT_SET_DATA(file_open_w, E_FILE_N_RESOLVE_KEY, n_resolv_cb);
551 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
552 E_FILE_N_RESOLVE_KEY, n_resolv_cb);
555 t_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _transport name resolution", accel_group);
556 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
557 g_resolv_flags & RESOLV_TRANSPORT);
558 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
559 gtk_widget_show(t_resolv_cb);
560 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
561 OBJECT_SET_DATA(file_open_w, E_FILE_T_RESOLVE_KEY, t_resolv_cb);
563 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
564 E_FILE_T_RESOLVE_KEY, t_resolv_cb);
568 SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
571 prev = preview_new();
572 OBJECT_SET_DATA(file_open_w, PREVIEW_TABLE_KEY, prev);
573 gtk_widget_show_all(prev);
574 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
576 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
577 SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
578 file_open_entry_changed, file_open_w);
579 file_open_entry_changed(file_open_w, file_open_w);
581 OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
582 OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
583 if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
585 file_open_ok_cb(file_open_w, file_open_w);
587 else window_destroy(file_open_w);
589 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->selection_entry, "changed",
590 file_open_entry_changed, file_open_w);
592 /* Connect the ok_button to file_open_ok_cb function and pass along a
593 pointer to the file selection box widget */
594 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
595 file_open_ok_cb, file_open_w);
597 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
598 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
600 /* Connect the cancel_button to destroy the widget */
601 window_set_cancel_button(file_open_w,
602 GTK_FILE_SELECTION(file_open_w)->cancel_button, window_cancel_button_cb);
604 SIGNAL_CONNECT(file_open_w, "delete_event", window_delete_event_cb, NULL);
606 gtk_widget_show(file_open_w);
607 window_present(file_open_w);
611 static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
615 /* save file first */
616 file_save_as_cmd(after_save_open_dialog, data);
618 case(ESD_BTN_DONT_SAVE):
622 case(ESD_BTN_CANCEL):
625 g_assert_not_reached();
630 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
633 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
634 /* user didn't saved his current file, ask him */
635 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
636 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
637 "If you open a new capture file without saving, your capture data will be discarded.");
638 simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
640 /* unchanged file, just open a new one */
641 file_open_cmd(widget);
645 /* user pressed "open" button */
647 file_open_ok_cb(GtkWidget *w, gpointer fs) {
648 gchar *cf_name, *rfilter, *s;
649 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
650 dfilter_t *rfcode = NULL;
653 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
654 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
656 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
658 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
659 rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
660 if (!dfilter_compile(rfilter, &rfcode)) {
661 bad_dfilter_alert_box(rfilter);
666 /* Perhaps the user specified a directory instead of a file.
667 Check whether they did. */
668 if (test_for_directory(cf_name) == EISDIR) {
669 /* It's a directory - set the file selection box to display that
670 directory, don't try to open the directory as a capture file. */
671 set_last_open_dir(cf_name);
673 file_selection_set_current_folder(fs, get_last_open_dir());
677 /* Try to open the capture file. */
678 if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
679 /* We couldn't open it; don't dismiss the open dialog box,
680 just leave it around so that the user can, after they
681 dismiss the alert box popped up for the open error,
684 dfilter_free(rfcode);
689 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
690 it closed the previous capture file, and thus destroyed any
691 previous read filter attached to "cf"). */
692 cfile.rfcode = rfcode;
694 /* Set the global resolving variable */
695 g_resolv_flags = prefs.name_resolve;
696 m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
697 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
698 g_resolv_flags |= RESOLV_MAC;
700 g_resolv_flags &= ~RESOLV_MAC;
701 n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
702 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
703 g_resolv_flags |= RESOLV_NETWORK;
705 g_resolv_flags &= ~RESOLV_NETWORK;
706 t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
707 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
708 g_resolv_flags |= RESOLV_TRANSPORT;
710 g_resolv_flags &= ~RESOLV_TRANSPORT;
712 /* We've crossed the Rubicon; get rid of the file selection box. */
713 window_destroy(GTK_WIDGET (fs));
715 switch (cf_read(&cfile)) {
719 /* Just because we got an error, that doesn't mean we were unable
720 to read any of the file; we handle what we could get from the
725 /* The user bailed out of re-reading the capture file; the
726 capture file has been closed - just free the capture file name
727 string and return (without changing the last containing
733 /* Save the name of the containing directory specified in the path name,
734 if any; we can write over cf_name, which is a good thing, given that
735 "get_dirname()" does write over its argument. */
736 s = get_dirname(cf_name);
737 set_last_open_dir(s);
738 gtk_widget_grab_focus(packet_list);
744 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
746 /* Note that we no longer have a "Open Capture File" dialog box. */
751 * Keep a static pointer to the current "Merge Capture File" window, if
752 * any, so that if somebody tries to do "File:Merge" while there's already
753 * an "Merge Capture File" window up, we just pop up the existing one,
754 * rather than creating a new one.
756 static GtkWidget *file_merge_w;
758 /* Merge existing with another file */
760 file_merge_cmd(GtkWidget *w)
762 GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *filter_hbox,
763 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
765 #if GTK_MAJOR_VERSION < 2
766 GtkAccelGroup *accel_group;
768 GtkTooltips *tooltips = gtk_tooltips_new();
769 /* No Apply button, and "OK" just sets our text widget, it doesn't
770 activate it (i.e., it doesn't cause us to try to open the file). */
771 static construct_args_t args = {
772 "Ethereal: Read Filter",
777 if (file_merge_w != NULL) {
778 /* There's already an "Merge Capture File" dialog box; reactivate it. */
779 reactivate_window(file_merge_w);
783 /* Default to saving all packets, in the file's current format. */
784 filetype = cfile.cd_t;
786 file_merge_w = file_selection_new("Ethereal: Merge with Capture File",
787 FILE_SELECTION_OPEN);
788 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
789 /* it's annoying, that the file chooser dialog is already shown here,
790 so we cannot use the correct gtk_window_set_default_size() to resize it */
791 WIDGET_SET_SIZE(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
793 gtk_window_set_default_size(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
796 #if GTK_MAJOR_VERSION < 2
797 /* Accelerator group for the accelerators (or, as they're called in
798 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
799 Ctrl+<key> is an accelerator). */
800 accel_group = gtk_accel_group_new();
801 gtk_window_add_accel_group(GTK_WINDOW(file_merge_w), accel_group);
804 switch (prefs.gui_fileopen_style) {
806 case FO_STYLE_LAST_OPENED:
807 /* The user has specified that we should start out in the last directory
808 we looked in. If we've already opened a file, use its containing
809 directory, if we could determine it, as the directory, otherwise
810 use the "last opened" directory saved in the preferences file if
812 /* This is now the default behaviour in file_selection_new() */
815 case FO_STYLE_SPECIFIED:
816 /* The user has specified that we should always start out in a
817 specified directory; if they've specified that directory,
818 start out by showing the files in that dir. */
819 if (prefs.gui_fileopen_dir[0] != '\0')
820 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
824 main_hb = gtk_hbox_new(FALSE, 3);
825 file_selection_set_extra_widget(file_merge_w, main_hb);
826 gtk_widget_show(main_hb);
828 /* Container for each row of widgets */
829 main_vb = gtk_vbox_new(FALSE, 3);
830 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
831 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
832 gtk_widget_show(main_vb);
836 ft_hb = gtk_hbox_new(FALSE, 3);
837 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
838 gtk_widget_show(ft_hb);
840 ft_lb = gtk_label_new("Merged output file type:");
841 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
842 gtk_widget_show(ft_lb);
844 ft_om = gtk_option_menu_new();
846 /* Generate the list of file types we can save. */
847 set_file_type_list(ft_om);
848 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
849 gtk_widget_show(ft_om);
851 filter_hbox = gtk_hbox_new(FALSE, 1);
852 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
853 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
854 gtk_widget_show(filter_hbox);
856 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
857 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
858 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
859 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
860 gtk_widget_show(filter_bt);
862 filter_te = gtk_entry_new();
863 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
864 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
865 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
866 gtk_widget_show(filter_te);
868 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
869 OBJECT_SET_DATA(file_merge_w, E_RFILTER_TE_KEY, filter_te);
871 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
872 E_RFILTER_TE_KEY, filter_te);
875 prepend_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Prepend packets to existing file", accel_group);
876 gtk_tooltips_set_tip(tooltips, prepend_rb,
877 "The resulting file contains the packets from the selected, followed by the packets from the currently loaded file,"
878 " the packet timestamps will be ignored.", NULL);
879 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
880 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
881 OBJECT_SET_DATA(file_merge_w,
882 E_MERGE_PREPEND_KEY, prepend_rb);
884 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
885 E_MERGE_PREPEND_KEY, prepend_rb);
887 gtk_widget_show(prepend_rb);
889 chrono_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Merge packets chronologically", accel_group);
890 gtk_tooltips_set_tip(tooltips, chrono_rb,
891 "The resulting file contains all the packets from the currently loaded and the selected file,"
892 " sorted by the packet timestamps.", NULL);
893 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
894 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
895 gtk_widget_show(chrono_rb);
896 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
897 OBJECT_SET_DATA(file_merge_w, E_MERGE_CHRONO_KEY, chrono_rb);
899 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
900 E_MERGE_CHRONO_KEY, chrono_rb);
903 append_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Append packets to existing file", accel_group);
904 gtk_tooltips_set_tip(tooltips, append_rb,
905 "The resulting file contains the packets from the currently loaded, followed by the packets from the selected file,"
906 " the packet timestamps will be ignored.", NULL);
907 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(append_rb),
908 g_resolv_flags & RESOLV_TRANSPORT);
909 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
910 gtk_widget_show(append_rb);
911 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
912 OBJECT_SET_DATA(file_merge_w, E_MERGE_APPEND_KEY, append_rb);
914 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
915 E_MERGE_APPEND_KEY, append_rb);
919 SIGNAL_CONNECT(file_merge_w, "destroy", file_merge_destroy_cb, NULL);
922 prev = preview_new();
923 OBJECT_SET_DATA(file_merge_w, PREVIEW_TABLE_KEY, prev);
924 gtk_widget_show_all(prev);
925 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
927 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
928 SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
929 file_open_entry_changed, file_merge_w);
930 file_open_entry_changed(file_merge_w, file_merge_w);
932 OBJECT_SET_DATA(file_merge_w, E_DFILTER_TE_KEY,
933 OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
934 if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
936 file_merge_ok_cb(file_merge_w, file_merge_w);
938 else window_destroy(file_merge_w);
940 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->selection_entry, "changed",
941 file_open_entry_changed, file_merge_w);
943 /* Connect the ok_button to file_merge_ok_cb function and pass along a
944 pointer to the file selection box widget */
945 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->ok_button, "clicked",
946 file_merge_ok_cb, file_merge_w);
948 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
949 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
951 /* Connect the cancel_button to destroy the widget */
952 window_set_cancel_button(file_merge_w,
953 GTK_FILE_SELECTION(file_merge_w)->cancel_button, window_cancel_button_cb);
955 SIGNAL_CONNECT(file_merge_w, "delete_event", window_delete_event_cb, NULL);
957 gtk_widget_show(file_merge_w);
958 window_present(file_merge_w);
962 static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
966 /* save file first */
967 file_save_as_cmd(after_save_merge_dialog, data);
969 case(ESD_BTN_CANCEL):
972 g_assert_not_reached();
977 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
980 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
981 /* user didn't saved his current file, ask him */
982 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
983 PRIMARY_TEXT_START "Save the capture file before merging to another one?" PRIMARY_TEXT_END "\n\n"
984 "A temporary capture file cannot be merged.");
985 simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
987 /* unchanged file, just start to merge */
988 file_merge_cmd(widget);
994 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
995 gchar *cf_name, *rfilter, *s;
996 GtkWidget *filter_te, *rb;
997 dfilter_t *rfcode = NULL;
1000 char *in_filenames[2];
1002 char tmpname[128+1];
1004 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1005 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1007 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1009 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
1010 rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
1011 if (!dfilter_compile(rfilter, &rfcode)) {
1012 bad_dfilter_alert_box(rfilter);
1017 /* Perhaps the user specified a directory instead of a file.
1018 Check whether they did. */
1019 if (test_for_directory(cf_name) == EISDIR) {
1020 /* It's a directory - set the file selection box to display that
1021 directory, don't try to open the directory as a capture file. */
1022 set_last_open_dir(cf_name);
1024 file_selection_set_current_folder(fs, get_last_open_dir());
1028 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
1030 /* merge or append the two files */
1031 rb = OBJECT_GET_DATA(w, E_MERGE_CHRONO_KEY);
1032 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1033 /* chonological order */
1034 in_filenames[0] = cfile.filename;
1035 in_filenames[1] = cf_name;
1036 merge_ok = merge_n_files(out_fd, 2, in_filenames, filetype, FALSE, &err);
1038 rb = OBJECT_GET_DATA(w, E_MERGE_PREPEND_KEY);
1039 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1041 in_filenames[0] = cfile.filename;
1042 in_filenames[1] = cf_name;
1043 merge_ok = merge_n_files(out_fd, 2, in_filenames, filetype, TRUE, &err);
1046 in_filenames[0] = cf_name;
1047 in_filenames[1] = cfile.filename;
1048 merge_ok = merge_n_files(out_fd, 2, in_filenames, filetype, TRUE, &err);
1056 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1057 "An error occurred while merging the files: %s.",
1058 wtap_strerror(err));
1061 dfilter_free(rfcode);
1067 /* We've crossed the Rubicon; get rid of the file selection box. */
1068 window_destroy(GTK_WIDGET (fs));
1070 /* Try to open the merged capture file. */
1071 if ((err = cf_open(tmpname, TRUE /* temporary file */, &cfile)) != 0) {
1072 /* We couldn't open it; don't dismiss the open dialog box,
1073 just leave it around so that the user can, after they
1074 dismiss the alert box popped up for the open error,
1077 dfilter_free(rfcode);
1081 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
1082 it closed the previous capture file, and thus destroyed any
1083 previous read filter attached to "cf"). */
1084 cfile.rfcode = rfcode;
1086 switch (cf_read(&cfile)) {
1090 /* Just because we got an error, that doesn't mean we were unable
1091 to read any of the file; we handle what we could get from the
1096 /* The user bailed out of re-reading the capture file; the
1097 capture file has been closed - just free the capture file name
1098 string and return (without changing the last containing
1103 /* Save the name of the containing directory specified in the path name,
1104 if any; we can write over cf_merged_name, which is a good thing, given that
1105 "get_dirname()" does write over its argument. */
1106 s = get_dirname(tmpname);
1107 set_last_open_dir(s);
1108 gtk_widget_grab_focus(packet_list);
1112 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1114 /* Note that we no longer have a "Merge Capture File" dialog box. */
1115 file_merge_w = NULL;
1119 void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1123 /* save file first */
1124 file_save_as_cmd(after_save_close_file, NULL);
1126 case(ESD_BTN_DONT_SAVE):
1129 case(ESD_BTN_CANCEL):
1132 g_assert_not_reached();
1138 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1141 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1142 /* user didn't saved his current file, ask him */
1143 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1144 PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
1145 "If you close without saving, your capture data will be discarded.");
1147 simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
1149 /* unchanged file, just close it */
1155 file_save_cmd_cb(GtkWidget *w, gpointer data) {
1156 /* If the file's already been saved, do nothing. */
1157 if (cfile.user_saved)
1160 /* Do a "Save As". */
1161 file_save_as_cmd_cb(w, data);
1165 can_save_with_wiretap(int ft)
1167 /* To save a file with Wiretap, Wiretap has to handle that format,
1168 and its code to handle that format must be able to write a file
1169 with this file's encapsulation type. */
1170 return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
1174 /* Generate a list of the file types we can save this file as.
1176 "filetype" is the type it has now.
1178 "encap" is the encapsulation for its packets (which could be
1179 "unknown" or "per-packet").
1181 "filtered" is TRUE if we're to save only the packets that passed
1182 the display filter (in which case we have to save it using Wiretap)
1183 and FALSE if we're to save the entire file (in which case, if we're
1184 saving it in the type it has already, we can just copy it).
1186 The same applies for sel_curr, sel_all, sel_m_only, sel_m_range and sel_man_range
1189 set_file_type_list(GtkWidget *option_menu)
1191 GtkWidget *ft_menu, *ft_menu_item;
1194 guint item_to_select;
1196 /* Default to the first supported file type, if the file's current
1197 type isn't supported. */
1200 ft_menu = gtk_menu_new();
1202 /* Check all file types. */
1204 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
1205 if (!packet_range_process_all(&range) || ft != cfile.cd_t) {
1206 /* not all unfiltered packets or a different file type. We have to use Wiretap. */
1207 if (!can_save_with_wiretap(ft))
1208 continue; /* We can't. */
1211 /* OK, we can write it out in this type. */
1212 ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
1213 if (ft == filetype) {
1214 /* Default to the same format as the file, if it's supported. */
1215 item_to_select = index;
1217 SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
1218 GINT_TO_POINTER(ft));
1219 gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
1220 gtk_widget_show(ft_menu_item);
1224 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
1225 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
1229 select_file_type_cb(GtkWidget *w _U_, gpointer data)
1231 int new_filetype = GPOINTER_TO_INT(data);
1233 if (filetype != new_filetype) {
1234 /* We can select only the filtered or marked packets to be saved if we can
1235 use Wiretap to save the file. */
1236 if (range_tb != NULL)
1237 range_set_displayed_sensitive(range_tb, can_save_with_wiretap(new_filetype));
1238 filetype = new_filetype;
1239 file_set_save_marked_sensitive();
1245 * Set the "Save only marked packets" toggle button as appropriate for
1246 * the current output file type and count of marked packets.
1248 * Called when the "Save As..." dialog box is created and when either
1249 * the file type or the marked count changes.
1252 file_set_save_marked_sensitive(void)
1254 if (file_save_as_w == NULL) {
1255 /* We don't currently have a "Save As..." dialog box up. */
1259 /* We can request that only the marked packets be saved only if we
1260 can use Wiretap to save the file and if there *are* marked packets. */
1261 if (can_save_with_wiretap(filetype) && cfile.marked_count > 0) {
1262 range_set_marked_sensitive(range_tb, TRUE);
1265 /* Force the "Save only marked packets" toggle to "false", turn
1266 off the flag it controls, and update the list of types we can
1267 save the file as. */
1268 range.process = range_process_all;
1269 set_file_type_list(ft_om);
1270 range_set_marked_sensitive(range_tb, FALSE);
1275 action_after_save_e action_after_save_g;
1276 gpointer action_after_save_data_g;
1280 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
1282 GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr;
1283 GtkTooltips *tooltips;
1285 #if GTK_MAJOR_VERSION < 2
1286 GtkAccelGroup *accel_group;
1289 if (file_save_as_w != NULL) {
1290 /* There's already an "Save Capture File As" dialog box; reactivate it. */
1291 reactivate_window(file_save_as_w);
1295 /* Default to saving all packets, in the file's current format. */
1296 filetype = cfile.cd_t;
1298 /* init the packet range */
1299 packet_range_init(&range);
1301 /* Enable tooltips */
1302 tooltips = gtk_tooltips_new();
1304 /* build the file selection */
1305 file_save_as_w = file_selection_new ("Ethereal: Save Capture File As",
1306 FILE_SELECTION_SAVE);
1308 /* as the dialog might already be gone, when using this values, we cannot
1309 * set data to the dialog object, but keep global values */
1310 action_after_save_g = action_after_save;
1311 action_after_save_data_g = action_after_save_data;
1313 #if GTK_MAJOR_VERSION < 2
1314 accel_group = gtk_accel_group_new();
1315 gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
1318 /* Container for each row of widgets */
1320 main_vb = gtk_vbox_new(FALSE, 5);
1321 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1322 file_selection_set_extra_widget(file_save_as_w, main_vb);
1323 gtk_widget_show(main_vb);
1325 /*** Packet Range frame ***/
1326 range_fr = gtk_frame_new("Packet Range");
1327 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1328 gtk_widget_show(range_fr);
1331 range_tb = range_new(&range
1332 #if GTK_MAJOR_VERSION < 2
1336 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1337 gtk_widget_show(range_tb);
1340 ft_hb = gtk_hbox_new(FALSE, 3);
1341 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1342 gtk_widget_show(ft_hb);
1344 ft_lb = gtk_label_new("File type:");
1345 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1346 gtk_widget_show(ft_lb);
1348 ft_om = gtk_option_menu_new();
1350 /* Generate the list of file types we can save. */
1351 set_file_type_list(ft_om);
1352 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1353 gtk_widget_show(ft_om);
1356 * Set the sensitivity of the "Save only marked packets" toggle
1359 * This has to be done after we create the file type menu option,
1360 * as the routine that sets it also sets that menu.
1362 file_set_save_marked_sensitive();
1364 /* dynamic values in the range frame */
1365 range_update_dynamics(range_tb);
1367 SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
1369 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1370 if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) {
1371 file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1373 window_destroy(file_save_as_w);
1376 /* Connect the ok_button to file_save_as_ok_cb function and pass along a
1377 pointer to the file selection box widget */
1378 SIGNAL_CONNECT(GTK_FILE_SELECTION (file_save_as_w)->ok_button, "clicked",
1379 file_save_as_ok_cb, file_save_as_w);
1381 window_set_cancel_button(file_save_as_w,
1382 GTK_FILE_SELECTION(file_save_as_w)->cancel_button, window_cancel_button_cb);
1384 SIGNAL_CONNECT(file_save_as_w, "delete_event", window_delete_event_cb, NULL);
1386 gtk_widget_show(file_save_as_w);
1387 window_present(file_save_as_w);
1392 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1394 file_save_as_cmd(after_save_no_action, NULL);
1398 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1402 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1403 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1405 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1408 /* Perhaps the user specified a directory instead of a file.
1409 Check whether they did. */
1410 if (test_for_directory(cf_name) == EISDIR) {
1411 /* It's a directory - set the file selection box to display that
1412 directory, and leave the selection box displayed. */
1413 set_last_open_dir(cf_name);
1415 file_selection_set_current_folder(fs, get_last_open_dir());
1419 /* Check whether the range is valid. */
1420 if (!range_check_validity(&range)) {
1421 /* The range isn't valid; don't dismiss the open dialog box,
1422 just leave it around so that the user can, after they
1423 dismiss the alert box popped up for the error, try again. */
1425 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1426 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1427 * as this will prevent the user from closing the now existing error
1428 * message, simply close the dialog (this is the best we can do here). */
1430 window_destroy(GTK_WIDGET (fs));
1432 gtk_widget_show(GTK_WIDGET (fs));
1437 /* don't show the dialog while saving */
1438 gtk_widget_hide(GTK_WIDGET (fs));
1440 /* Write out the packets (all, or only the ones from the current
1441 range) to the file with the specified name. */
1442 if (! cf_save(cf_name, &cfile, &range, filetype)) {
1443 /* The write failed; don't dismiss the open dialog box,
1444 just leave it around so that the user can, after they
1445 dismiss the alert box popped up for the error, try again. */
1447 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1448 /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1449 * as this will prevent the user from closing the now existing error
1450 * message, simply close the dialog (this is the best we can do here). */
1452 window_destroy(GTK_WIDGET (fs));
1454 gtk_widget_show(GTK_WIDGET (fs));
1459 /* The write succeeded; get rid of the file selection box. */
1460 /* cf_save might already closed our dialog! */
1462 window_destroy(GTK_WIDGET (fs));
1464 /* Save the directory name for future file dialogs. */
1465 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1466 set_last_open_dir(dirname);
1469 /* we have finished saving, do we have pending things to do? */
1470 switch(action_after_save_g) {
1471 case(after_save_no_action):
1473 case(after_save_open_dialog):
1474 file_open_cmd(action_after_save_data_g);
1476 case(after_save_open_recent_file):
1477 menu_open_recent_file_cmd(action_after_save_data_g);
1479 case(after_save_open_dnd_file):
1480 dnd_open_file_cmd(action_after_save_data_g);
1482 case(after_save_merge_dialog):
1483 file_merge_cmd(action_after_save_data_g);
1486 case(after_save_capture_dialog):
1490 case(after_save_close_file):
1493 case(after_save_exit):
1497 g_assert_not_reached();
1500 action_after_save_g = after_save_no_action;
1504 file_save_as_destroy(void)
1507 window_destroy(file_save_as_w);
1511 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1513 /* Note that we no longer have a "Save Capture File As" dialog box. */
1514 file_save_as_w = NULL;
1517 /* Reload a file using the current read and display filters */
1519 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1523 /******************** Color Filters *********************************/
1525 * Keep a static pointer to the current "Color Export" window, if
1526 * any, so that if somebody tries to do "Export"
1527 * while there's already a "Color Export" window up, we just pop
1528 * up the existing one, rather than creating a new one.
1530 static GtkWidget *file_color_import_w;
1532 /* sets the file path to the global color filter file.
1533 WARNING: called by both the import and the export dialog.
1536 color_global_cb(GtkWidget *widget _U_, gpointer data)
1538 GtkWidget *fs_widget = data;
1541 /* decide what file to open (from dfilter code) */
1542 path = get_datafile_path("colorfilters");
1544 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1545 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1547 file_selection_set_current_folder(fs_widget, path);
1549 g_free((gchar *)path);
1552 /* Import color filters */
1554 file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
1556 GtkWidget *main_vb, *cfglobal_but;
1557 #if GTK_MAJOR_VERSION < 2
1558 GtkAccelGroup *accel_group;
1560 /* No Apply button, and "OK" just sets our text widget, it doesn't
1561 activate it (i.e., it doesn't cause us to try to open the file). */
1563 if (file_color_import_w != NULL) {
1564 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1565 reactivate_window(file_color_import_w);
1569 file_color_import_w = file_selection_new("Ethereal: Import Color Filters",
1570 FILE_SELECTION_OPEN);
1572 #if GTK_MAJOR_VERSION < 2
1573 /* Accelerator group for the accelerators (or, as they're called in
1574 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1575 Ctrl+<key> is an accelerator). */
1576 accel_group = gtk_accel_group_new();
1577 gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1580 /* Container for each row of widgets */
1581 main_vb = gtk_vbox_new(FALSE, 3);
1582 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1583 file_selection_set_extra_widget(file_color_import_w, main_vb);
1584 gtk_widget_show(main_vb);
1587 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1588 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1589 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1590 gtk_widget_show(cfglobal_but);
1592 SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1594 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1595 OBJECT_SET_DATA(file_color_import_w, ARGUMENT_CL, data);
1597 if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1599 file_color_import_ok_cb(file_color_import_w, file_color_import_w);
1601 else window_destroy(file_color_import_w);
1603 /* Connect the ok_button to file_open_ok_cb function and pass along a
1604 pointer to the file selection box widget */
1605 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1606 file_color_import_ok_cb, file_color_import_w);
1608 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
1611 window_set_cancel_button(file_color_import_w,
1612 GTK_FILE_SELECTION(file_color_import_w)->cancel_button, window_cancel_button_cb);
1614 SIGNAL_CONNECT(file_color_import_w, "delete_event", window_delete_event_cb, NULL);
1617 gtk_widget_show(file_color_import_w);
1618 window_present(file_color_import_w);
1623 file_color_import_ok_cb(GtkWidget *w, gpointer fs) {
1627 argument = OBJECT_GET_DATA(w, ARGUMENT_CL); /* to be passed back into read_other_filters */
1629 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1630 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1632 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1634 /* Perhaps the user specified a directory instead of a file.
1635 Check whether they did. */
1636 if (test_for_directory(cf_name) == EISDIR) {
1637 /* It's a directory - set the file selection box to display that
1638 directory, don't try to open the directory as a capture file. */
1639 set_last_open_dir(cf_name);
1641 file_selection_set_current_folder(fs, get_last_open_dir());
1645 /* Try to open the capture file. */
1647 if (!read_other_filters(cf_name, argument)) {
1648 /* We couldn't open it; don't dismiss the open dialog box,
1649 just leave it around so that the user can, after they
1650 dismiss the alert box popped up for the open error,
1656 /* We've crossed the Rubicon; get rid of the file selection box. */
1657 window_destroy(GTK_WIDGET (fs));
1659 /* Save the name of the containing directory specified in the path name,
1660 if any; we can write over cf_name, which is a good thing, given that
1661 "get_dirname()" does write over its argument. */
1662 s = get_dirname(cf_name);
1663 set_last_open_dir(s);
1664 gtk_widget_grab_focus(packet_list);
1670 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1672 /* Note that we no longer have a "Open Capture File" dialog box. */
1673 file_color_import_w = NULL;
1676 static GtkWidget *file_color_export_w;
1678 * Set the "Export only marked filters" toggle button as appropriate for
1679 * the current output file type and count of marked filters.
1681 * Called when the "Export" dialog box is created and when the marked
1685 color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
1687 if (file_color_export_w == NULL) {
1688 /* We don't currently have an "Export" dialog box up. */
1692 /* We can request that only the marked filters be saved only if
1693 there *are* marked filters. */
1694 if (color_marked_count() != 0)
1695 gtk_widget_set_sensitive(cfmark_cb, TRUE);
1697 /* Force the "Export only marked filters" toggle to "false", turn
1698 off the flag it controls. */
1699 color_marked = FALSE;
1700 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1701 gtk_widget_set_sensitive(cfmark_cb, FALSE);
1706 color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
1708 color_marked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1712 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1714 GtkWidget *main_vb, *cfglobal_but;
1716 if (file_color_export_w != NULL) {
1717 /* There's already an "Color Filter Export" dialog box; reactivate it. */
1718 reactivate_window(file_color_export_w);
1722 /* Default to saving all packets, in the file's current format. */
1723 color_marked = FALSE;
1724 filetype = cfile.cd_t;
1726 file_color_export_w = file_selection_new("Ethereal: Export Color Filters",
1727 FILE_SELECTION_SAVE);
1729 /* Container for each row of widgets */
1730 main_vb = gtk_vbox_new(FALSE, 3);
1731 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1732 file_selection_set_extra_widget(file_color_export_w, main_vb);
1733 gtk_widget_show(main_vb);
1735 cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
1736 gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
1737 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1738 SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
1739 gtk_widget_show(cfmark_cb);
1740 color_set_export_marked_sensitive(cfmark_cb);
1742 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1743 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1744 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1745 gtk_widget_show(cfglobal_but);
1747 SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1749 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1750 if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1752 file_color_export_ok_cb(file_color_export_w, file_color_export_w);
1754 else window_destroy(file_color_export_w);
1756 /* Connect the ok_button to file_export_ok_cb function and pass along a
1757 pointer to the file selection box widget */
1758 SIGNAL_CONNECT(GTK_FILE_SELECTION (file_color_export_w)->ok_button, "clicked",
1759 file_color_export_ok_cb, file_color_export_w);
1761 window_set_cancel_button(file_color_export_w,
1762 GTK_FILE_SELECTION(file_color_export_w)->cancel_button, window_cancel_button_cb);
1764 SIGNAL_CONNECT(file_color_export_w, "delete_event", window_delete_event_cb, NULL);
1767 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1769 gtk_widget_show(file_color_export_w);
1770 window_present(file_color_export_w);
1775 file_color_export_ok_cb(GtkWidget *w _U_, gpointer fs) {
1779 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1780 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1782 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1785 /* Perhaps the user specified a directory instead of a file.
1786 Check whether they did. */
1787 if (test_for_directory(cf_name) == EISDIR) {
1788 /* It's a directory - set the file selection box to display that
1789 directory, and leave the selection box displayed. */
1790 set_last_open_dir(cf_name);
1792 file_selection_set_current_folder(fs, get_last_open_dir());
1796 /* Write out the filters (all, or only the ones that are currently
1797 displayed or marked) to the file with the specified name. */
1799 if (!write_other_filters(cf_name, color_marked))
1801 /* The write failed; don't dismiss the open dialog box,
1802 just leave it around so that the user can, after they
1803 dismiss the alert box popped up for the error, try again. */
1809 /* The write succeeded; get rid of the file selection box. */
1810 window_destroy(GTK_WIDGET (fs));
1812 /* Save the directory name for future file dialogs. */
1813 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1814 set_last_open_dir(dirname);
1819 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1821 file_color_export_w = NULL;