added compression support for capture file output. The Save/As dialog now has a check...
[obnox/wireshark/wip.git] / gtk / file_dlg.c
1 /* file_dlg.c
2  * Dialog boxes for handling files
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <string.h>
30
31 #include <gtk/gtk.h>
32
33 #include "packet-range.h"
34 #include <epan/filesystem.h>
35
36 #include "globals.h"
37 #include "gtkglobals.h"
38 #include <epan/addr_resolv.h>
39 #include "keys.h"
40 #include "filter_dlg.h"
41 #include "gui_utils.h"
42 #include "alert_box.h"
43 #include "simple_dialog.h"
44 #include "menu.h"
45 #include "dlg_utils.h"
46 #include "file_dlg.h"
47 #include "main.h"
48 #include "compat_macros.h"
49 #include <epan/prefs.h>
50 #include "recent.h"
51 #include "color.h"
52 #include "../ui_util.h"
53 #include "color_filters.h"
54 #include "gtk/color_dlg.h"
55 #ifdef HAVE_LIBPCAP
56 #include "capture_dlg.h"
57 #endif
58 #include "range_utils.h"
59 #include "merge.h"
60 #include "util.h"
61
62 #ifdef HAVE_UNISTD_H
63 #include <unistd.h>
64 #endif
65
66 #ifdef HAVE_IO_H
67 #include <io.h> /* open/close on win32 */
68 #endif
69
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);
82
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"
86
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"
90
91 #define ARGUMENT_CL "argument_cl"
92
93
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"
101
102
103 /*
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.
108  */
109 static GtkWidget *file_save_as_w;
110
111 /* XXX - can we make these not be static? */
112 static packet_range_t range;
113 static gboolean color_marked;
114 static int filetype;
115 static GtkWidget *cfmark_cb;
116 static GtkWidget *ft_om;
117 static GtkWidget *range_tb;
118
119 #define PREVIEW_STR_MAX         200
120
121
122 /* set a new filename for the preview widget */
123 static wtap *
124 preview_set_filename(GtkWidget *prev, const gchar *cf_name)
125 {
126     GtkWidget  *label;
127     wtap       *wth;
128     int         err = 0;
129     gchar      *err_info;
130     gchar       string_buff[PREVIEW_STR_MAX];
131     gint64      filesize;
132
133
134     /* init preview labels */
135     label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
136     gtk_label_set_text(GTK_LABEL(label), "-");
137     label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
138     gtk_label_set_text(GTK_LABEL(label), "-");
139     label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
140     gtk_label_set_text(GTK_LABEL(label), "-");
141     label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
142     gtk_label_set_text(GTK_LABEL(label), "-");
143     label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
144     gtk_label_set_text(GTK_LABEL(label), "-");
145     label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
146     gtk_label_set_text(GTK_LABEL(label), "-");
147
148     if(!cf_name) {
149         return NULL;
150     }
151
152     label = OBJECT_GET_DATA(prev, PREVIEW_FILENAME_KEY);
153     gtk_label_set_text(GTK_LABEL(label), get_basename(cf_name));
154
155     if (test_for_directory(cf_name) == EISDIR) {
156         label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
157         gtk_label_set_text(GTK_LABEL(label), "directory");
158         return NULL;
159     }
160
161     wth = wtap_open_offline(cf_name, &err, &err_info, TRUE);
162     if (wth == NULL) {
163         label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
164         if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
165             gtk_label_set_text(GTK_LABEL(label), "unknown file format");
166         } else {
167             gtk_label_set_text(GTK_LABEL(label), "error opening file");
168         }
169         return NULL;
170     }
171
172     /* Find the size of the file. */
173     filesize = wtap_file_size(wth, &err);
174     if (filesize == -1) {
175         gtk_label_set_text(GTK_LABEL(label), "error getting file size");
176         wtap_close(wth);
177         return NULL;
178     }
179     g_snprintf(string_buff, PREVIEW_STR_MAX, "%" PRId64 " bytes", filesize);
180     label = OBJECT_GET_DATA(prev, PREVIEW_SIZE_KEY);
181     gtk_label_set_text(GTK_LABEL(label), string_buff);
182
183     /* type */
184     g_snprintf(string_buff, PREVIEW_STR_MAX, "%s", wtap_file_type_string(wtap_file_type(wth)));
185     label = OBJECT_GET_DATA(prev, PREVIEW_FORMAT_KEY);
186     gtk_label_set_text(GTK_LABEL(label), string_buff);
187
188     return wth;
189 }
190
191
192 /* do a preview run on the currently selected capture file */
193 static void
194 preview_do(GtkWidget *prev, wtap *wth)
195 {
196     GtkWidget  *label;
197     unsigned int elapsed_time;
198     time_t      time_preview;
199     time_t      time_current;
200     int         err = 0;
201     gchar      *err_info;
202     long        data_offset;
203     const struct wtap_pkthdr *phdr;
204     double      start_time = 0; /* seconds, with nsec resolution */
205     double      stop_time = 0;  /* seconds, with nsec resolution */
206     double      cur_time;
207     unsigned int packets = 0;
208     gboolean    is_breaked = FALSE;
209     gchar       string_buff[PREVIEW_STR_MAX];
210     time_t      ti_time;
211     struct tm  *ti_tm;
212
213
214     time(&time_preview);
215     while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
216         phdr = wtap_phdr(wth);        
217         cur_time = nstime_to_sec( (const nstime_t *) &phdr->ts );
218         if(packets == 0) {
219             start_time  = cur_time;
220             stop_time = cur_time;
221         }
222         if (cur_time < start_time) {
223             start_time = cur_time;
224         }
225         if (cur_time > stop_time){
226             stop_time = cur_time;
227         }
228
229         packets++;
230         if(packets%1000) {
231             /* do we have a timeout? */
232             time(&time_current);
233             if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
234                 is_breaked = TRUE;
235                 break;
236             }
237         }
238     }
239
240     if(err != 0) {
241         g_snprintf(string_buff, PREVIEW_STR_MAX, "error after reading %u packets", packets);
242         label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
243         gtk_label_set_text(GTK_LABEL(label), string_buff);
244         wtap_close(wth);
245         return;
246     }
247
248     /* packet count */
249     if(is_breaked) {
250         g_snprintf(string_buff, PREVIEW_STR_MAX, "more than %u packets (preview timeout)", packets);
251     } else {
252         g_snprintf(string_buff, PREVIEW_STR_MAX, "%u", packets);
253     }
254     label = OBJECT_GET_DATA(prev, PREVIEW_PACKETS_KEY);
255     gtk_label_set_text(GTK_LABEL(label), string_buff);
256
257     /* first packet */
258     ti_time = (long)start_time;
259     ti_tm = localtime( &ti_time );
260     g_snprintf(string_buff, PREVIEW_STR_MAX,
261              "%04d-%02d-%02d %02d:%02d:%02d",
262              ti_tm->tm_year + 1900,
263              ti_tm->tm_mon + 1,
264              ti_tm->tm_mday,
265              ti_tm->tm_hour,
266              ti_tm->tm_min,
267              ti_tm->tm_sec);
268     label = OBJECT_GET_DATA(prev, PREVIEW_FIRST_KEY);
269     gtk_label_set_text(GTK_LABEL(label), string_buff);
270
271     /* elapsed time */
272     elapsed_time = (unsigned int)(stop_time-start_time);
273     if(elapsed_time/86400) {
274       g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u days %02u:%02u:%02u", 
275         elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
276     } else {
277       g_snprintf(string_buff, PREVIEW_STR_MAX, "%02u:%02u:%02u", 
278         elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60);
279     }
280     if(is_breaked) {
281       g_snprintf(string_buff, PREVIEW_STR_MAX, "unknown");
282     }
283     label = OBJECT_GET_DATA(prev, PREVIEW_ELAPSED_KEY);
284     gtk_label_set_text(GTK_LABEL(label), string_buff);
285
286     wtap_close(wth);
287 }
288
289 #if 0
290 /* as the dialog layout will look very ugly when using the file chooser preview mechanism,
291    simply use the same layout as in GTK1 */
292 /* (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 */
293 static void
294 update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
295 {
296     GtkWidget *prev = GTK_WIDGET (data);
297     char *cf_name;
298     gboolean have_preview;
299
300     cf_name = gtk_file_chooser_get_preview_filename (file_chooser);
301
302     have_preview = preview_set_filename(prev, cf_name);
303
304     g_free (cf_name);
305
306     have_preview = TRUE;
307     gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
308 }
309 #endif
310
311
312 /* the filename text entry changed */
313 static void
314 file_open_entry_changed(GtkWidget *w _U_, gpointer file_sel)
315 {
316     GtkWidget *prev = OBJECT_GET_DATA(file_sel, PREVIEW_TABLE_KEY);
317     const gchar* cf_name;
318     gboolean have_preview;
319     wtap       *wth;
320
321     /* get the filename */
322 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
323     cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel));
324 #else
325     cf_name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_sel));
326 #endif
327
328     /* set the filename to the preview */
329     wth = preview_set_filename(prev, cf_name);
330     have_preview = (wth != NULL);
331
332     /* make the preview widget sensitive */
333     gtk_widget_set_sensitive(prev, have_preview);
334
335     /* make the open/save/... dialog button sensitive */
336 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
337     gtk_dialog_set_response_sensitive(file_sel, GTK_RESPONSE_ACCEPT, have_preview);
338 #else
339     gtk_widget_set_sensitive(GTK_FILE_SELECTION(file_sel)->ok_button, have_preview);
340 #endif
341
342     /* do the actual preview */
343     if(have_preview)
344         preview_do(prev, wth);
345 }
346
347
348 /* copied from summary_dlg.c */
349 static GtkWidget *
350 add_string_to_table_sensitive(GtkWidget *list, guint *row, const gchar *title, const gchar *value, gboolean sensitive)
351 {
352     GtkWidget *label;
353     gchar     *indent;
354
355     if(strlen(value) != 0) {
356         indent = g_strdup_printf("   %s", title);
357     } else {
358         indent = g_strdup(title);
359     }
360     label = gtk_label_new(indent);
361     g_free(indent);
362     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
363     gtk_widget_set_sensitive(label, sensitive);
364     gtk_table_attach_defaults(GTK_TABLE(list), label, 0, 1, *row, *row+1);
365
366     label = gtk_label_new(value);
367     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
368     gtk_widget_set_sensitive(label, sensitive);
369     gtk_table_attach_defaults(GTK_TABLE(list), label, 1, 2, *row, *row+1);
370
371     *row = *row + 1;
372
373     return label;
374 }
375
376 static GtkWidget *
377 add_string_to_table(GtkWidget *list, guint *row, const gchar *title, const gchar *value)
378 {
379     return add_string_to_table_sensitive(list, row, title, value, TRUE);
380 }
381
382
383
384 static GtkWidget *
385 preview_new(void)
386 {
387     GtkWidget *table, *label;
388     guint         row;
389
390     table = gtk_table_new(1, 2, FALSE);
391     gtk_table_set_col_spacings(GTK_TABLE(table), 6);
392     gtk_table_set_row_spacings(GTK_TABLE(table), 3);
393     row = 0;
394
395     label = add_string_to_table(table, &row, "Filename:", "-");
396     WIDGET_SET_SIZE(label, DEF_WIDTH/3, -1);
397     OBJECT_SET_DATA(table, PREVIEW_FILENAME_KEY, label);
398     label = add_string_to_table(table, &row, "Format:", "-");
399     OBJECT_SET_DATA(table, PREVIEW_FORMAT_KEY, label);
400     label = add_string_to_table(table, &row, "Size:", "-");
401     OBJECT_SET_DATA(table, PREVIEW_SIZE_KEY, label);
402     label = add_string_to_table(table, &row, "Packets:", "-");
403     OBJECT_SET_DATA(table, PREVIEW_PACKETS_KEY, label);
404     label = add_string_to_table(table, &row, "First Packet:", "-");
405     OBJECT_SET_DATA(table, PREVIEW_FIRST_KEY, label);
406     label = add_string_to_table(table, &row, "Elapsed time:", "-");
407     OBJECT_SET_DATA(table, PREVIEW_ELAPSED_KEY, label);
408
409     return table;
410 }
411
412 /*
413  * Keep a static pointer to the current "Open Capture File" window, if
414  * any, so that if somebody tries to do "File:Open" while there's already
415  * an "Open Capture File" window up, we just pop up the existing one,
416  * rather than creating a new one.
417  */
418 static GtkWidget *file_open_w;
419
420 /* Open a file */
421 static void
422 file_open_cmd(GtkWidget *w)
423 {
424   GtkWidget     *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
425                 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
426 #if GTK_MAJOR_VERSION < 2
427   GtkAccelGroup *accel_group;
428 #endif
429   /* No Apply button, and "OK" just sets our text widget, it doesn't
430      activate it (i.e., it doesn't cause us to try to open the file). */
431   static construct_args_t args = {
432         "Ethereal: Read Filter",
433         FALSE,
434         FALSE
435   };
436
437   if (file_open_w != NULL) {
438     /* There's already an "Open Capture File" dialog box; reactivate it. */
439     reactivate_window(file_open_w);
440     return;
441   }
442
443   file_open_w = file_selection_new("Ethereal: Open Capture File",
444                                    FILE_SELECTION_OPEN);
445 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
446   /* it's annoying, that the file chooser dialog is already shown here, 
447      so we cannot use the correct gtk_window_set_default_size() to resize it */
448   WIDGET_SET_SIZE(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
449 #else
450   gtk_window_set_default_size(GTK_WINDOW(file_open_w), DEF_WIDTH, DEF_HEIGHT);
451 #endif
452
453 #if GTK_MAJOR_VERSION < 2
454   /* Accelerator group for the accelerators (or, as they're called in
455      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
456      Ctrl+<key> is an accelerator). */
457   accel_group = gtk_accel_group_new();
458   gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
459 #endif
460
461   switch (prefs.gui_fileopen_style) {
462
463   case FO_STYLE_LAST_OPENED:
464     /* The user has specified that we should start out in the last directory
465        we looked in.  If we've already opened a file, use its containing
466        directory, if we could determine it, as the directory, otherwise
467        use the "last opened" directory saved in the preferences file if
468        there was one. */
469     /* This is now the default behaviour in file_selection_new() */
470     break;
471
472   case FO_STYLE_SPECIFIED:
473     /* The user has specified that we should always start out in a
474        specified directory; if they've specified that directory,
475        start out by showing the files in that dir. */
476     if (prefs.gui_fileopen_dir[0] != '\0')
477       file_selection_set_current_folder(file_open_w, prefs.gui_fileopen_dir);
478     break;
479   }
480
481   
482   main_hb = gtk_hbox_new(FALSE, 3);
483   file_selection_set_extra_widget(file_open_w, main_hb);
484   gtk_widget_show(main_hb);
485
486   /* Container for each row of widgets */
487   main_vb = gtk_vbox_new(FALSE, 3);
488   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
489   gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
490   gtk_widget_show(main_vb);
491
492   /* filter row */
493   filter_hbox = gtk_hbox_new(FALSE, 1);
494   gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
495   gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
496   gtk_widget_show(filter_hbox);
497
498   filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
499   SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
500   SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
501   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
502   gtk_widget_show(filter_bt);
503
504   filter_te = gtk_entry_new();
505   OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
506   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
507   SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
508   gtk_widget_show(filter_te);
509
510 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
511   OBJECT_SET_DATA(file_open_w, E_RFILTER_TE_KEY, filter_te);
512 #else
513   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
514                   E_RFILTER_TE_KEY, filter_te);
515 #endif
516
517   /* resolve buttons */
518   m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
519   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
520         g_resolv_flags & RESOLV_MAC);
521   gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
522 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
523   OBJECT_SET_DATA(file_open_w,
524                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
525 #else
526   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
527                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
528 #endif
529   gtk_widget_show(m_resolv_cb);
530
531   n_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _network name resolution", accel_group);
532   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
533         g_resolv_flags & RESOLV_NETWORK);
534   gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
535   gtk_widget_show(n_resolv_cb);
536 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
537   OBJECT_SET_DATA(file_open_w, E_FILE_N_RESOLVE_KEY, n_resolv_cb);
538 #else
539   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
540                   E_FILE_N_RESOLVE_KEY, n_resolv_cb);
541 #endif
542
543   t_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _transport name resolution", accel_group);
544   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
545         g_resolv_flags & RESOLV_TRANSPORT);
546   gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
547   gtk_widget_show(t_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_T_RESOLVE_KEY, t_resolv_cb);
550 #else
551   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
552                   E_FILE_T_RESOLVE_KEY, t_resolv_cb);
553 #endif
554
555
556   SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
557
558   /* preview widget */
559   prev = preview_new();
560   OBJECT_SET_DATA(file_open_w, PREVIEW_TABLE_KEY, prev);
561   gtk_widget_show_all(prev);
562   gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
563
564 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
565   SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_open_w), "selection-changed", 
566       file_open_entry_changed, file_open_w);
567   file_open_entry_changed(file_open_w, file_open_w);
568
569   OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
570                   OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
571   if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
572   {
573     file_open_ok_cb(file_open_w, file_open_w);
574   }
575   else window_destroy(file_open_w);
576 #else
577   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->selection_entry, "changed", 
578       file_open_entry_changed, file_open_w);
579
580   /* Connect the ok_button to file_open_ok_cb function and pass along a
581      pointer to the file selection box widget */
582   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
583                  file_open_ok_cb, file_open_w);
584
585   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
586                   E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
587
588   /* Connect the cancel_button to destroy the widget */
589   window_set_cancel_button(file_open_w, 
590       GTK_FILE_SELECTION(file_open_w)->cancel_button, window_cancel_button_cb);
591
592   SIGNAL_CONNECT(file_open_w, "delete_event", window_delete_event_cb, NULL);
593
594   gtk_widget_show(file_open_w);
595   window_present(file_open_w);
596 #endif
597 }
598
599 static void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
600 {
601     switch(btn) {
602     case(ESD_BTN_SAVE):
603         /* save file first */
604         file_save_as_cmd(after_save_open_dialog, data);
605         break;
606     case(ESD_BTN_DONT_SAVE):
607         cf_close(&cfile);
608         file_open_cmd(data);
609         break;
610     case(ESD_BTN_CANCEL):
611         break;
612     default:
613         g_assert_not_reached();
614     }
615 }
616
617 void
618 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
619   gpointer  dialog;
620
621   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
622     /* user didn't saved his current file, ask him */
623     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
624                 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
625                 "If you open a new capture file without saving, your capture data will be discarded.");
626     simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
627   } else {
628     /* unchanged file, just open a new one */
629     file_open_cmd(widget);
630   }
631 }
632
633 /* user pressed "open" button */
634 static void
635 file_open_ok_cb(GtkWidget *w, gpointer fs) {
636   gchar       *cf_name, *s;
637   const gchar *rfilter;
638   GtkWidget   *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
639   dfilter_t   *rfcode = NULL;
640   int          err;
641
642 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
643   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
644 #else
645   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
646 #endif
647   filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
648   rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
649   if (!dfilter_compile(rfilter, &rfcode)) {
650     bad_dfilter_alert_box(rfilter);
651     g_free(cf_name);
652     return;
653   }
654
655   /* Perhaps the user specified a directory instead of a file.
656      Check whether they did. */
657   if (test_for_directory(cf_name) == EISDIR) {
658         /* It's a directory - set the file selection box to display that
659            directory, don't try to open the directory as a capture file. */
660         set_last_open_dir(cf_name);
661         g_free(cf_name);
662         file_selection_set_current_folder(fs, get_last_open_dir());
663         return;
664   }
665
666   /* Try to open the capture file. */
667   if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
668     /* We couldn't open it; don't dismiss the open dialog box,
669        just leave it around so that the user can, after they
670        dismiss the alert box popped up for the open error,
671        try again. */
672     if (rfcode != NULL)
673       dfilter_free(rfcode);
674     g_free(cf_name);
675     return;
676   }
677
678   /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
679      it closed the previous capture file, and thus destroyed any
680      previous read filter attached to "cf"). */
681   cfile.rfcode = rfcode;
682
683   /* Set the global resolving variable */
684   g_resolv_flags = prefs.name_resolve;
685   m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
686   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)))
687     g_resolv_flags |= RESOLV_MAC;
688   else
689     g_resolv_flags &= ~RESOLV_MAC;
690   n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
691   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)))
692     g_resolv_flags |= RESOLV_NETWORK;
693   else
694     g_resolv_flags &= ~RESOLV_NETWORK;
695   t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
696   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)))
697     g_resolv_flags |= RESOLV_TRANSPORT;
698   else
699     g_resolv_flags &= ~RESOLV_TRANSPORT;
700
701   /* We've crossed the Rubicon; get rid of the file selection box. */
702   window_destroy(GTK_WIDGET (fs));
703
704   switch (cf_read(&cfile)) {
705
706   case CF_READ_OK:
707   case CF_READ_ERROR:
708     /* Just because we got an error, that doesn't mean we were unable
709        to read any of the file; we handle what we could get from the
710        file. */
711     break;
712
713   case CF_READ_ABORTED:
714     /* The user bailed out of re-reading the capture file; the
715        capture file has been closed - just free the capture file name
716        string and return (without changing the last containing
717        directory). */
718     g_free(cf_name);
719     return;
720   }
721
722   /* Save the name of the containing directory specified in the path name,
723      if any; we can write over cf_name, which is a good thing, given that
724      "get_dirname()" does write over its argument. */
725   s = get_dirname(cf_name);
726   set_last_open_dir(s);
727   gtk_widget_grab_focus(packet_list);
728
729   g_free(cf_name);
730 }
731
732 static void
733 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
734 {
735   /* Note that we no longer have a "Open Capture File" dialog box. */
736   file_open_w = NULL;
737 }
738
739 /*
740  * Keep a static pointer to the current "Merge Capture File" window, if
741  * any, so that if somebody tries to do "File:Merge" while there's already
742  * an "Merge Capture File" window up, we just pop up the existing one,
743  * rather than creating a new one.
744  */
745 static GtkWidget *file_merge_w;
746
747 /* Merge existing with another file */
748 static void
749 file_merge_cmd(GtkWidget *w)
750 {
751   GtkWidget     *main_hb, *main_vb, *ft_hb, *ft_lb, *filter_hbox,
752                 *filter_bt, *filter_te, *prepend_rb, *chrono_rb,
753                 *append_rb, *prev;
754 #if GTK_MAJOR_VERSION < 2
755   GtkAccelGroup *accel_group;
756 #endif
757   GtkTooltips *tooltips = gtk_tooltips_new();
758   /* No Apply button, and "OK" just sets our text widget, it doesn't
759      activate it (i.e., it doesn't cause us to try to open the file). */
760   static construct_args_t args = {
761         "Ethereal: Read Filter",
762         FALSE,
763         FALSE
764   };
765
766   if (file_merge_w != NULL) {
767     /* There's already an "Merge Capture File" dialog box; reactivate it. */
768     reactivate_window(file_merge_w);
769     return;
770   }
771
772   /* Default to saving all packets, in the file's current format. */
773   filetype = cfile.cd_t;
774
775   file_merge_w = file_selection_new("Ethereal: Merge with Capture File",
776                                    FILE_SELECTION_OPEN);
777 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
778   /* it's annoying, that the file chooser dialog is already shown here, 
779      so we cannot use the correct gtk_window_set_default_size() to resize it */
780   WIDGET_SET_SIZE(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
781 #else
782   gtk_window_set_default_size(GTK_WINDOW(file_merge_w), DEF_WIDTH, DEF_HEIGHT);
783 #endif
784
785 #if GTK_MAJOR_VERSION < 2
786   /* Accelerator group for the accelerators (or, as they're called in
787      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
788      Ctrl+<key> is an accelerator). */
789   accel_group = gtk_accel_group_new();
790   gtk_window_add_accel_group(GTK_WINDOW(file_merge_w), accel_group);
791 #endif
792
793   switch (prefs.gui_fileopen_style) {
794
795   case FO_STYLE_LAST_OPENED:
796     /* The user has specified that we should start out in the last directory
797        we looked in.  If we've already opened a file, use its containing
798        directory, if we could determine it, as the directory, otherwise
799        use the "last opened" directory saved in the preferences file if
800        there was one. */
801     /* This is now the default behaviour in file_selection_new() */
802     break;
803
804   case FO_STYLE_SPECIFIED:
805     /* The user has specified that we should always start out in a
806        specified directory; if they've specified that directory,
807        start out by showing the files in that dir. */
808     if (prefs.gui_fileopen_dir[0] != '\0')
809       file_selection_set_current_folder(file_merge_w, prefs.gui_fileopen_dir);
810     break;
811   }
812     
813   main_hb = gtk_hbox_new(FALSE, 3);
814   file_selection_set_extra_widget(file_merge_w, main_hb);
815   gtk_widget_show(main_hb);
816
817   /* Container for each row of widgets */
818   main_vb = gtk_vbox_new(FALSE, 3);
819   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
820   gtk_box_pack_start(GTK_BOX(main_hb), main_vb, FALSE, FALSE, 0);
821   gtk_widget_show(main_vb);
822
823   /* File type row */
824   range_tb = NULL;
825   ft_hb = gtk_hbox_new(FALSE, 3);
826   gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
827   gtk_widget_show(ft_hb);
828
829   ft_lb = gtk_label_new("Merged output file type:");
830   gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
831   gtk_widget_show(ft_lb);
832
833   ft_om = gtk_option_menu_new();
834
835   /* Generate the list of file types we can save. */
836   set_file_type_list(ft_om);
837   gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
838   gtk_widget_show(ft_om);
839
840   filter_hbox = gtk_hbox_new(FALSE, 1);
841   gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
842   gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
843   gtk_widget_show(filter_hbox);
844
845   filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
846   SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
847   SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
848   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
849   gtk_widget_show(filter_bt);
850
851   filter_te = gtk_entry_new();
852   OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
853   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
854   SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
855   gtk_widget_show(filter_te);
856
857 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
858   OBJECT_SET_DATA(file_merge_w, E_RFILTER_TE_KEY, filter_te);
859 #else
860   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
861                   E_RFILTER_TE_KEY, filter_te);
862 #endif
863
864   prepend_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Prepend packets to existing file", accel_group);
865   gtk_tooltips_set_tip(tooltips, prepend_rb, 
866       "The resulting file contains the packets from the selected, followed by the packets from the currently loaded file,"
867       " the packet timestamps will be ignored.", NULL);
868   gtk_box_pack_start(GTK_BOX(main_vb), prepend_rb, FALSE, FALSE, 0);
869 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
870   OBJECT_SET_DATA(file_merge_w,
871                   E_MERGE_PREPEND_KEY, prepend_rb);
872 #else
873   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
874                   E_MERGE_PREPEND_KEY, prepend_rb);
875 #endif
876   gtk_widget_show(prepend_rb);
877
878   chrono_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Merge packets chronologically", accel_group);
879   gtk_tooltips_set_tip(tooltips, chrono_rb, 
880       "The resulting file contains all the packets from the currently loaded and the selected file,"
881       " sorted by the packet timestamps.", NULL);
882   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chrono_rb), TRUE);
883   gtk_box_pack_start(GTK_BOX(main_vb), chrono_rb, FALSE, FALSE, 0);
884   gtk_widget_show(chrono_rb);
885 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
886   OBJECT_SET_DATA(file_merge_w, E_MERGE_CHRONO_KEY, chrono_rb);
887 #else
888   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
889                   E_MERGE_CHRONO_KEY, chrono_rb);
890 #endif
891
892   append_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(prepend_rb, "Append packets to existing file", accel_group);
893   gtk_tooltips_set_tip(tooltips, append_rb, 
894       "The resulting file contains the packets from the currently loaded, followed by the packets from the selected file,"
895       " the packet timestamps will be ignored.", NULL);
896   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(append_rb),
897         g_resolv_flags & RESOLV_TRANSPORT);
898   gtk_box_pack_start(GTK_BOX(main_vb), append_rb, FALSE, FALSE, 0);
899   gtk_widget_show(append_rb);
900 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
901   OBJECT_SET_DATA(file_merge_w, E_MERGE_APPEND_KEY, append_rb);
902 #else
903   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
904                   E_MERGE_APPEND_KEY, append_rb);
905 #endif
906
907
908   SIGNAL_CONNECT(file_merge_w, "destroy", file_merge_destroy_cb, NULL);
909
910   /* preview widget */
911   prev = preview_new();
912   OBJECT_SET_DATA(file_merge_w, PREVIEW_TABLE_KEY, prev);
913   gtk_widget_show_all(prev);
914   gtk_box_pack_start(GTK_BOX(main_hb), prev, TRUE, TRUE, 0);
915
916 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
917   SIGNAL_CONNECT(GTK_FILE_CHOOSER(file_merge_w), "selection-changed", 
918       file_open_entry_changed, file_merge_w);
919   file_open_entry_changed(file_merge_w, file_merge_w);
920
921   OBJECT_SET_DATA(file_merge_w, E_DFILTER_TE_KEY,
922                   OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
923   if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) == GTK_RESPONSE_ACCEPT)
924   {
925     file_merge_ok_cb(file_merge_w, file_merge_w);
926   }
927   else window_destroy(file_merge_w);
928 #else
929   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->selection_entry, "changed", 
930       file_open_entry_changed, file_merge_w);
931
932   /* Connect the ok_button to file_merge_ok_cb function and pass along a
933      pointer to the file selection box widget */
934   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_merge_w)->ok_button, "clicked",
935                  file_merge_ok_cb, file_merge_w);
936
937   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_merge_w)->ok_button,
938                   E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
939
940   /* Connect the cancel_button to destroy the widget */
941   window_set_cancel_button(file_merge_w, 
942       GTK_FILE_SELECTION(file_merge_w)->cancel_button, window_cancel_button_cb);
943
944   SIGNAL_CONNECT(file_merge_w, "delete_event", window_delete_event_cb, NULL);
945
946   gtk_widget_show(file_merge_w);
947   window_present(file_merge_w);
948 #endif
949 }
950
951 static void file_merge_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
952 {
953     switch(btn) {
954     case(ESD_BTN_OK):
955         /* save file first */
956         file_save_as_cmd(after_save_merge_dialog, data);
957         break;
958     case(ESD_BTN_CANCEL):
959         break;
960     default:
961         g_assert_not_reached();
962     }
963 }
964
965 void
966 file_merge_cmd_cb(GtkWidget *widget, gpointer data _U_) {
967   gpointer  dialog;
968
969   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
970     /* user didn't saved his current file, ask him */
971     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
972                 PRIMARY_TEXT_START "Save the capture file before merging to another one?" PRIMARY_TEXT_END "\n\n"
973                 "A temporary capture file can't be merged.");
974     simple_dialog_set_cb(dialog, file_merge_answered_cb, widget);
975   } else {
976     /* unchanged file, just start to merge */
977     file_merge_cmd(widget);
978   }
979 }
980
981
982 static void
983 file_merge_ok_cb(GtkWidget *w, gpointer fs) {
984   gchar       *cf_name, *s;
985   const gchar *rfilter;
986   GtkWidget   *filter_te, *rb;
987   dfilter_t   *rfcode = NULL;
988   int          err;
989   cf_status_t  merge_status;
990   char        *in_filenames[2];
991   char        *tmpname;
992
993 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
994   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
995 #else
996   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
997 #endif
998   filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
999   rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
1000   if (!dfilter_compile(rfilter, &rfcode)) {
1001     bad_dfilter_alert_box(rfilter);
1002     g_free(cf_name);
1003     return;
1004   }
1005
1006   /* Perhaps the user specified a directory instead of a file.
1007      Check whether they did. */
1008   if (test_for_directory(cf_name) == EISDIR) {
1009         /* It's a directory - set the file selection box to display that
1010            directory, don't try to open the directory as a capture file. */
1011         set_last_open_dir(cf_name);
1012         g_free(cf_name);
1013         file_selection_set_current_folder(fs, get_last_open_dir());
1014         return;
1015   }
1016
1017   /* merge or append the two files */
1018   rb = OBJECT_GET_DATA(w, E_MERGE_CHRONO_KEY);
1019   tmpname = NULL;
1020   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1021       /* chronological order */
1022       in_filenames[0] = cfile.filename;
1023       in_filenames[1] = cf_name;
1024       merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype, FALSE);
1025   } else {
1026       rb = OBJECT_GET_DATA(w, E_MERGE_PREPEND_KEY);
1027       if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rb))) {
1028           /* prepend file */
1029           in_filenames[0] = cfile.filename;
1030           in_filenames[1] = cf_name;
1031           merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype,
1032                                         TRUE);
1033       } else {
1034           /* append file */
1035           in_filenames[0] = cf_name;
1036           in_filenames[1] = cfile.filename;
1037           merge_status = cf_merge_files(&tmpname, 2, in_filenames, filetype,
1038                                         TRUE);
1039       }
1040   }
1041
1042   g_free(cf_name);
1043   
1044   if (merge_status != CF_OK) {
1045     if (rfcode != NULL)
1046       dfilter_free(rfcode);
1047     g_free(tmpname);
1048     return;
1049   }
1050
1051   cf_close(&cfile);
1052
1053   /* We've crossed the Rubicon; get rid of the file selection box. */
1054   window_destroy(GTK_WIDGET (fs));
1055
1056   /* Try to open the merged capture file. */
1057   if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
1058     /* We couldn't open it; don't dismiss the open dialog box,
1059        just leave it around so that the user can, after they
1060        dismiss the alert box popped up for the open error,
1061        try again. */
1062     if (rfcode != NULL)
1063       dfilter_free(rfcode);
1064     g_free(tmpname);
1065     return;
1066   }
1067   g_free(tmpname);
1068
1069   /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
1070      it closed the previous capture file, and thus destroyed any
1071      previous read filter attached to "cf"). */
1072   cfile.rfcode = rfcode;
1073
1074   switch (cf_read(&cfile)) {
1075
1076   case CF_READ_OK:
1077   case CF_READ_ERROR:
1078     /* Just because we got an error, that doesn't mean we were unable
1079        to read any of the file; we handle what we could get from the
1080        file. */
1081     break;
1082
1083   case CF_READ_ABORTED:
1084     /* The user bailed out of re-reading the capture file; the
1085        capture file has been closed - just free the capture file name
1086        string and return (without changing the last containing
1087        directory). */
1088     return;
1089   }
1090
1091   /* Save the name of the containing directory specified in the path name,
1092      if any; we can write over cf_merged_name, which is a good thing, given that
1093      "get_dirname()" does write over its argument. */
1094   s = get_dirname(tmpname);
1095   set_last_open_dir(s);
1096   gtk_widget_grab_focus(packet_list);
1097 }
1098
1099 static void
1100 file_merge_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1101 {
1102   /* Note that we no longer have a "Merge Capture File" dialog box. */
1103   file_merge_w = NULL;
1104 }
1105
1106
1107 static void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1108 {
1109     switch(btn) {
1110     case(ESD_BTN_SAVE):
1111         /* save file first */
1112         file_save_as_cmd(after_save_close_file, NULL);
1113         break;
1114     case(ESD_BTN_DONT_SAVE):
1115         cf_close(&cfile);
1116         break;
1117     case(ESD_BTN_CANCEL):
1118         break;
1119     default:
1120         g_assert_not_reached();
1121     }
1122 }
1123
1124 /* Close a file */
1125 void
1126 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
1127   gpointer  dialog;
1128
1129   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1130     /* user didn't saved his current file, ask him */
1131     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1132                 PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
1133                 "If you close without saving, your capture data will be discarded.");
1134
1135     simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
1136   } else {
1137     /* unchanged file, just close it */
1138     cf_close(&cfile);
1139   }
1140 }
1141
1142 void
1143 file_save_cmd_cb(GtkWidget *w, gpointer data) {
1144   /* If the file's already been saved, do nothing.  */
1145   if (cfile.user_saved)
1146     return;
1147
1148   /* Do a "Save As". */
1149   file_save_as_cmd_cb(w, data);
1150 }
1151
1152 static gboolean
1153 can_save_with_wiretap(int ft)
1154 {
1155   /* To save a file with Wiretap, Wiretap has to handle that format,
1156      and its code to handle that format must be able to write a file
1157      with this file's encapsulation type. */
1158   return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
1159 }
1160
1161
1162 /* Generate a list of the file types we can save this file as.
1163
1164    "filetype" is the type it has now.
1165
1166    "encap" is the encapsulation for its packets (which could be
1167    "unknown" or "per-packet").
1168
1169    "filtered" is TRUE if we're to save only the packets that passed
1170    the display filter (in which case we have to save it using Wiretap)
1171    and FALSE if we're to save the entire file (in which case, if we're
1172    saving it in the type it has already, we can just copy it).
1173
1174    The same applies for sel_curr, sel_all, sel_m_only, sel_m_range and sel_man_range
1175 */
1176 static void
1177 set_file_type_list(GtkWidget *option_menu)
1178 {
1179   GtkWidget *ft_menu, *ft_menu_item;
1180   int ft;
1181   guint index;
1182   guint item_to_select;
1183
1184   /* Default to the first supported file type, if the file's current
1185      type isn't supported. */
1186   item_to_select = 0;
1187
1188   ft_menu = gtk_menu_new();
1189
1190   /* Check all file types. */
1191   index = 0;
1192   for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
1193     if (!packet_range_process_all(&range) || ft != cfile.cd_t) {
1194       /* not all unfiltered packets or a different file type.  We have to use Wiretap. */
1195       if (!can_save_with_wiretap(ft))
1196         continue;       /* We can't. */
1197     }
1198
1199     /* OK, we can write it out in this type. */
1200     ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
1201     if (ft == filetype) {
1202       /* Default to the same format as the file, if it's supported. */
1203       item_to_select = index;
1204     }
1205     SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
1206                    GINT_TO_POINTER(ft));
1207     gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
1208     gtk_widget_show(ft_menu_item);
1209     index++;
1210   }
1211
1212   gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
1213   gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
1214 }
1215
1216 static void
1217 select_file_type_cb(GtkWidget *w _U_, gpointer data)
1218 {
1219   int new_filetype = GPOINTER_TO_INT(data);
1220   GtkWidget *compressed_cb;
1221
1222   if (filetype != new_filetype) {
1223     /* We can select only the filtered or marked packets to be saved if we can
1224        use Wiretap to save the file. */
1225     if (range_tb != NULL)
1226        range_set_displayed_sensitive(range_tb, can_save_with_wiretap(new_filetype));
1227     filetype = new_filetype;
1228     file_set_save_marked_sensitive();
1229         compressed_cb = OBJECT_GET_DATA(file_save_as_w, "compressed");
1230         gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(new_filetype));
1231   }
1232 }
1233
1234
1235 /*
1236  * Set the "Save only marked packets" toggle button as appropriate for
1237  * the current output file type and count of marked packets.
1238  *
1239  * Called when the "Save As..." dialog box is created and when either
1240  * the file type or the marked count changes.
1241  */
1242 void
1243 file_set_save_marked_sensitive(void)
1244 {
1245   if (file_save_as_w == NULL) {
1246     /* We don't currently have a "Save As..." dialog box up. */
1247     return;
1248   }
1249         
1250   /* We can request that only the marked packets be saved only if we
1251      can use Wiretap to save the file and if there *are* marked packets. */
1252   if (can_save_with_wiretap(filetype) && cfile.marked_count > 0) {
1253     range_set_marked_sensitive(range_tb, TRUE);
1254   }
1255   else {
1256     /* Force the "Save only marked packets" toggle to "false", turn
1257        off the flag it controls, and update the list of types we can
1258        save the file as. */
1259     range.process = range_process_all;
1260     set_file_type_list(ft_om);
1261     range_set_marked_sensitive(range_tb, FALSE);
1262   }
1263 }
1264
1265
1266 action_after_save_e action_after_save_g;
1267 gpointer            action_after_save_data_g;
1268
1269
1270 void
1271 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
1272 {
1273   GtkWidget     *main_vb, *ft_hb, *ft_lb, *range_fr, *compressed_cb;
1274   GtkTooltips   *tooltips;
1275
1276 #if GTK_MAJOR_VERSION < 2
1277   GtkAccelGroup *accel_group;
1278 #endif
1279           
1280   if (file_save_as_w != NULL) {
1281     /* There's already an "Save Capture File As" dialog box; reactivate it. */
1282     reactivate_window(file_save_as_w);
1283     return;
1284   }
1285
1286   /* Default to saving all packets, in the file's current format. */
1287   filetype = cfile.cd_t;
1288
1289   /* init the packet range */
1290   packet_range_init(&range);
1291
1292   /* Enable tooltips */
1293   tooltips = gtk_tooltips_new();
1294           
1295   /* build the file selection */
1296   file_save_as_w = file_selection_new ("Ethereal: Save Capture File As",
1297                                        FILE_SELECTION_SAVE);
1298
1299   /* as the dialog might already be gone, when using this values, we cannot
1300    * set data to the dialog object, but keep global values */
1301   action_after_save_g       = action_after_save;
1302   action_after_save_data_g  = action_after_save_data;
1303
1304 #if GTK_MAJOR_VERSION < 2
1305   accel_group = gtk_accel_group_new();
1306   gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
1307 #endif
1308         
1309   /* Container for each row of widgets */
1310        
1311   main_vb = gtk_vbox_new(FALSE, 5);
1312   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1313   file_selection_set_extra_widget(file_save_as_w, main_vb);
1314   gtk_widget_show(main_vb);     
1315                 
1316   /*** Packet Range frame ***/
1317   range_fr = gtk_frame_new("Packet Range");
1318   gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
1319   gtk_widget_show(range_fr);
1320   
1321   /* range table */
1322   range_tb = range_new(&range
1323 #if GTK_MAJOR_VERSION < 2
1324   , accel_group
1325 #endif
1326   );
1327   gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
1328   gtk_widget_show(range_tb);
1329
1330   /* File type row */
1331   ft_hb = gtk_hbox_new(FALSE, 3);
1332   gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1333   gtk_widget_show(ft_hb);
1334
1335   ft_lb = gtk_label_new("File type:");
1336   gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1337   gtk_widget_show(ft_lb);
1338
1339   ft_om = gtk_option_menu_new();
1340
1341   /* Generate the list of file types we can save. */
1342   set_file_type_list(ft_om);
1343   gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1344   gtk_widget_show(ft_om);
1345
1346   /*
1347    * Set the sensitivity of the "Save only marked packets" toggle
1348    * button
1349    *
1350    * This has to be done after we create the file type menu option,
1351    * as the routine that sets it also sets that menu.
1352    */
1353   file_set_save_marked_sensitive();
1354         
1355   /* dynamic values in the range frame */
1356   range_update_dynamics(range_tb);
1357
1358   /* compressed */
1359   compressed_cb = gtk_check_button_new_with_label("Compress with gzip");
1360   gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb);
1361   gtk_widget_show(compressed_cb);
1362   OBJECT_SET_DATA(file_save_as_w, "compressed", compressed_cb);
1363   gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(cfile.cd_t));
1364
1365   SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
1366
1367 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1368   if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT) {
1369     file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1370   } else {
1371     window_destroy(file_save_as_w);
1372   }
1373 #else
1374   /* Connect the ok_button to file_save_as_ok_cb function and pass along a
1375      pointer to the file selection box widget */
1376   SIGNAL_CONNECT(GTK_FILE_SELECTION (file_save_as_w)->ok_button, "clicked",
1377                  file_save_as_ok_cb, file_save_as_w);
1378
1379   window_set_cancel_button(file_save_as_w, 
1380       GTK_FILE_SELECTION(file_save_as_w)->cancel_button, window_cancel_button_cb);
1381
1382   SIGNAL_CONNECT(file_save_as_w, "delete_event", window_delete_event_cb, NULL);
1383
1384   gtk_widget_show(file_save_as_w);
1385   window_present(file_save_as_w);
1386 #endif
1387 }
1388
1389 void
1390 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1391 {
1392   file_save_as_cmd(after_save_no_action, NULL);
1393 }
1394
1395
1396 /* all tests ok, we only have to save the file */
1397 /* (and probably continue with a pending operation) */
1398 static void
1399 file_save_as_cb(GtkWidget *w _U_, gpointer fs) {
1400   gchar *cf_name;
1401   gchar *dirname;
1402   GtkWidget *compressed_cb;
1403
1404
1405 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1406   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1407 #else
1408   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1409 #endif
1410
1411   compressed_cb = OBJECT_GET_DATA(file_save_as_w, "compressed");
1412
1413   /* Write out the packets (all, or only the ones from the current
1414      range) to the file with the specified name. */
1415   if (cf_save(&cfile, cf_name, &range, filetype, 
1416           gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb))) != CF_OK) {
1417     /* The write failed; don't dismiss the open dialog box,
1418        just leave it around so that the user can, after they
1419        dismiss the alert box popped up for the error, try again. */
1420     g_free(cf_name);
1421 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1422     /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1423      * as this will prevent the user from closing the now existing error
1424      * message, simply close the dialog (this is the best we can do here). */
1425     if (file_save_as_w)
1426       window_destroy(GTK_WIDGET (fs));
1427 #else
1428     gtk_widget_show(GTK_WIDGET (fs));
1429 #endif
1430     return;
1431   }
1432
1433   /* The write succeeded; get rid of the file selection box. */
1434   /* cf_save() might already closed our dialog! */
1435   if (file_save_as_w)
1436     window_destroy(GTK_WIDGET (fs));
1437
1438   /* Save the directory name for future file dialogs. */
1439   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
1440   set_last_open_dir(dirname);
1441   g_free(cf_name);
1442
1443   /* we have finished saving, do we have pending things to do? */
1444   switch(action_after_save_g) {
1445   case(after_save_no_action):
1446       break;
1447   case(after_save_open_dialog):
1448       file_open_cmd(action_after_save_data_g);
1449       break;
1450   case(after_save_open_recent_file):
1451       menu_open_recent_file_cmd(action_after_save_data_g);
1452       break;
1453   case(after_save_open_dnd_file):
1454       dnd_open_file_cmd(action_after_save_data_g);
1455       break;
1456   case(after_save_merge_dialog):
1457       file_merge_cmd(action_after_save_data_g);
1458       break;
1459 #ifdef HAVE_LIBPCAP
1460   case(after_save_capture_dialog):
1461       capture_start_confirmed();
1462       break;
1463 #endif
1464   case(after_save_close_file):
1465       cf_close(&cfile);
1466       break;
1467   case(after_save_exit):
1468       main_do_quit();
1469       break;
1470   default:
1471       g_assert_not_reached();
1472   }
1473
1474   action_after_save_g = after_save_no_action;
1475 }
1476
1477
1478 static void file_save_as_exists_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
1479 {
1480     gchar       *cf_name;
1481
1482 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1483     cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data)));
1484 #else
1485     cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(data)));
1486 #endif
1487
1488     switch(btn) {
1489     case(ESD_BTN_OK):
1490         /* save file */
1491         unlink(cf_name);
1492         file_save_as_cb(NULL, data);
1493         break;
1494     case(ESD_BTN_CANCEL):
1495         break;
1496     default:
1497         g_assert_not_reached();
1498     }
1499 }
1500
1501
1502 /* user pressed "Save" dialog "Ok" button */
1503 static void
1504 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1505   gchar *cf_name;
1506   gpointer  dialog;
1507   
1508 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1509   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1510 #else
1511   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1512 #endif
1513
1514   /* Perhaps the user specified a directory instead of a file.
1515      Check whether they did. */
1516   if (test_for_directory(cf_name) == EISDIR) {
1517         /* It's a directory - set the file selection box to display that
1518            directory, and leave the selection box displayed. */
1519         set_last_open_dir(cf_name);
1520         g_free(cf_name);
1521         file_selection_set_current_folder(fs, get_last_open_dir());
1522         return;
1523   }
1524
1525   /* Check whether the range is valid. */
1526   if (!range_check_validity(&range)) {
1527     /* The range isn't valid; don't dismiss the open dialog box,
1528        just leave it around so that the user can, after they
1529        dismiss the alert box popped up for the error, try again. */
1530     g_free(cf_name);
1531 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1532     /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1533      * as this will prevent the user from closing the now existing error
1534      * message, simply close the dialog (this is the best we can do here). */
1535     if (file_save_as_w)
1536       window_destroy(GTK_WIDGET (fs));
1537 #else
1538     gtk_widget_show(GTK_WIDGET (fs));
1539 #endif
1540     return;
1541   }
1542
1543   /*
1544    * Check that the from file is not the same as to file
1545    * We do it here so we catch all cases ...
1546    * Unfortunately, the file requester gives us an absolute file
1547    * name and the read file name may be relative (if supplied on
1548    * the command line). From Joerg Mayer.
1549    */
1550   if (files_identical(cfile.filename, cf_name)) {
1551     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1552       "%sCapture file: \"%s\" identical to loaded file!%s\n\n"
1553       "Please choose a different filename.",
1554       simple_dialog_primary_start(), cf_name, simple_dialog_primary_end());
1555     g_free(cf_name);
1556 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1557     /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
1558      * as this will prevent the user from closing the now existing error
1559      * message, simply close the dialog (this is the best we can do here). */
1560     if (file_save_as_w)
1561       window_destroy(GTK_WIDGET (fs));
1562 #else
1563     gtk_widget_show(GTK_WIDGET (fs));
1564 #endif
1565     return;
1566   }
1567
1568   /* don't show the dialog while saving (or asking) */
1569   gtk_widget_hide(GTK_WIDGET (fs));
1570
1571   /* it the file doesn't exist, simply try to save it */
1572   if (!file_exists(cf_name)) {
1573     file_save_as_cb(NULL, fs);
1574     g_free(cf_name);
1575     return;
1576   }
1577
1578   /* the file exists, ask the user to remove it first */
1579   dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
1580       PRIMARY_TEXT_START "Capture file: \"%s\" already exists!" PRIMARY_TEXT_END "\n\n"
1581       "Replace the current file?", cf_name);
1582   simple_dialog_set_cb(dialog, file_save_as_exists_answered_cb, fs);
1583
1584   g_free(cf_name);
1585 }
1586
1587 void
1588 file_save_as_destroy(void)
1589 {
1590   if (file_save_as_w)
1591     window_destroy(file_save_as_w);
1592 }
1593
1594 static void
1595 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1596 {
1597   /* Note that we no longer have a "Save Capture File As" dialog box. */
1598   file_save_as_w = NULL;
1599 }
1600
1601 /* Reload a file using the current read and display filters */
1602 void
1603 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1604   cf_reload(&cfile);
1605 }
1606
1607 /******************** Color Filters *********************************/
1608 /*
1609  * Keep a static pointer to the current "Color Export" window, if
1610  * any, so that if somebody tries to do "Export"
1611  * while there's already a "Color Export" window up, we just pop
1612  * up the existing one, rather than creating a new one.
1613  */
1614 static GtkWidget *file_color_import_w;
1615
1616 /* sets the file path to the global color filter file.
1617    WARNING: called by both the import and the export dialog.
1618 */
1619 static void
1620 color_global_cb(GtkWidget *widget _U_, gpointer data)
1621 {
1622   GtkWidget *fs_widget = data;
1623   gchar *path;
1624
1625   /* decide what file to open (from dfilter code) */
1626   path = get_datafile_path("colorfilters");
1627
1628 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1629   gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1630 #else
1631   file_selection_set_current_folder(fs_widget, path);
1632 #endif
1633   g_free((gchar *)path);
1634 }
1635
1636 /* Import color filters */
1637 void
1638 file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
1639 {
1640   GtkWidget     *main_vb, *cfglobal_but;
1641 #if GTK_MAJOR_VERSION < 2
1642   GtkAccelGroup *accel_group;
1643 #endif
1644   /* No Apply button, and "OK" just sets our text widget, it doesn't
1645      activate it (i.e., it doesn't cause us to try to open the file). */
1646
1647   if (file_color_import_w != NULL) {
1648     /* There's already an "Import Color Filters" dialog box; reactivate it. */
1649     reactivate_window(file_color_import_w);
1650     return;
1651   }
1652
1653   file_color_import_w = file_selection_new("Ethereal: Import Color Filters",
1654                                            FILE_SELECTION_OPEN);
1655
1656 #if GTK_MAJOR_VERSION < 2
1657   /* Accelerator group for the accelerators (or, as they're called in
1658      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1659      Ctrl+<key> is an accelerator). */
1660   accel_group = gtk_accel_group_new();
1661   gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1662 #endif
1663
1664   /* Container for each row of widgets */
1665   main_vb = gtk_vbox_new(FALSE, 3);
1666   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1667   file_selection_set_extra_widget(file_color_import_w, main_vb);
1668   gtk_widget_show(main_vb);
1669
1670
1671   cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1672   gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1673   SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1674   gtk_widget_show(cfglobal_but);
1675
1676   SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1677
1678 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1679   OBJECT_SET_DATA(file_color_import_w, ARGUMENT_CL, data);
1680
1681   if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1682   {
1683       file_color_import_ok_cb(file_color_import_w, file_color_import_w);
1684   }
1685   else window_destroy(file_color_import_w);
1686 #else
1687   /* Connect the ok_button to file_open_ok_cb function and pass along a
1688      pointer to the file selection box widget */
1689   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1690                  file_color_import_ok_cb, file_color_import_w);
1691
1692   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
1693                   ARGUMENT_CL, data);
1694
1695   window_set_cancel_button(file_color_import_w, 
1696       GTK_FILE_SELECTION(file_color_import_w)->cancel_button, window_cancel_button_cb);
1697
1698   SIGNAL_CONNECT(file_color_import_w, "delete_event", window_delete_event_cb, NULL);
1699
1700
1701   gtk_widget_show(file_color_import_w);
1702   window_present(file_color_import_w);
1703 #endif
1704 }
1705
1706 static void
1707 file_color_import_ok_cb(GtkWidget *w, gpointer fs) {
1708   gchar     *cf_name, *s;
1709   gpointer  argument;
1710
1711   argument = OBJECT_GET_DATA(w, ARGUMENT_CL);     /* to be passed back into color_filters_import */
1712   
1713 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1714   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1715 #else
1716   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1717 #endif
1718   /* Perhaps the user specified a directory instead of a file.
1719      Check whether they did. */
1720   if (test_for_directory(cf_name) == EISDIR) {
1721         /* It's a directory - set the file selection box to display that
1722            directory, don't try to open the directory as a color filter file. */
1723         set_last_open_dir(cf_name);
1724         g_free(cf_name);
1725         file_selection_set_current_folder(fs, get_last_open_dir());
1726         return;
1727   }
1728
1729   /* Try to open the color filter file. */
1730
1731   if (!color_filters_import(cf_name, argument)) {
1732     /* We couldn't open it; don't dismiss the open dialog box,
1733        just leave it around so that the user can, after they
1734        dismiss the alert box popped up for the open error,
1735        try again. */
1736     g_free(cf_name);
1737     return;
1738   }
1739
1740   /* We've crossed the Rubicon; get rid of the file selection box. */
1741   window_destroy(GTK_WIDGET (fs));
1742
1743   /* Save the name of the containing directory specified in the path name,
1744      if any; we can write over cf_name, which is a good thing, given that
1745      "get_dirname()" does write over its argument. */
1746   s = get_dirname(cf_name);
1747   set_last_open_dir(s);
1748   gtk_widget_grab_focus(packet_list);
1749
1750   g_free(cf_name);
1751 }
1752
1753 static void
1754 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1755 {
1756   /* Note that we no longer have a "Open Capture File" dialog box. */
1757   file_color_import_w = NULL;
1758 }
1759
1760 static GtkWidget *file_color_export_w;
1761 /*
1762  * Set the "Export only marked filters" toggle button as appropriate for
1763  * the current output file type and count of marked filters.
1764  *
1765  * Called when the "Export" dialog box is created and when the marked
1766  * count changes.
1767  */
1768 static void
1769 color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
1770 {
1771   if (file_color_export_w == NULL) {
1772     /* We don't currently have an "Export" dialog box up. */
1773     return;
1774   }
1775
1776   /* We can request that only the marked filters be saved only if
1777         there *are* marked filters. */
1778   if (color_marked_count() != 0)
1779     gtk_widget_set_sensitive(cfmark_cb, TRUE);
1780   else {
1781     /* Force the "Export only marked filters" toggle to "false", turn
1782        off the flag it controls. */
1783     color_marked = FALSE;
1784     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1785     gtk_widget_set_sensitive(cfmark_cb, FALSE);
1786   }
1787 }
1788
1789 static void
1790 color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
1791 {
1792   color_marked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1793 }
1794
1795 void
1796 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1797 {
1798   GtkWidget *main_vb, *cfglobal_but;
1799
1800   if (file_color_export_w != NULL) {
1801     /* There's already an "Color Filter Export" dialog box; reactivate it. */
1802     reactivate_window(file_color_export_w);
1803     return;
1804   }
1805
1806   /* Default to saving all packets, in the file's current format. */
1807   color_marked   = FALSE;
1808   filetype = cfile.cd_t;
1809
1810   file_color_export_w = file_selection_new("Ethereal: Export Color Filters",
1811                                            FILE_SELECTION_SAVE);
1812
1813   /* Container for each row of widgets */
1814   main_vb = gtk_vbox_new(FALSE, 3);
1815   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1816   file_selection_set_extra_widget(file_color_export_w, main_vb);
1817   gtk_widget_show(main_vb);
1818
1819   cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
1820   gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
1821   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1822   SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
1823   gtk_widget_show(cfmark_cb);
1824   color_set_export_marked_sensitive(cfmark_cb);
1825
1826   cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1827   gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1828   SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1829   gtk_widget_show(cfglobal_but);
1830
1831   SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1832
1833 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1834   if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1835   {
1836       file_color_export_ok_cb(file_color_export_w, file_color_export_w);
1837   }
1838   else window_destroy(file_color_export_w);
1839 #else
1840   /* Connect the ok_button to file_export_ok_cb function and pass along a
1841      pointer to the file selection box widget */
1842   SIGNAL_CONNECT(GTK_FILE_SELECTION (file_color_export_w)->ok_button, "clicked",
1843                  file_color_export_ok_cb, file_color_export_w);
1844
1845   window_set_cancel_button(file_color_export_w, 
1846       GTK_FILE_SELECTION(file_color_export_w)->cancel_button, window_cancel_button_cb);
1847
1848   SIGNAL_CONNECT(file_color_export_w, "delete_event", window_delete_event_cb, NULL);
1849
1850
1851   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1852
1853   gtk_widget_show(file_color_export_w);
1854   window_present(file_color_export_w);
1855 #endif
1856 }
1857
1858 static void
1859 file_color_export_ok_cb(GtkWidget *w _U_, gpointer fs) {
1860   gchar *cf_name;
1861   gchar *dirname;
1862
1863 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1864   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1865 #else
1866   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1867 #endif
1868
1869   /* Perhaps the user specified a directory instead of a file.
1870      Check whether they did. */
1871   if (test_for_directory(cf_name) == EISDIR) {
1872         /* It's a directory - set the file selection box to display that
1873            directory, and leave the selection box displayed. */
1874         set_last_open_dir(cf_name);
1875         g_free(cf_name);
1876         file_selection_set_current_folder(fs, get_last_open_dir());
1877         return;
1878   }
1879
1880   /* Write out the filters (all, or only the ones that are currently
1881      displayed or marked) to the file with the specified name. */
1882
1883    if (!color_filters_export(cf_name, color_marked))
1884    {
1885     /* The write failed; don't dismiss the open dialog box,
1886        just leave it around so that the user can, after they
1887        dismiss the alert box popped up for the error, try again. */
1888
1889        g_free(cf_name);
1890        return;
1891    }
1892
1893   /* The write succeeded; get rid of the file selection box. */
1894   window_destroy(GTK_WIDGET (fs));
1895
1896   /* Save the directory name for future file dialogs. */
1897   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
1898   set_last_open_dir(dirname);
1899   g_free(cf_name);
1900 }
1901
1902 static void
1903 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1904 {
1905   file_color_export_w = NULL;
1906 }