2 * Dialog boxes for handling files
4 * $Id: file_dlg.c,v 1.128 2004/07/13 07:15:44 guy Exp $
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.
34 #include <epan/filesystem.h>
37 #include "gtkglobals.h"
38 #include <epan/resolv.h>
40 #include "filter_prefs.h"
42 #include "alert_box.h"
43 #include "simple_dialog.h"
45 #include "dlg_utils.h"
48 #include "compat_macros.h"
52 #include "../ui_util.h"
53 #include "gtk/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);
82 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
83 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
84 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
86 #define E_MERGE_PREPEND_KEY "merge_dlg_prepend_key"
87 #define E_MERGE_CHRONO_KEY "merge_dlg_chrono_key"
88 #define E_MERGE_APPEND_KEY "merge_dlg_append_key"
90 #define ARGUMENT_CL "argument_cl"
93 #define PREVIEW_TABLE_KEY "preview_table_key"
94 #define PREVIEW_FILENAME_KEY "preview_filename_key"
95 #define PREVIEW_FORMAT_KEY "preview_format_key"
96 #define PREVIEW_SIZE_KEY "preview_size_key"
97 #define PREVIEW_ELAPSED_KEY "preview_elapsed_key"
98 #define PREVIEW_PACKETS_KEY "preview_packets_key"
99 #define PREVIEW_FIRST_KEY "preview_first_key"
103 * Keep a static pointer to the current "Save Capture File As" window, if
104 * any, so that if somebody tries to do "File:Save" or "File:Save As"
105 * while there's already a "Save Capture File As" window up, we just pop
106 * up the existing one, rather than creating a new one.
108 static GtkWidget *file_save_as_w;
111 #ifdef HAVE_SYS_STAT_H
112 #include <sys/stat.h>
115 #define PREVIEW_STR_MAX 200
116 #define PREVIEW_TIMEOUT_SECS 3
119 secs_usecs( guint32 s, guint32 us)
121 return (us / 1000000.0) + (double)s;
125 /* set a new filename for the preview widget */
127 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
131 const struct wtap_pkthdr *phdr;
136 gchar string_buff[PREVIEW_STR_MAX];
137 unsigned int packet = 0;
138 double start_time = 0; /* seconds, with msec resolution */
139 double stop_time = 0; /* seconds, with msec resolution */
143 unsigned int elapsed_time;
146 gboolean is_breaked = FALSE;
149 label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
150 gtk_label_set_text(GTK_LABEL(label), "-");
151 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
152 gtk_label_set_text(GTK_LABEL(label), "-");
153 label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
154 gtk_label_set_text(GTK_LABEL(label), "-");
155 label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
156 gtk_label_set_text(GTK_LABEL(label), "-");
157 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
158 gtk_label_set_text(GTK_LABEL(label), "-");
159 label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
160 gtk_label_set_text(GTK_LABEL(label), "-");
166 label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
167 gtk_label_set_text(GTK_LABEL(label), get_basename((char *)cf_name));
169 if (test_for_directory(cf_name) == EISDIR) {
170 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
171 gtk_label_set_text(GTK_LABEL(label), "directory");
175 wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
177 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
178 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
179 gtk_label_set_text(GTK_LABEL(label), "unknown file format");
181 gtk_label_set_text(GTK_LABEL(label), "error opening file");
186 /* Find the size of the file. */
187 if (fstat(wtap_fd(wth), &cf_stat) < 0) {
193 filesize = cf_stat.st_size;
194 g_snprintf(string_buff, PREVIEW_STR_MAX, "%" PRIu64 " bytes", filesize);
195 label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
196 gtk_label_set_text(GTK_LABEL(label), string_buff);
199 g_snprintf(string_buff, PREVIEW_STR_MAX, "%s", wtap_file_type_string(wtap_file_type(wth)));
200 label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
201 gtk_label_set_text(GTK_LABEL(label), string_buff);
204 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
205 phdr = wtap_phdr(wth);
206 cur_time = secs_usecs(phdr->ts.tv_sec, phdr->ts.tv_usec);
208 start_time = cur_time;
209 stop_time = cur_time;
211 if (cur_time < start_time) {
212 start_time = cur_time;
214 if (cur_time > stop_time){
215 stop_time = cur_time;
220 if(time_current-time_preview >= PREVIEW_TIMEOUT_SECS) {
228 g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packet);
229 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
230 gtk_label_set_text(GTK_LABEL(label), string_buff);
237 g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packet);
239 g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packet);
241 label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
242 gtk_label_set_text(GTK_LABEL(label), string_buff);
245 ti_time = (long)start_time;
246 ti_tm = localtime( &ti_time );
247 g_snprintf(string_buff, PREVIEW_STR_MAX,
248 "%04d-%02d-%02d %02d:%02d:%02d",
249 ti_tm->tm_year + 1900,
255 label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
256 gtk_label_set_text(GTK_LABEL(label), string_buff);
259 elapsed_time = (unsigned int)(stop_time-start_time);
260 if(elapsed_time/86400) {
261 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u",
262 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
264 g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u",
265 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
268 g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
270 label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
271 gtk_label_set_text(GTK_LABEL(label), string_buff);
279 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
280 simply use the same layout as in GTK1 */
281 /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
283 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
285 GtkWidget *prev = GTK_WIDGET (data);
287 gboolean have_preview;
289 cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
291 have_preview = preview_set_filename(prev, cf_name);
296 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
301 /* the text entry changed */
303 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
305 GtkWidget *prev = OBJECT_GET_DATA(file_sel, PREVIEW_TABLE_KEY);
306 const gchar* cf_name;
307 gboolean have_preview;
309 /* get the filename */
310 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
311 cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
313 cf_name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_sel));
316 /* set the filename to the preview */
317 have_preview = preview_set_filename(prev, cf_name);
319 /* make the preview widget sensitive */
320 gtk_widget_set_sensitive(prev, have_preview);
322 /* make the open/save/... dialog button sensitive */
323 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
324 gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
326 gtk_widget_set_sensitive(GTK_FILE_SELECTION(file_sel)->ok_button, have_preview);
331 /* copied from summary_dlg.c */
333 add_string_to_table_sensitive(GtkWidget *list, guint *row, gchar *title, gchar *value, gboolean sensitive)
338 if(strlen(value) != 0) {
339 indent = g_strdup_printf(" %s", title);
341 indent = g_strdup(title);
343 label = gtk_label_new(indent);
345 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
346 gtk_widget_set_sensitive(label, sensitive);
347 gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
349 label = gtk_label_new(value);
350 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
351 gtk_widget_set_sensitive(label, sensitive);
352 gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
360 add_string_to_table(GtkWidget *list, guint *row, gchar *title, gchar *value)
362 return add_string_to_table_sensitive(list, row, title, value, TRUE);
370 GtkWidget *table, *label;
373 table = gtk_table_new(1, 2, FALSE);
374 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
375 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
378 label = add_string_to_table(table, &row, "Filename:", "-");
379 WIDGET_SET_SIZE(label, DEF_WIDTH/3, -1);
380 OBJECT_SET_DATA(table, PREVIEW_FILENAME_KEY, label);
381 label = add_string_to_table(table, &row, "Format:", "-");
382 OBJECT_SET_DATA(table, PREVIEW_FORMAT_KEY, label);
383 label = add_string_to_table(table, &row, "Size:", "-");
384 OBJECT_SET_DATA(table, PREVIEW_SIZE_KEY, label);
385 label = add_string_to_table(table, &row, "Packets:", "-");
386 OBJECT_SET_DATA(table, PREVIEW_PACKETS_KEY, label);
387 label = add_string_to_table(table, &row, "First Packet:", "-");
388 OBJECT_SET_DATA(table, PREVIEW_FIRST_KEY, label);
389 label = add_string_to_table(table, &row, "Elapsed time:", "-");
390 OBJECT_SET_DATA(table, PREVIEW_ELAPSED_KEY, label);
396 * Keep a static pointer to the current "Open Capture File" window, if
397 * any, so that if somebody tries to do "File:Open" while there's already
398 * an "Open Capture File" window up, we just pop up the existing one,
399 * rather than creating a new one.
401 static GtkWidget *file_open_w;
405 file_open_cmd(GtkWidget *w)
407 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
408 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
409 #if GTK_MAJOR_VERSION < 2
410 GtkAccelGroup *accel_group;
412 /* No Apply button, and "OK" just sets our text widget, it doesn't
413 activate it (i.e., it doesn't cause us to try to open the file). */
414 static construct_args_t args = {
415 "Ethereal: Read Filter",
420 if (file_open_w != NULL) {
421 /* There's already an "Open Capture File" dialog box; reactivate it. */
422 reactivate_window(file_open_w);
426 file_open_w = file_selection_new("Ethereal: Open Capture File",
427 FILE_SELECTION_OPEN);
428 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
429 /* it's annoying, that the file chooser dialog is already shown here,
430 so we cannot use the correct gtk_window_set_default_size() to resize it */
431 WIDGET_SET_SIZE(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
433 gtk_window_set_default_size(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
436 #if GTK_MAJOR_VERSION < 2
437 /* Accelerator group for the accelerators (or, as they're called in
438 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
439 Ctrl+<key> is an accelerator). */
440 accel_group = gtk_accel_group_new();
441 gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
444 switch (prefs.gui_fileopen_style) {
446 case FO_STYLE_LAST_OPENED:
447 /* The user has specified that we should start out in the last directory
448 we looked in. If we've already opened a file, use its containing
449 directory, if we could determine it, as the directory, otherwise
450 use the "last opened" directory saved in the preferences file if
452 /* This is now the default behaviour in file_selection_new() */
455 case FO_STYLE_SPECIFIED:
456 /* The user has specified that we should always start out in a
457 specified directory; if they've specified that directory,
458 start out by showing the files in that dir. */
459 if (prefs.gui_fileopen_dir[0] != '\0')
460 file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
465 main_hb = gtk_hbox_new(FALSE, 3);
466 file_selection_set_extra_widget(file_open_w, main_hb);
467 gtk_widget_show(main_hb);
469 /* Container for each row of widgets */
470 main_vb = gtk_vbox_new(FALSE, 3);
471 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
472 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
473 gtk_widget_show(main_vb);
476 filter_hbox = gtk_hbox_new(FALSE, 1);
477 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
478 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
479 gtk_widget_show(filter_hbox);
481 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
482 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
483 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
484 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
485 gtk_widget_show(filter_bt);
487 filter_te = gtk_entry_new();
488 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
489 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
490 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
491 gtk_widget_show(filter_te);
493 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
494 OBJECT_SET_DATA(file_open_w, E_RFILTER_TE_KEY, filter_te);
496 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
497 E_RFILTER_TE_KEY, filter_te);
500 /* resolve buttons */
501 m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
502 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
503 g_resolv_flags & RESOLV_MAC);
504 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
505 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
506 OBJECT_SET_DATA(file_open_w,
507 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
509 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
510 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
512 gtk_widget_show(m_resolv_cb);
514 n_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _network name resolution", accel_group);
515 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
516 g_resolv_flags & RESOLV_NETWORK);
517 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
518 gtk_widget_show(n_resolv_cb);
519 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
520 OBJECT_SET_DATA(file_open_w, E_FILE_N_RESOLVE_KEY, n_resolv_cb);
522 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
523 E_FILE_N_RESOLVE_KEY, n_resolv_cb);
526 t_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _transport name resolution", accel_group);
527 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
528 g_resolv_flags & RESOLV_TRANSPORT);
529 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
530 gtk_widget_show(t_resolv_cb);
531 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
532 OBJECT_SET_DATA(file_open_w, E_FILE_T_RESOLVE_KEY, t_resolv_cb);
534 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
535 E_FILE_T_RESOLVE_KEY, t_resolv_cb);
539 SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
542 prev = preview_new();
543 OBJECT_SET_DATA(file_open_w, PREVIEW_TABLE_KEY, prev);
544 gtk_widget_show_all(prev);
545 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
547 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
548 SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_open_w), "selection-changed",
549 file_open_entry_changed, file_open_w);
550 file_open_entry_changed(file_open_w, file_open_w);
552 OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
553 OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
554 if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
556 file_open_ok_cb(file_open_w, file_open_w);
558 else window_destroy(file_open_w);
560 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->selection_entry, "changed",
561 file_open_entry_changed, file_open_w);
563 /* Connect the ok_button to file_open_ok_cb function and pass along a
564 pointer to the file selection box widget */
565 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
566 file_open_ok_cb, file_open_w);
568 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
569 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
571 /* Connect the cancel_button to destroy the widget */
572 window_set_cancel_button(file_open_w,
573 GTK_FILE_SELECTION(file_open_w)->cancel_button, window_cancel_button_cb);
575 SIGNAL_CONNECT(file_open_w, "delete_event", window_delete_event_cb, NULL);
577 gtk_widget_show(file_open_w);
578 window_present(file_open_w);
582 static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
586 /* save file first */
587 file_save_as_cmd(after_save_open_dialog, data);
589 case(ESD_BTN_DONT_SAVE):
593 case(ESD_BTN_CANCEL):
596 g_assert_not_reached();
601 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
604 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
605 /* user didn't saved his current file, ask him */
606 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
607 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
608 "If you open a new capture file without saving, your capture data will be discarded.");
609 simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
611 /* unchanged file, just open a new one */
612 file_open_cmd(widget);
617 file_open_ok_cb(GtkWidget *w, gpointer fs) {
618 gchar *cf_name, *rfilter, *s;
619 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
620 dfilter_t *rfcode = NULL;
623 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
624 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
626 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
628 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
629 rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
630 if (!dfilter_compile(rfilter, &rfcode)) {
631 bad_dfilter_alert_box(rfilter);
636 /* Perhaps the user specified a directory instead of a file.
637 Check whether they did. */
638 if (test_for_directory(cf_name) == EISDIR) {
639 /* It's a directory - set the file selection box to display that
640 directory, don't try to open the directory as a capture file. */
641 set_last_open_dir(cf_name);
643 file_selection_set_current_folder(fs, get_last_open_dir());
647 /* Try to open the capture file. */
648 if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
649 /* We couldn't open it; don't dismiss the open dialog box,
650 just leave it around so that the user can, after they
651 dismiss the alert box popped up for the open error,
654 dfilter_free(rfcode);
659 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
660 it closed the previous capture file, and thus destroyed any
661 previous read filter attached to "cf"). */
662 cfile.rfcode = rfcode;
664 /* Set the global resolving variable */
665 g_resolv_flags = prefs.name_resolve & RESOLV_CONCURRENT;
666 m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
667 g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)) ? RESOLV_MAC : RESOLV_NONE;
668 n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
669 g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)) ? RESOLV_NETWORK : RESOLV_NONE;
670 t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
671 g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)) ? RESOLV_TRANSPORT : RESOLV_NONE;
673 /* We've crossed the Rubicon; get rid of the file selection box. */
674 window_destroy(GTK_WIDGET (fs));
676 switch (cf_read(&cfile)) {
680 /* Just because we got an error, that doesn't mean we were unable
681 to read any of the file; we handle what we could get from the
686 /* The user bailed out of re-reading the capture file; the
687 capture file has been closed - just free the capture file name
688 string and return (without changing the last containing
694 /* Save the name of the containing directory specified in the path name,
695 if any; we can write over cf_name, which is a good thing, given that
696 "get_dirname()" does write over its argument. */
697 s = get_dirname(cf_name);
698 set_last_open_dir(s);
699 gtk_widget_grab_focus(packet_list);
705 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
707 /* Note that we no longer have a "Open Capture File" dialog box. */
712 * Keep a static pointer to the current "Marge Capture File" window, if
713 * any, so that if somebody tries to do "File:Merge" while there's already
714 * an "Merge Capture File" window up, we just pop up the existing one,
715 * rather than creating a new one.
717 static GtkWidget *file_merge_w;
719 /* Merge existing with another file */
721 file_merge_cmd(GtkWidget *w)
723 GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
724 *prepend_rb, *chrono_rb, *append_rb, *prev;
725 #if GTK_MAJOR_VERSION < 2
726 GtkAccelGroup *accel_group;
728 GtkTooltips *tooltips = gtk_tooltips_new();
729 /* No Apply button, and "OK" just sets our text widget, it doesn't
730 activate it (i.e., it doesn't cause us to try to open the file). */
731 static construct_args_t args = {
732 "Ethereal: Read Filter",
737 if (file_merge_w != NULL) {
738 /* There's already an "Merge Capture File" dialog box; reactivate it. */
739 reactivate_window(file_merge_w);
743 file_merge_w = file_selection_new("Ethereal: Merge with Capture File",
744 FILE_SELECTION_OPEN);
745 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
746 /* it's annoying, that the file chooser dialog is already shown here,
747 so we cannot use the correct gtk_window_set_default_size() to resize it */
748 WIDGET_SET_SIZE(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
750 gtk_window_set_default_size(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
753 #if GTK_MAJOR_VERSION < 2
754 /* Accelerator group for the accelerators (or, as they're called in
755 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
756 Ctrl+<key> is an accelerator). */
757 accel_group = gtk_accel_group_new();
758 gtk_window_add_accel_group(GTK_WINDOW(file_merge_w), accel_group);
761 switch (prefs.gui_fileopen_style) {
763 case FO_STYLE_LAST_OPENED:
764 /* The user has specified that we should start out in the last directory
765 we looked in. If we've already opened a file, use its containing
766 directory, if we could determine it, as the directory, otherwise
767 use the "last opened" directory saved in the preferences file if
769 /* This is now the default behaviour in file_selection_new() */
772 case FO_STYLE_SPECIFIED:
773 /* The user has specified that we should always start out in a
774 specified directory; if they've specified that directory,
775 start out by showing the files in that dir. */
776 if (prefs.gui_fileopen_dir[0] != '\0')
777 file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
781 main_hb = gtk_hbox_new(FALSE, 3);
782 file_selection_set_extra_widget(file_merge_w, main_hb);
783 gtk_widget_show(main_hb);
785 /* Container for each row of widgets */
786 main_vb = gtk_vbox_new(FALSE, 3);
787 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
788 gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
789 gtk_widget_show(main_vb);
791 filter_hbox = gtk_hbox_new(FALSE, 1);
792 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
793 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
794 gtk_widget_show(filter_hbox);
796 filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
797 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
798 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
799 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
800 gtk_widget_show(filter_bt);
802 filter_te = gtk_entry_new();
803 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
804 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
805 SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
806 gtk_widget_show(filter_te);
808 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
809 OBJECT_SET_DATA(file_merge_w, E_RFILTER_TE_KEY, filter_te);
811 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
812 E_RFILTER_TE_KEY, filter_te);
815 prepend_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Prepend packets to existing file", accel_group);
816 gtk_tooltips_set_tip(tooltips, prepend_rb,
817 "The resulting file contains the packets from the selected, followed by the packets from the currently loaded file,"
818 " the packet timestamps will be ignored.", NULL);
819 gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
820 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
821 OBJECT_SET_DATA(file_merge_w,
822 E_MERGE_PREPEND_KEY, prepend_rb);
824 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
825 E_MERGE_PREPEND_KEY, prepend_rb);
827 gtk_widget_show(prepend_rb);
829 chrono_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Merge packets chronologically", accel_group);
830 gtk_tooltips_set_tip(tooltips, chrono_rb,
831 "The resulting file contains all the packets from the currently loaded and the selected file,"
832 " sorted by the packet timestamps.", NULL);
833 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
834 gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
835 gtk_widget_show(chrono_rb);
836 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
837 OBJECT_SET_DATA(file_merge_w, E_MERGE_CHRONO_KEY, chrono_rb);
839 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
840 E_MERGE_CHRONO_KEY, chrono_rb);
843 append_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Append packets to existing file", accel_group);
844 gtk_tooltips_set_tip(tooltips, append_rb,
845 "The resulting file contains the packets from the currently loaded, followed by the packets from the selected file,"
846 " the packet timestamps will be ignored.", NULL);
847 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(append_rb),
848 g_resolv_flags & RESOLV_TRANSPORT);
849 gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
850 gtk_widget_show(append_rb);
851 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
852 OBJECT_SET_DATA(file_merge_w, E_MERGE_APPEND_KEY, append_rb);
854 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
855 E_MERGE_APPEND_KEY, append_rb);
859 SIGNAL_CONNECT(file_merge_w, "destroy", file_merge_destroy_cb, NULL);
862 prev = preview_new();
863 OBJECT_SET_DATA(file_merge_w, PREVIEW_TABLE_KEY, prev);
864 gtk_widget_show_all(prev);
865 gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
867 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
868 SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_merge_w), "selection-changed",
869 file_open_entry_changed, file_merge_w);
870 file_open_entry_changed(file_merge_w, file_merge_w);
872 OBJECT_SET_DATA(file_merge_w, E_DFILTER_TE_KEY,
873 OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
874 if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
876 file_merge_ok_cb(file_merge_w, file_merge_w);
878 else window_destroy(file_merge_w);
880 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->selection_entry, "changed",
881 file_open_entry_changed, file_merge_w);
883 /* Connect the ok_button to file_merge_ok_cb function and pass along a
884 pointer to the file selection box widget */
885 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->ok_button, "clicked",
886 file_merge_ok_cb, file_merge_w);
888 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
889 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
891 /* Connect the cancel_button to destroy the widget */
892 window_set_cancel_button(file_merge_w,
893 GTK_FILE_SELECTION(file_merge_w)->cancel_button, window_cancel_button_cb);
895 SIGNAL_CONNECT(file_merge_w, "delete_event", window_delete_event_cb, NULL);
897 gtk_widget_show(file_merge_w);
898 window_present(file_merge_w);
902 static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
906 /* save file first */
907 file_save_as_cmd(after_save_merge_dialog, data);
909 case(ESD_BTN_CANCEL):
912 g_assert_not_reached();
917 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
920 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
921 /* user didn't saved his current file, ask him */
922 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
923 PRIMARY_TEXT_START "Save the capture file before merging to another one?" PRIMARY_TEXT_END "\n\n"
924 "A temporary capture file cannot be merged.");
925 simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
927 /* unchanged file, just start to merge */
928 file_merge_cmd(widget);
934 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
935 gchar *cf_name, *rfilter, *s;
936 GtkWidget *filter_te, *rb;
937 dfilter_t *rfcode = NULL;
940 char *in_filenames[2];
944 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
945 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
947 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
949 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
950 rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
951 if (!dfilter_compile(rfilter, &rfcode)) {
952 bad_dfilter_alert_box(rfilter);
957 /* Perhaps the user specified a directory instead of a file.
958 Check whether they did. */
959 if (test_for_directory(cf_name) == EISDIR) {
960 /* It's a directory - set the file selection box to display that
961 directory, don't try to open the directory as a capture file. */
962 set_last_open_dir(cf_name);
964 file_selection_set_current_folder(fs, get_last_open_dir());
968 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
970 /* merge or append the two files */
971 rb = OBJECT_GET_DATA(w, E_MERGE_CHRONO_KEY);
972 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
973 /* chonological order */
974 in_filenames[0] = cfile.filename;
975 in_filenames[1] = cf_name;
976 merge_ok = merge_n_files(out_fd, 2, in_filenames, FALSE, &err);
978 rb = OBJECT_GET_DATA(w, E_MERGE_PREPEND_KEY);
979 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
981 in_filenames[0] = cfile.filename;
982 in_filenames[1] = cf_name;
983 merge_ok = merge_n_files(out_fd, 2, in_filenames, TRUE, &err);
986 in_filenames[0] = cf_name;
987 in_filenames[1] = cfile.filename;
988 merge_ok = merge_n_files(out_fd, 2, in_filenames, TRUE, &err);
996 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
997 "An error occurred while merging the files: %s.",
1001 dfilter_free(rfcode);
1007 /* We've crossed the Rubicon; get rid of the file selection box. */
1008 window_destroy(GTK_WIDGET (fs));
1010 /* Try to open the merged capture file. */
1011 if ((err = cf_open(tmpname, TRUE /* temporary file */, &cfile)) != 0) {
1012 /* We couldn't open it; don't dismiss the open dialog box,
1013 just leave it around so that the user can, after they
1014 dismiss the alert box popped up for the open error,
1017 dfilter_free(rfcode);
1021 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
1022 it closed the previous capture file, and thus destroyed any
1023 previous read filter attached to "cf"). */
1024 cfile.rfcode = rfcode;
1026 switch (cf_read(&cfile)) {
1030 /* Just because we got an error, that doesn't mean we were unable
1031 to read any of the file; we handle what we could get from the
1036 /* The user bailed out of re-reading the capture file; the
1037 capture file has been closed - just free the capture file name
1038 string and return (without changing the last containing
1043 /* Save the name of the containing directory specified in the path name,
1044 if any; we can write over cf_merged_name, which is a good thing, given that
1045 "get_dirname()" does write over its argument. */
1046 s = get_dirname(tmpname);
1047 set_last_open_dir(s);
1048 gtk_widget_grab_focus(packet_list);
1052 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1054 /* Note that we no longer have a "Merge Capture File" dialog box. */
1055 file_merge_w = NULL;
1059 void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1063 /* save file first */
1064 file_save_as_cmd(after_save_close_file, NULL);
1066 case(ESD_BTN_DONT_SAVE):
1069 case(ESD_BTN_CANCEL):
1072 g_assert_not_reached();
1078 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1081 if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1082 /* user didn't saved his current file, ask him */
1083 dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1084 PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
1085 "If you close without saving, your capture data will be discarded.");
1087 simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
1089 /* unchanged file, just close it */
1095 file_save_cmd_cb(GtkWidget *w, gpointer data) {
1096 /* If the file's already been saved, do nothing. */
1097 if (cfile.user_saved)
1100 /* Do a "Save As". */
1101 file_save_as_cmd_cb(w, data);
1104 /* XXX - can we make these not be static? */
1105 static packet_range_t range;
1106 static gboolean color_marked;
1107 static int filetype;
1108 static GtkWidget *cfmark_cb;
1109 static GtkWidget *ft_om;
1110 static GtkWidget *range_tb;
1113 can_save_with_wiretap(int ft)
1115 /* To save a file with Wiretap, Wiretap has to handle that format,
1116 and its code to handle that format must be able to write a file
1117 with this file's encapsulation type. */
1118 return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
1122 /* Generate a list of the file types we can save this file as.
1124 "filetype" is the type it has now.
1126 "encap" is the encapsulation for its packets (which could be
1127 "unknown" or "per-packet").
1129 "filtered" is TRUE if we're to save only the packets that passed
1130 the display filter (in which case we have to save it using Wiretap)
1131 and FALSE if we're to save the entire file (in which case, if we're
1132 saving it in the type it has already, we can just copy it).
1134 The same applies for sel_curr, sel_all, sel_m_only, sel_m_range and sel_man_range
1137 set_file_type_list(GtkWidget *option_menu)
1139 GtkWidget *ft_menu, *ft_menu_item;
1142 guint item_to_select;
1144 /* Default to the first supported file type, if the file's current
1145 type isn't supported. */
1148 ft_menu = gtk_menu_new();
1150 /* Check all file types. */
1152 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
1153 if (!packet_range_process_all(&range) || ft != cfile.cd_t) {
1154 /* not all unfiltered packets or a different file type. We have to use Wiretap. */
1155 if (!can_save_with_wiretap(ft))
1156 continue; /* We can't. */
1159 /* OK, we can write it out in this type. */
1160 ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
1161 if (ft == filetype) {
1162 /* Default to the same format as the file, if it's supported. */
1163 item_to_select = index;
1165 SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
1166 GINT_TO_POINTER(ft));
1167 gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
1168 gtk_widget_show(ft_menu_item);
1172 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
1173 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
1177 select_file_type_cb(GtkWidget *w _U_, gpointer data)
1179 int new_filetype = GPOINTER_TO_INT(data);
1181 if (filetype != new_filetype) {
1182 /* We can select only the filtered or marked packets to be saved if we can
1183 use Wiretap to save the file. */
1184 range_set_displayed_sensitive(range_tb, can_save_with_wiretap(new_filetype));
1185 filetype = new_filetype;
1186 file_set_save_marked_sensitive();
1192 * Set the "Save only marked packets" toggle button as appropriate for
1193 * the current output file type and count of marked packets.
1195 * Called when the "Save As..." dialog box is created and when either
1196 * the file type or the marked count changes.
1199 file_set_save_marked_sensitive(void)
1201 if (file_save_as_w == NULL) {
1202 /* We don't currently have a "Save As..." dialog box up. */
1206 /* We can request that only the marked packets be saved only if we
1207 can use Wiretap to save the file and if there *are* marked packets. */
1208 if (can_save_with_wiretap(filetype) && cfile.marked_count != 0) {
1209 range_set_marked_sensitive(range_tb, TRUE);
1212 /* Force the "Save only marked packets" toggle to "false", turn
1213 off the flag it controls, and update the list of types we can
1214 save the file as. */
1215 range.process = range_process_all;
1216 set_file_type_list(ft_om);
1217 range_set_marked_sensitive(range_tb, FALSE);
1222 action_after_save_e action_after_save_g;
1223 gpointer action_after_save_data_g;
1227 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
1229 GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr;
1230 GtkTooltips *tooltips;
1232 #if GTK_MAJOR_VERSION < 2
1233 GtkAccelGroup *accel_group;
1236 if (file_save_as_w != NULL) {
1237 /* There's already an "Save Capture File As" dialog box; reactivate it. */
1238 reactivate_window(file_save_as_w);
1242 /* Default to saving all packets, in the file's current format. */
1243 filetype = cfile.cd_t;
1245 /* init the packet range */
1246 packet_range_init(&range);
1248 /* Enable tooltips */
1249 tooltips = gtk_tooltips_new();
1251 /* build the file selection */
1252 file_save_as_w = file_selection_new ("Ethereal: Save Capture File As",
1253 FILE_SELECTION_SAVE);
1255 /* as the dialog might already be gone, when using this values, we cannot
1256 * set data to the dialog object, but keep global values */
1257 action_after_save_g = action_after_save;
1258 action_after_save_data_g = action_after_save_data;
1260 #if GTK_MAJOR_VERSION < 2
1261 accel_group = gtk_accel_group_new();
1262 gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
1265 /* Container for each row of widgets */
1267 main_vb = gtk_vbox_new(FALSE, 5);
1268 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1269 file_selection_set_extra_widget(file_save_as_w, main_vb);
1270 gtk_widget_show(main_vb);
1272 /*** Packet Range frame ***/
1273 range_fr = gtk_frame_new("Packet Range");
1274 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1275 gtk_widget_show(range_fr);
1278 range_tb = range_new(&range
1279 #if GTK_MAJOR_VERSION < 2
1283 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1284 gtk_widget_show(range_tb);
1287 ft_hb = gtk_hbox_new(FALSE, 3);
1288 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1289 gtk_widget_show(ft_hb);
1291 ft_lb = gtk_label_new("File type:");
1292 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1293 gtk_widget_show(ft_lb);
1295 ft_om = gtk_option_menu_new();
1297 /* Generate the list of file types we can save. */
1298 set_file_type_list(ft_om);
1299 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1300 gtk_widget_show(ft_om);
1303 * Set the sensitivity of the "Save only marked packets" toggle
1306 * This has to be done after we create the file type menu option,
1307 * as the routine that sets it also sets that menu.
1309 file_set_save_marked_sensitive();
1311 /* dynamic values in the range frame */
1312 range_update_dynamics(range_tb);
1314 SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
1316 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1317 if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) {
1318 file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1320 window_destroy(file_save_as_w);
1323 /* Connect the ok_button to file_save_as_ok_cb function and pass along a
1324 pointer to the file selection box widget */
1325 SIGNAL_CONNECT(GTK_FILE_SELECTION (file_save_as_w)->ok_button, "clicked",
1326 file_save_as_ok_cb, file_save_as_w);
1328 window_set_cancel_button(file_save_as_w,
1329 GTK_FILE_SELECTION(file_save_as_w)->cancel_button, window_cancel_button_cb);
1331 SIGNAL_CONNECT(file_save_as_w, "delete_event", window_delete_event_cb, NULL);
1333 gtk_widget_show(file_save_as_w);
1334 window_present(file_save_as_w);
1339 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1341 file_save_as_cmd(after_save_no_action, NULL);
1345 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1349 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1350 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1352 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1355 /* Perhaps the user specified a directory instead of a file.
1356 Check whether they did. */
1357 if (test_for_directory(cf_name) == EISDIR) {
1358 /* It's a directory - set the file selection box to display that
1359 directory, and leave the selection box displayed. */
1360 set_last_open_dir(cf_name);
1362 file_selection_set_current_folder(fs, get_last_open_dir());
1366 /* don't show the dialog while saving */
1367 gtk_widget_hide(GTK_WIDGET (fs));
1369 /* Write out the packets (all, or only the ones from the current
1370 range) to the file with the specified name. */
1371 if (! cf_save(cf_name, &cfile, &range, filetype)) {
1372 /* The write failed; don't dismiss the open dialog box,
1373 just leave it around so that the user can, after they
1374 dismiss the alert box popped up for the error, try again. */
1376 gtk_widget_show(GTK_WIDGET (fs));
1380 /* The write succeeded; get rid of the file selection box. */
1381 /* cf_save might already closed our dialog! */
1383 window_destroy(GTK_WIDGET (fs));
1385 /* Save the directory name for future file dialogs. */
1386 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1387 set_last_open_dir(dirname);
1390 /* we have finished saving, do we have pending things to do? */
1391 switch(action_after_save_g) {
1392 case(after_save_no_action):
1394 case(after_save_open_dialog):
1395 file_open_cmd(action_after_save_data_g);
1397 case(after_save_open_recent_file):
1398 menu_open_recent_file_cmd(action_after_save_data_g);
1400 case(after_save_open_dnd_file):
1401 dnd_open_file_cmd(action_after_save_data_g);
1403 case(after_save_merge_dialog):
1404 file_merge_cmd(action_after_save_data_g);
1407 case(after_save_capture_dialog):
1411 case(after_save_close_file):
1414 case(after_save_exit):
1418 g_assert_not_reached();
1421 action_after_save_g = after_save_no_action;
1425 file_save_as_destroy(void)
1428 window_destroy(file_save_as_w);
1432 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1434 /* Note that we no longer have a "Save Capture File As" dialog box. */
1435 file_save_as_w = NULL;
1438 /* Reload a file using the current read and display filters */
1440 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1442 gboolean is_tempfile;
1444 /* If the file could be opened, "cf_open()" calls "cf_close()"
1445 to get rid of state for the old capture file before filling in state
1446 for the new capture file. "cf_close()" will remove the file if
1447 it's a temporary file; we don't want that to happen (for one thing,
1448 it'd prevent subsequent reopens from working). Remember whether it's
1449 a temporary file, mark it as not being a temporary file, and then
1450 reopen it as the type of file it was.
1452 Also, "cf_close()" will free "cfile.filename", so we must make
1453 a copy of it first. */
1454 filename = g_strdup(cfile.filename);
1455 is_tempfile = cfile.is_tempfile;
1456 cfile.is_tempfile = FALSE;
1457 if (cf_open(filename, is_tempfile, &cfile) == 0) {
1458 switch (cf_read(&cfile)) {
1462 /* Just because we got an error, that doesn't mean we were unable
1463 to read any of the file; we handle what we could get from the
1468 /* The user bailed out of re-reading the capture file; the
1469 capture file has been closed - just free the capture file name
1470 string and return (without changing the last containing
1476 /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
1477 Instead, the file was left open, so we should restore "cfile.is_tempfile"
1480 XXX - change the menu? Presumably "cf_open()" will do that;
1481 make sure it does! */
1482 cfile.is_tempfile = is_tempfile;
1484 /* "cf_open()" made a copy of the file name we handed it, so
1485 we should free up our copy. */
1489 /******************** Color Filters *********************************/
1491 * Keep a static pointer to the current "Color Export" window, if
1492 * any, so that if somebody tries to do "Export"
1493 * while there's already a "Color Export" window up, we just pop
1494 * up the existing one, rather than creating a new one.
1496 static GtkWidget *file_color_import_w;
1498 /* sets the file path to the global color filter file.
1499 WARNING: called by both the import and the export dialog.
1502 color_global_cb(GtkWidget *widget _U_, gpointer data)
1504 GtkWidget *fs_widget = data;
1507 /* decide what file to open (from dfilter code) */
1508 path = get_datafile_path("colorfilters");
1510 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1511 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1513 file_selection_set_current_folder(fs_widget, path);
1515 g_free((gchar *)path);
1518 /* Import color filters */
1520 file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
1522 GtkWidget *main_vb, *cfglobal_but;
1523 #if GTK_MAJOR_VERSION < 2
1524 GtkAccelGroup *accel_group;
1526 /* No Apply button, and "OK" just sets our text widget, it doesn't
1527 activate it (i.e., it doesn't cause us to try to open the file). */
1529 if (file_color_import_w != NULL) {
1530 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1531 reactivate_window(file_color_import_w);
1535 file_color_import_w = file_selection_new("Ethereal: Import Color Filters",
1536 FILE_SELECTION_OPEN);
1538 #if GTK_MAJOR_VERSION < 2
1539 /* Accelerator group for the accelerators (or, as they're called in
1540 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1541 Ctrl+<key> is an accelerator). */
1542 accel_group = gtk_accel_group_new();
1543 gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1546 /* Container for each row of widgets */
1547 main_vb = gtk_vbox_new(FALSE, 3);
1548 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1549 file_selection_set_extra_widget(file_color_import_w, main_vb);
1550 gtk_widget_show(main_vb);
1553 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1554 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1555 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1556 gtk_widget_show(cfglobal_but);
1558 SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1560 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1561 OBJECT_SET_DATA(file_color_import_w, ARGUMENT_CL, data);
1563 if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1565 file_color_import_ok_cb(file_color_import_w, file_color_import_w);
1567 else window_destroy(file_color_import_w);
1569 /* Connect the ok_button to file_open_ok_cb function and pass along a
1570 pointer to the file selection box widget */
1571 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1572 file_color_import_ok_cb, file_color_import_w);
1574 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
1577 window_set_cancel_button(file_color_import_w,
1578 GTK_FILE_SELECTION(file_color_import_w)->cancel_button, window_cancel_button_cb);
1580 SIGNAL_CONNECT(file_color_import_w, "delete_event", window_delete_event_cb, NULL);
1583 gtk_widget_show(file_color_import_w);
1584 window_present(file_color_import_w);
1589 file_color_import_ok_cb(GtkWidget *w, gpointer fs) {
1593 argument = OBJECT_GET_DATA(w, ARGUMENT_CL); /* to be passed back into read_other_filters */
1595 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1596 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1598 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1600 /* Perhaps the user specified a directory instead of a file.
1601 Check whether they did. */
1602 if (test_for_directory(cf_name) == EISDIR) {
1603 /* It's a directory - set the file selection box to display that
1604 directory, don't try to open the directory as a capture file. */
1605 set_last_open_dir(cf_name);
1607 file_selection_set_current_folder(fs, get_last_open_dir());
1611 /* Try to open the capture file. */
1613 if (!read_other_filters(cf_name, argument)) {
1614 /* We couldn't open it; don't dismiss the open dialog box,
1615 just leave it around so that the user can, after they
1616 dismiss the alert box popped up for the open error,
1622 /* We've crossed the Rubicon; get rid of the file selection box. */
1623 window_destroy(GTK_WIDGET (fs));
1625 /* Save the name of the containing directory specified in the path name,
1626 if any; we can write over cf_name, which is a good thing, given that
1627 "get_dirname()" does write over its argument. */
1628 s = get_dirname(cf_name);
1629 set_last_open_dir(s);
1630 gtk_widget_grab_focus(packet_list);
1636 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1638 /* Note that we no longer have a "Open Capture File" dialog box. */
1639 file_color_import_w = NULL;
1642 static GtkWidget *file_color_export_w;
1644 * Set the "Export only marked filters" toggle button as appropriate for
1645 * the current output file type and count of marked filters.
1647 * Called when the "Export" dialog box is created and when the marked
1651 color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
1653 if (file_color_export_w == NULL) {
1654 /* We don't currently have an "Export" dialog box up. */
1658 /* We can request that only the marked filters be saved only if
1659 there *are* marked filters. */
1660 if (color_marked_count() != 0)
1661 gtk_widget_set_sensitive(cfmark_cb, TRUE);
1663 /* Force the "Export only marked filters" toggle to "false", turn
1664 off the flag it controls. */
1665 color_marked = FALSE;
1666 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1667 gtk_widget_set_sensitive(cfmark_cb, FALSE);
1672 color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
1674 color_marked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1678 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1680 GtkWidget *main_vb, *cfglobal_but;
1682 if (file_color_export_w != NULL) {
1683 /* There's already an "Color Filter Export" dialog box; reactivate it. */
1684 reactivate_window(file_color_export_w);
1688 /* Default to saving all packets, in the file's current format. */
1689 color_marked = FALSE;
1690 filetype = cfile.cd_t;
1692 file_color_export_w = file_selection_new("Ethereal: Export Color Filters",
1693 FILE_SELECTION_SAVE);
1695 /* Container for each row of widgets */
1696 main_vb = gtk_vbox_new(FALSE, 3);
1697 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1698 file_selection_set_extra_widget(file_color_export_w, main_vb);
1699 gtk_widget_show(main_vb);
1701 cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
1702 gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
1703 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1704 SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
1705 gtk_widget_show(cfmark_cb);
1706 color_set_export_marked_sensitive(cfmark_cb);
1708 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1709 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1710 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1711 gtk_widget_show(cfglobal_but);
1713 SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1715 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1716 if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1718 file_color_export_ok_cb(file_color_export_w, file_color_export_w);
1720 else window_destroy(file_color_export_w);
1722 /* Connect the ok_button to file_export_ok_cb function and pass along a
1723 pointer to the file selection box widget */
1724 SIGNAL_CONNECT(GTK_FILE_SELECTION (file_color_export_w)->ok_button, "clicked",
1725 file_color_export_ok_cb, file_color_export_w);
1727 window_set_cancel_button(file_color_export_w,
1728 GTK_FILE_SELECTION(file_color_export_w)->cancel_button, window_cancel_button_cb);
1730 SIGNAL_CONNECT(file_color_export_w, "delete_event", window_delete_event_cb, NULL);
1733 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1735 gtk_widget_show(file_color_export_w);
1736 window_present(file_color_export_w);
1741 file_color_export_ok_cb(GtkWidget *w _U_, gpointer fs) {
1745 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1746 cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1748 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1751 /* Perhaps the user specified a directory instead of a file.
1752 Check whether they did. */
1753 if (test_for_directory(cf_name) == EISDIR) {
1754 /* It's a directory - set the file selection box to display that
1755 directory, and leave the selection box displayed. */
1756 set_last_open_dir(cf_name);
1758 file_selection_set_current_folder(fs, get_last_open_dir());
1762 /* Write out the filters (all, or only the ones that are currently
1763 displayed or marked) to the file with the specified name. */
1765 if (!write_other_filters(cf_name, color_marked))
1767 /* The write failed; don't dismiss the open dialog box,
1768 just leave it around so that the user can, after they
1769 dismiss the alert box popped up for the error, try again. */
1775 /* The write succeeded; get rid of the file selection box. */
1776 window_destroy(GTK_WIDGET (fs));
1778 /* Save the directory name for future file dialogs. */
1779 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1780 set_last_open_dir(dirname);
1785 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1787 file_color_export_w = NULL;