minor code cleanup, including removed MSVC warnings
[obnox/wireshark/wip.git] / gtk / file_dlg.c
1 /* file_dlg.c
2  * Dialog boxes for handling files
3  *
4  * $Id: file_dlg.c,v 1.100 2004/03/27 12:18:40 ulfl Exp $
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 <gtk/gtk.h>
30
31 #include "range.h"
32 #include <epan/filesystem.h>
33
34 #include "globals.h"
35 #include "gtkglobals.h"
36 #include <epan/resolv.h>
37 #include "keys.h"
38 #include "filter_prefs.h"
39 #include "ui_util.h"
40 #include "alert_box.h"
41 #include "simple_dialog.h"
42 #include "menu.h"
43 #include "file_dlg.h"
44 #include "dlg_utils.h"
45 #include "main.h"
46 #include "compat_macros.h"
47 #include "prefs.h"
48 #include "recent.h"
49 #include "color.h"
50 #include "../ui_util.h"
51 #include "gtk/color_filters.h"
52 #include "gtk/color_dlg.h"
53 #ifdef HAVE_LIBPCAP
54 #include "capture_dlg.h"
55 #endif
56
57
58 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
59 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
60 static void select_file_type_cb(GtkWidget *w, gpointer data);
61 static void file_save_as_ok_cb(GtkWidget *w, gpointer fs);
62 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
63 static void file_color_import_ok_cb(GtkWidget *w, gpointer fs);
64 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
65 static void file_color_export_ok_cb(GtkWidget *w, gpointer fs);
66 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
67 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || GTK_MAJOR_VERSION < 2
68 static void file_select_ok_cb(GtkWidget *w, gpointer data);
69 static void file_select_cancel_cb(GtkWidget *w, gpointer data);
70 #endif
71 static void file_select_destroy_cb(GtkWidget *win, GtkWidget* file_te);
72 static void toggle_captured_cb(GtkWidget *widget, gpointer data _U_);
73
74 #define E_FILE_M_RESOLVE_KEY      "file_dlg_mac_resolve_key"
75 #define E_FILE_N_RESOLVE_KEY      "file_dlg_network_resolve_key"
76 #define E_FILE_T_RESOLVE_KEY      "file_dlg_transport_resolve_key"
77
78 #define ARGUMENT_CL "argument_cl"
79
80 /*
81  * Keep a static pointer to the current "Save Capture File As" window, if
82  * any, so that if somebody tries to do "File:Save" or "File:Save As"
83  * while there's already a "Save Capture File As" window up, we just pop
84  * up the existing one, rather than creating a new one.
85  */
86 static GtkWidget *file_save_as_w;
87
88 /*
89  * A generic select_file_cb routine that is intended to be connected to
90  * a Browse button on other dialog boxes. This allows the user to browse
91  * for a file and select it. We fill in the text_entry that is asssociated
92  * with the button that invoked us. 
93  *
94  * We display the window label specified in our args.
95  */
96 void
97 select_file_cb(GtkWidget *file_bt, const char *label)
98 {
99   GtkWidget *caller = gtk_widget_get_toplevel(file_bt);
100   GtkWidget *fs, *file_te;
101 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
102   gchar     *f_name;
103 #endif
104
105   /* Has a file selection dialog box already been opened for that top-level
106      widget? */
107   fs = OBJECT_GET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY);
108   file_te = OBJECT_GET_DATA(file_bt, E_FILE_TE_PTR_KEY);
109   if (fs != NULL) {
110     /* Yes.  Just re-activate that dialog box. */
111     reactivate_window(fs);
112     return;
113   }
114
115 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
116   fs = file_selection_new(label, GTK_FILE_CHOOSER_ACTION_SAVE);
117 #else
118   fs = file_selection_new(label);
119 #endif
120
121   /* If we've opened a file, start out by showing the files in the directory
122      in which that file resided. */
123   if (last_open_dir)
124 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
125     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs), last_open_dir);
126 #else
127     gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
128 #endif
129
130   OBJECT_SET_DATA(fs, PRINT_FILE_TE_KEY, file_te);
131
132   /* Set the E_FS_CALLER_PTR_KEY for the new dialog to point to our caller. */
133   OBJECT_SET_DATA(fs, E_FS_CALLER_PTR_KEY, caller);
134
135   /* Set the E_FILE_SEL_DIALOG_PTR_KEY for the caller to point to us */
136   OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, fs);
137
138   /* Call a handler when the file selection box is destroyed, so we can inform
139      our caller, if any, that it's been destroyed. */
140   SIGNAL_CONNECT(fs, "destroy", GTK_SIGNAL_FUNC(file_select_destroy_cb), 
141                  file_te);
142
143 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
144   if (gtk_dialog_run(GTK_DIALOG(fs)) == GTK_RESPONSE_ACCEPT)
145   {
146       f_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
147       gtk_entry_set_text(GTK_ENTRY(file_te), f_name);
148       g_free(f_name);
149   }
150   gtk_widget_destroy(fs);
151 #else
152   SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->ok_button, "clicked", 
153                  file_select_ok_cb, fs);
154
155   /* Connect the cancel_button to destroy the widget */
156   SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->cancel_button, "clicked",
157                  file_select_cancel_cb, fs);
158
159   /* Catch the "key_press_event" signal in the window, so that we can catch
160      the ESC key being pressed and act as if the "Cancel" button had
161      been selected. */
162   dlg_set_cancel(fs, GTK_FILE_SELECTION(fs)->cancel_button);
163
164   gtk_widget_show(fs);
165 #endif
166 }
167
168 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || GTK_MAJOR_VERSION < 2
169 static void
170 file_select_ok_cb(GtkWidget *w _U_, gpointer data)
171 {
172   gchar     *f_name;
173
174   f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));
175
176   /* Perhaps the user specified a directory instead of a file.
177      Check whether they did. */
178   if (test_for_directory(f_name) == EISDIR) {
179         /* It's a directory - set the file selection box to display it. */
180         set_last_open_dir(f_name);
181         g_free(f_name);
182         gtk_file_selection_set_filename(GTK_FILE_SELECTION(data),
183                                         last_open_dir);
184         return;
185   }
186
187   gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, PRINT_FILE_TE_KEY)),
188                      f_name);
189   gtk_widget_destroy(GTK_WIDGET(data));
190
191   g_free(f_name);
192 }
193
194 static void
195 file_select_cancel_cb(GtkWidget *w _U_, gpointer data)
196 {
197   gtk_widget_destroy(GTK_WIDGET(data));
198 }
199 #endif
200
201 static void
202 file_select_destroy_cb(GtkWidget *win, GtkWidget* file_te)
203 {
204   GtkWidget *caller;
205
206   /* Get the widget that requested that we be popped up.
207      (It should arrange to destroy us if it's destroyed, so
208      that we don't get a pointer to a non-existent window here.) */
209   caller = OBJECT_GET_DATA(win, E_FS_CALLER_PTR_KEY);
210
211   /* Tell it we no longer exist. */
212   OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, NULL);
213
214   /* Now nuke this window. */
215   gtk_grab_remove(GTK_WIDGET(win));
216   gtk_widget_destroy(GTK_WIDGET(win));
217
218   /* Give the focus to the file text entry widget so the user can just press
219      Return to print to the file. */
220   gtk_widget_grab_focus(file_te);
221 }
222
223 /*
224  * Keep a static pointer to the current "Open Capture File" window, if
225  * any, so that if somebody tries to do "File:Open" while there's already
226  * an "Open Capture File" window up, we just pop up the existing one,
227  * rather than creating a new one.
228  */
229 static GtkWidget *file_open_w;
230
231 /* Open a file */
232 void
233 file_open_cmd(GtkWidget *w)
234 {
235   GtkWidget     *main_vb, *filter_hbox, *filter_bt, *filter_te,
236                 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
237 #if GTK_MAJOR_VERSION < 2
238   GtkAccelGroup *accel_group;
239 #endif
240   /* No Apply button, and "OK" just sets our text widget, it doesn't
241      activate it (i.e., it doesn't cause us to try to open the file). */
242   static construct_args_t args = {
243         "Ethereal: Read Filter",
244         FALSE,
245         FALSE
246   };
247
248   if (file_open_w != NULL) {
249     /* There's already an "Open Capture File" dialog box; reactivate it. */
250     reactivate_window(file_open_w);
251     return;
252   }
253
254 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
255   file_open_w = file_selection_new("Ethereal: Open Capture File",
256                                    GTK_FILE_CHOOSER_ACTION_OPEN);
257 #else
258   file_open_w = file_selection_new("Ethereal: Open Capture File");
259 #endif
260   SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
261
262 #if GTK_MAJOR_VERSION < 2
263   /* Accelerator group for the accelerators (or, as they're called in
264      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
265      Ctrl+<key> is an accelerator). */
266   accel_group = gtk_accel_group_new();
267   gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
268 #endif
269
270   switch (prefs.gui_fileopen_style) {
271
272   case FO_STYLE_LAST_OPENED:
273     /* The user has specified that we should start out in the last directory
274        we looked in.  If we've already opened a file, use its containing
275        directory, if we could determine it, as the directory, otherwise
276        use the "last opened" directory saved in the preferences file if
277        there was one. */
278     if (last_open_dir) {
279 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
280       gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_open_w),
281                                           last_open_dir);
282 #else
283       gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
284                                       last_open_dir);
285 #endif
286     }
287     break;
288
289   case FO_STYLE_SPECIFIED:
290     /* The user has specified that we should always start out in a
291        specified directory; if they've specified that directory,
292        start out by showing the files in that dir. */
293     if (prefs.gui_fileopen_dir[0] != '\0') {
294 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
295       gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_open_w),
296                                           prefs.gui_fileopen_dir);
297 #else
298       gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
299                                       prefs.gui_fileopen_dir);
300 #endif
301     }
302     break;
303   }
304     
305   /* Container for each row of widgets */
306   main_vb = gtk_vbox_new(FALSE, 3);
307   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
308 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
309   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_open_w), main_vb);
310 #else
311   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_open_w)->action_area),
312     main_vb, FALSE, FALSE, 0);
313 #endif
314   gtk_widget_show(main_vb);
315
316   filter_hbox = gtk_hbox_new(FALSE, 1);
317   gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
318   gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
319   gtk_widget_show(filter_hbox);
320
321   filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
322   SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
323   SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
324   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
325   gtk_widget_show(filter_bt);
326
327   filter_te = gtk_entry_new();
328   OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
329   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
330   SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
331   gtk_widget_show(filter_te);
332
333 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
334   OBJECT_SET_DATA(file_open_w, E_RFILTER_TE_KEY, filter_te);
335 #else
336   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
337                   E_RFILTER_TE_KEY, filter_te);
338 #endif
339
340   m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
341   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
342         g_resolv_flags & RESOLV_MAC);
343   gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
344 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
345   OBJECT_SET_DATA(file_open_w,
346                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
347 #else
348   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
349                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
350 #endif
351   gtk_widget_show(m_resolv_cb);
352
353   n_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _network name resolution", accel_group);
354   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
355         g_resolv_flags & RESOLV_NETWORK);
356   gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
357   gtk_widget_show(n_resolv_cb);
358 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
359   OBJECT_SET_DATA(file_open_w, E_FILE_N_RESOLVE_KEY, n_resolv_cb);
360 #else
361   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
362                   E_FILE_N_RESOLVE_KEY, n_resolv_cb);
363 #endif
364
365   t_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _transport name resolution", accel_group);
366   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
367         g_resolv_flags & RESOLV_TRANSPORT);
368   gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
369   gtk_widget_show(t_resolv_cb);
370 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
371   OBJECT_SET_DATA(file_open_w, E_FILE_T_RESOLVE_KEY, t_resolv_cb);
372 #else
373   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
374                   E_FILE_T_RESOLVE_KEY, t_resolv_cb);
375 #endif
376
377 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
378   OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
379                   OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
380   if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
381   {
382     file_open_ok_cb(file_open_w, file_open_w);
383   }
384   else gtk_widget_destroy(file_open_w);
385 #else
386   /* Connect the ok_button to file_open_ok_cb function and pass along a
387      pointer to the file selection box widget */
388   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
389                  file_open_ok_cb, file_open_w);
390
391   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
392                   E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
393
394   /* Connect the cancel_button to destroy the widget */
395   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_open_w)->cancel_button,
396                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
397                         file_open_w);
398
399   /* Catch the "key_press_event" signal in the window, so that we can catch
400      the ESC key being pressed and act as if the "Cancel" button had
401      been selected. */
402   dlg_set_cancel(file_open_w, GTK_FILE_SELECTION(file_open_w)->cancel_button);
403
404   gtk_widget_show(file_open_w);
405 #endif
406 }
407
408 void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
409 {
410     switch(btn) {
411     case(ESD_BTN_YES):
412         /* save file first */
413         file_save_as_cmd(after_save_open_dialog, data);
414         break;
415     case(ESD_BTN_NO):
416         cf_close(&cfile);
417         file_open_cmd(data);
418         break;
419     case(ESD_BTN_CANCEL):
420         break;
421     default:
422         g_assert_not_reached();
423     }
424 }
425
426 void
427 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
428   gpointer  dialog;
429
430   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
431     /* user didn't saved his current file, ask him */
432     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
433                 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
434                 "If you open a new capture file without saving, your capture data will be discarded.");
435     simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
436   } else {
437     /* unchanged file, just open a new one */
438     file_open_cmd(widget);
439   }
440 }
441
442 static void
443 file_open_ok_cb(GtkWidget *w, gpointer fs) {
444   gchar     *cf_name, *rfilter, *s;
445   GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
446   dfilter_t *rfcode = NULL;
447   int        err;
448
449 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
450   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
451 #else
452   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
453 #endif
454   filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
455   rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
456   if (!dfilter_compile(rfilter, &rfcode)) {
457     bad_dfilter_alert_box(rfilter);
458     g_free(cf_name);
459     return;
460   }
461
462   /* Perhaps the user specified a directory instead of a file.
463      Check whether they did. */
464   if (test_for_directory(cf_name) == EISDIR) {
465         /* It's a directory - set the file selection box to display that
466            directory, don't try to open the directory as a capture file. */
467         set_last_open_dir(cf_name);
468         g_free(cf_name);
469         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
470         return;
471   }
472
473   /* Try to open the capture file. */
474   if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
475     /* We couldn't open it; don't dismiss the open dialog box,
476        just leave it around so that the user can, after they
477        dismiss the alert box popped up for the open error,
478        try again. */
479     if (rfcode != NULL)
480       dfilter_free(rfcode);
481     g_free(cf_name);
482     return;
483   }
484
485   /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
486      it closed the previous capture file, and thus destroyed any
487      previous read filter attached to "cf"). */
488   cfile.rfcode = rfcode;
489
490   /* Set the global resolving variable */
491   g_resolv_flags = prefs.name_resolve & RESOLV_CONCURRENT;
492   m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
493   g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)) ? RESOLV_MAC : RESOLV_NONE;
494   n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
495   g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)) ? RESOLV_NETWORK : RESOLV_NONE;
496   t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
497   g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)) ? RESOLV_TRANSPORT : RESOLV_NONE;
498
499   /* We've crossed the Rubicon; get rid of the file selection box. */
500   gtk_widget_hide(GTK_WIDGET (fs));
501   gtk_widget_destroy(GTK_WIDGET (fs));
502
503   switch (cf_read(&cfile)) {
504
505   case READ_SUCCESS:
506   case READ_ERROR:
507     /* Just because we got an error, that doesn't mean we were unable
508        to read any of the file; we handle what we could get from the
509        file. */
510     break;
511
512   case READ_ABORTED:
513     /* The user bailed out of re-reading the capture file; the
514        capture file has been closed - just free the capture file name
515        string and return (without changing the last containing
516        directory). */
517     g_free(cf_name);
518     return;
519   }
520
521   /* Save the name of the containing directory specified in the path name,
522      if any; we can write over cf_name, which is a good thing, given that
523      "get_dirname()" does write over its argument. */
524   s = get_dirname(cf_name);
525   set_last_open_dir(s);
526   gtk_widget_grab_focus(packet_list);
527
528   g_free(cf_name);
529 }
530
531 static void
532 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
533 {
534   /* Note that we no longer have a "Open Capture File" dialog box. */
535   file_open_w = NULL;
536 }
537
538 void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
539 {
540     switch(btn) {
541     case(ESD_BTN_YES):
542         /* save file first */
543         file_save_as_cmd(after_save_close_file, NULL);
544         break;
545     case(ESD_BTN_NO):
546         cf_close(&cfile);
547         break;
548     case(ESD_BTN_CANCEL):
549         break;
550     default:
551         g_assert_not_reached();
552     }
553 }
554
555 /* Close a file */
556 void
557 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
558   gpointer  dialog;
559
560   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
561     /* user didn't saved his current file, ask him */
562     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
563                 PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
564                 "If you close without saving, your capture data will be discarded.");
565
566     simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
567   } else {
568     /* unchanged file, just close it */
569     cf_close(&cfile);
570   }
571 }
572
573 void
574 file_save_cmd_cb(GtkWidget *w, gpointer data) {
575   /* If the file's already been saved, do nothing.  */
576   if (cfile.user_saved)
577     return;
578
579   /* Do a "Save As". */
580   file_save_as_cmd_cb(w, data);
581 }
582
583 /* XXX - can we make these not be static? */
584 static packet_range_t range;
585 static gboolean color_marked;
586 static int filetype;
587 static GtkWidget *captured_bt;
588 static GtkWidget *displayed_bt;
589 static GtkWidget *select_all_rb;
590 static GtkWidget *select_all_c_lb;
591 static GtkWidget *select_all_d_lb;
592 static GtkWidget *select_curr_rb;
593 static GtkWidget *select_curr_c_lb;
594 static GtkWidget *select_curr_d_lb;
595 static GtkWidget *select_marked_only_rb;
596 static GtkWidget *select_marked_only_c_lb;
597 static GtkWidget *select_marked_only_d_lb;
598 static GtkWidget *select_marked_range_rb;
599 static GtkWidget *select_marked_range_c_lb;
600 static GtkWidget *select_marked_range_d_lb;
601 static GtkWidget *select_user_range_rb;
602 static GtkWidget *select_user_range_c_lb;
603 static GtkWidget *select_user_range_d_lb;
604 static GtkWidget *select_user_range_entry;
605 static GtkWidget *cfmark_cb;
606 static GtkWidget *ft_om;
607
608 static gboolean
609 can_save_with_wiretap(int ft)
610 {
611   /* To save a file with Wiretap, Wiretap has to handle that format,
612      and its code to handle that format must be able to write a file
613      with this file's encapsulation type. */
614   return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
615 }
616
617 static void
618 file_set_save_dynamics(void) {
619   gboolean      filtered_active;
620   gchar         label_text[100];
621   gint          selected_num;
622
623
624   filtered_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(displayed_bt));
625
626   gtk_widget_set_sensitive(displayed_bt, can_save_with_wiretap(filetype));
627
628   gtk_widget_set_sensitive(select_all_c_lb, !filtered_active);
629   g_snprintf(label_text, sizeof(label_text), "%u", cfile.count);
630   gtk_label_set_text(GTK_LABEL(select_all_c_lb), label_text);
631   gtk_widget_set_sensitive(select_all_d_lb, filtered_active);
632   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_cnt);
633
634   gtk_label_set_text(GTK_LABEL(select_all_d_lb), label_text);
635
636   selected_num = (cfile.current_frame) ? cfile.current_frame->num : 0;
637   /* XXX: how to update the radio button label but keep the mnemonic? */
638 /*  g_snprintf(label_text, sizeof(label_text), "_Selected packet #%u only", selected_num);
639   gtk_label_set_text(GTK_LABEL(GTK_BIN(select_curr_rb)->child), label_text);*/
640   gtk_widget_set_sensitive(select_curr_rb, selected_num);
641   g_snprintf(label_text, sizeof(label_text), "%u", selected_num ? 1 : 0);
642   gtk_label_set_text(GTK_LABEL(select_curr_c_lb), label_text);
643   gtk_widget_set_sensitive(select_curr_c_lb, selected_num && !filtered_active);
644   g_snprintf(label_text, sizeof(label_text), "%u", selected_num ? 1 : 0);
645   gtk_label_set_text(GTK_LABEL(select_curr_d_lb), label_text);
646   gtk_widget_set_sensitive(select_curr_d_lb, selected_num && filtered_active);
647
648   gtk_widget_set_sensitive(select_marked_only_rb, cfile.marked_count);
649   g_snprintf(label_text, sizeof(label_text), "%u", cfile.marked_count);
650   gtk_label_set_text(GTK_LABEL(select_marked_only_c_lb), label_text);
651   gtk_widget_set_sensitive(select_marked_only_c_lb, cfile.marked_count && !filtered_active);
652   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_marked_cnt);
653   gtk_label_set_text(GTK_LABEL(select_marked_only_d_lb), label_text);
654   gtk_widget_set_sensitive(select_marked_only_d_lb, range.displayed_marked_cnt && filtered_active);
655
656   gtk_widget_set_sensitive(select_marked_range_rb, range.mark_range_cnt);
657   g_snprintf(label_text, sizeof(label_text), "%u", range.mark_range_cnt);
658   gtk_label_set_text(GTK_LABEL(select_marked_range_c_lb), label_text);
659   gtk_widget_set_sensitive(select_marked_range_c_lb, range.mark_range_cnt && !filtered_active);
660   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_mark_range_cnt);
661   gtk_label_set_text(GTK_LABEL(select_marked_range_d_lb), label_text);
662   gtk_widget_set_sensitive(select_marked_range_d_lb, range.displayed_mark_range_cnt && filtered_active);
663
664   gtk_widget_set_sensitive(select_user_range_rb, TRUE);
665   g_snprintf(label_text, sizeof(label_text), "%u", range.user_range_cnt);
666   gtk_label_set_text(GTK_LABEL(select_user_range_c_lb), label_text);
667   gtk_widget_set_sensitive(select_user_range_c_lb, !filtered_active);
668   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_user_range_cnt);
669   gtk_label_set_text(GTK_LABEL(select_user_range_d_lb), label_text);
670   gtk_widget_set_sensitive(select_user_range_d_lb, filtered_active);
671 }
672
673 /* Generate a list of the file types we can save this file as.
674
675    "filetype" is the type it has now.
676
677    "encap" is the encapsulation for its packets (which could be
678    "unknown" or "per-packet").
679
680    "filtered" is TRUE if we're to save only the packets that passed
681    the display filter (in which case we have to save it using Wiretap)
682    and FALSE if we're to save the entire file (in which case, if we're
683    saving it in the type it has already, we can just copy it).
684
685    The same applies for sel_curr, sel_all, sel_m_only, sel_m_range and sel_man_range
686 */
687 static void
688 set_file_type_list(GtkWidget *option_menu)
689 {
690   GtkWidget *ft_menu, *ft_menu_item;
691   int ft;
692   guint index;
693   guint item_to_select;
694
695   /* Default to the first supported file type, if the file's current
696      type isn't supported. */
697   item_to_select = 0;
698
699   ft_menu = gtk_menu_new();
700
701   /* Check all file types. */
702   index = 0;
703   for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
704     if (!packet_range_process_all(&range) || ft != cfile.cd_t) {
705       /* not all unfiltered packets or a different file type.  We have to use Wiretap. */
706       if (!can_save_with_wiretap(ft))
707         continue;       /* We can't. */
708     }
709
710     /* OK, we can write it out in this type. */
711     ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
712     if (ft == filetype) {
713       /* Default to the same format as the file, if it's supported. */
714       item_to_select = index;
715     }
716     SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
717                    GINT_TO_POINTER(ft));
718     gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
719     gtk_widget_show(ft_menu_item);
720     index++;
721   }
722
723   gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
724   gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
725 }
726
727 static void
728 select_file_type_cb(GtkWidget *w _U_, gpointer data)
729 {
730   int new_filetype = GPOINTER_TO_INT(data);
731
732   if (filetype != new_filetype) {
733     /* We can select only the filtered or marked packets to be saved if we can
734        use Wiretap to save the file. */
735     gtk_widget_set_sensitive(displayed_bt, can_save_with_wiretap(new_filetype));
736     filetype = new_filetype;
737     file_set_save_marked_sensitive();
738   }
739 }
740
741 static void
742 toggle_captured_cb(GtkWidget *widget, gpointer data _U_)
743 {
744   /* is the button now active? */
745   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
746     /* They changed the state of the "captured" button. */
747     range.process_filtered = FALSE;
748     /* XXX: the following line fails, I have no idea why */
749     /* set_file_type_list(ft_om);*/
750
751     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(captured_bt), TRUE);
752     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(displayed_bt), FALSE);
753
754     file_set_save_dynamics();
755   }
756 }
757
758 static void
759 toggle_filtered_cb(GtkWidget *widget, gpointer data _U_)
760 {
761   /* is the button now active? */
762   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
763     range.process_filtered = TRUE;
764     set_file_type_list(ft_om);
765
766     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(captured_bt), FALSE);
767     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(displayed_bt), TRUE);
768     
769     file_set_save_dynamics();
770   }
771 }
772
773 static void
774 toggle_select_all(GtkWidget *widget, gpointer data _U_)
775 {
776   /* is the button now active? */
777   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
778     range.process = range_process_all;
779     set_file_type_list(ft_om);
780     file_set_save_dynamics();
781   }
782 }
783
784 static void
785 toggle_select_selected(GtkWidget *widget, gpointer data _U_)
786 {
787   /* is the button now active? */
788   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
789     range.process = range_process_selected;
790     set_file_type_list(ft_om);
791     file_set_save_dynamics();
792   }
793 }
794
795 static void
796 toggle_select_marked_only(GtkWidget *widget, gpointer data _U_)
797 {
798   /* is the button now active? */
799   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
800     range.process = range_process_marked;
801     set_file_type_list(ft_om);
802     file_set_save_dynamics();
803   }
804 }
805
806 static void
807 toggle_select_marked_range(GtkWidget *widget, gpointer data _U_)
808 {
809   /* is the button now active? */
810   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
811     range.process = range_process_marked_range;
812     set_file_type_list(ft_om);
813     file_set_save_dynamics();
814   }
815 }
816
817 static void
818 toggle_select_user_range(GtkWidget *widget, gpointer data _U_)
819 {
820   /* is the button now active? */
821   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
822     range.process = range_process_user_range;
823     set_file_type_list(ft_om);
824     file_set_save_dynamics();
825   }
826         
827   /* Make the entry widget sensitive or insensitive */
828   gtk_widget_set_sensitive(select_user_range_entry, range.process == range_process_user_range);
829
830   /* When selecting user specified range, then focus on the entry */
831   if (range.process == range_process_user_range)
832       gtk_widget_grab_focus(select_user_range_entry);
833
834 }
835
836 static void
837 range_entry(GtkWidget *entry)
838 {
839   const gchar *entry_text;
840
841   entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
842   packet_range_convert_str(&range, entry_text);
843   file_set_save_dynamics();
844 }
845
846 /*
847  * Set the "Save only marked packets" toggle button as appropriate for
848  * the current output file type and count of marked packets.
849  *
850  * Called when the "Save As..." dialog box is created and when either
851  * the file type or the marked count changes.
852  */
853 void
854 file_set_save_marked_sensitive(void)
855 {
856   if (file_save_as_w == NULL) {
857     /* We don't currently have a "Save As..." dialog box up. */
858     return;
859   }
860         
861   /* We can request that only the marked packets be saved only if we
862      can use Wiretap to save the file and if there *are* marked packets. */
863   if (can_save_with_wiretap(filetype) && cfile.marked_count != 0) {
864     gtk_widget_set_sensitive(select_marked_only_rb, TRUE);
865     gtk_widget_set_sensitive(select_marked_range_rb, TRUE);       
866   }
867   else {
868     /* Force the "Save only marked packets" toggle to "false", turn
869        off the flag it controls, and update the list of types we can
870        save the file as. */
871     range.process = range_process_all;
872     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_marked_only_rb), FALSE);
873     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_marked_range_rb), FALSE);       
874     set_file_type_list(ft_om);
875     gtk_widget_set_sensitive(select_marked_only_rb,  FALSE);
876     gtk_widget_set_sensitive(select_marked_range_rb, FALSE);      
877   }
878 }
879
880 action_after_save_e action_after_save_g;
881 gpointer            action_after_save_data_g;
882
883
884 void
885 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
886 {
887   GtkWidget     *main_vb, *ft_hb, *ft_lb, *range_fr, *range_tb;
888   GtkTooltips   *tooltips;
889
890 #if GTK_MAJOR_VERSION < 2
891   GtkAccelGroup *accel_group;
892 #endif
893           
894   if (file_save_as_w != NULL) {
895     /* There's already an "Save Capture File As" dialog box; reactivate it. */
896     reactivate_window(file_save_as_w);
897     return;
898   }
899
900   /* Default to saving all packets, in the file's current format. */
901   filetype = cfile.cd_t;
902
903   /* init the packet range */
904   packet_range_init(&range);
905
906   /* Enable tooltips */
907   tooltips = gtk_tooltips_new();
908           
909   /* build the file selection */
910 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
911   file_save_as_w = file_selection_new ("Ethereal: Save Capture File As",
912                                        GTK_FILE_CHOOSER_ACTION_SAVE);
913 #else
914   file_save_as_w = file_selection_new ("Ethereal: Save Capture File As");
915 #endif
916   SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
917
918   /* as the dialog might already be gone, when using this values, we cannot
919    * set data to the dialog object, but keep global values */
920   action_after_save_g       = action_after_save;
921   action_after_save_data_g  = action_after_save_data;
922
923 #if GTK_MAJOR_VERSION < 2
924   accel_group = gtk_accel_group_new();
925   gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
926 #endif
927         
928   /* If we've opened a file, start out by showing the files in the directory
929      in which that file resided. */
930   if (last_open_dir)
931 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
932     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_save_as_w),
933                                         last_open_dir);
934 #else
935     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w),
936                                     last_open_dir);
937 #endif
938
939   /* Container for each row of widgets */
940        
941   main_vb = gtk_vbox_new(FALSE, 5);
942   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
943 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
944   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_save_as_w), main_vb);
945 #else
946   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_save_as_w)->action_area),
947                      main_vb, FALSE, FALSE, 0);
948 #endif
949   gtk_widget_show(main_vb);     
950                 
951   /*** Packet Range frame ***/
952   range_fr = gtk_frame_new("Packet Range");
953   gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
954   gtk_widget_show(range_fr);
955   
956   /* range table */
957   range_tb = gtk_table_new(7, 3, FALSE);
958   gtk_container_border_width(GTK_CONTAINER(range_tb), 5);
959   gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
960   gtk_widget_show(range_tb);
961
962   /* captured button */
963   captured_bt = TOGGLE_BUTTON_NEW_WITH_MNEMONIC("_Captured", accel_group);
964   gtk_table_attach_defaults(GTK_TABLE(range_tb), captured_bt, 1, 2, 0, 1);
965   SIGNAL_CONNECT(captured_bt, "toggled", toggle_captured_cb, NULL);
966   gtk_tooltips_set_tip (tooltips,captured_bt,("Process all the below chosen packets"), NULL);
967   gtk_widget_show(captured_bt);
968
969   /* displayed button */
970   displayed_bt = TOGGLE_BUTTON_NEW_WITH_MNEMONIC("_Displayed", accel_group);
971   gtk_table_attach_defaults(GTK_TABLE(range_tb), displayed_bt, 2, 3, 0, 1);
972   SIGNAL_CONNECT(displayed_bt, "toggled", toggle_filtered_cb, NULL);
973   gtk_tooltips_set_tip (tooltips,displayed_bt,("Process only the below chosen packets, which also passes the current display filter"), NULL);
974   gtk_widget_show(displayed_bt);
975
976
977   /* Process all packets */
978   select_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "_All packets", accel_group);
979   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_all_rb, 0, 1, 1, 2);
980   gtk_tooltips_set_tip (tooltips,select_all_rb,("Process all packets"), NULL);
981   SIGNAL_CONNECT(select_all_rb, "toggled", toggle_select_all, NULL);
982   gtk_widget_show(select_all_rb);
983
984   select_all_c_lb = gtk_label_new("?");
985   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_all_c_lb, 1, 2, 1, 2);
986   gtk_widget_show(select_all_c_lb);
987   select_all_d_lb = gtk_label_new("?");
988   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_all_d_lb, 2, 3, 1, 2);
989   gtk_widget_show(select_all_d_lb);
990
991         
992   /* Process currently selected */
993   select_curr_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "_Selected packet only", accel_group);
994   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_curr_rb, 0, 1, 2, 3);
995   gtk_tooltips_set_tip (tooltips,select_curr_rb,("Process the currently selected packet only"), NULL);
996   SIGNAL_CONNECT(select_curr_rb, "toggled", toggle_select_selected, NULL);
997   gtk_widget_show(select_curr_rb);
998         
999   select_curr_c_lb = gtk_label_new("?");
1000   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_curr_c_lb, 1, 2, 2, 3);
1001   gtk_widget_show(select_curr_c_lb);
1002   select_curr_d_lb = gtk_label_new("?");
1003   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_curr_d_lb, 2, 3, 2, 3);
1004   gtk_widget_show(select_curr_d_lb);
1005
1006
1007   /* Process marked packets */
1008   select_marked_only_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "_Marked packets only", accel_group);
1009   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_only_rb, 0, 1, 3, 4);
1010   gtk_tooltips_set_tip (tooltips,select_marked_only_rb,("Process marked packets only"), NULL);
1011   SIGNAL_CONNECT(select_marked_only_rb, "toggled", toggle_select_marked_only, NULL);
1012   gtk_widget_show(select_marked_only_rb);
1013
1014   select_marked_only_c_lb = gtk_label_new("?");
1015   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_only_c_lb, 1, 2, 3, 4);
1016   gtk_widget_show(select_marked_only_c_lb);
1017   select_marked_only_d_lb = gtk_label_new("?");
1018   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_only_d_lb, 2, 3, 3, 4);
1019   gtk_widget_show(select_marked_only_d_lb);
1020
1021   
1022   /* Process packet range between first and last packet */
1023   select_marked_range_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "From first _to last marked packet", accel_group);
1024   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_range_rb, 0, 1, 4, 5);
1025   gtk_tooltips_set_tip (tooltips,select_marked_range_rb,("Process all packets between the first and last marker"), NULL);
1026   SIGNAL_CONNECT(select_marked_range_rb, "toggled", toggle_select_marked_range, NULL);
1027   gtk_widget_show(select_marked_range_rb);
1028
1029   select_marked_range_c_lb = gtk_label_new("?");
1030   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_range_c_lb, 1, 2, 4, 5);
1031   gtk_widget_show(select_marked_range_c_lb);
1032   select_marked_range_d_lb = gtk_label_new("?");
1033   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_range_d_lb, 2, 3, 4, 5);
1034   gtk_widget_show(select_marked_range_d_lb);
1035
1036
1037   /* Process a user specified provided packet range : -10,30,40-70,80- */
1038   select_user_range_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "Specify a packet _range:", accel_group);
1039   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_rb, 0, 1, 5, 6);
1040   gtk_tooltips_set_tip (tooltips,select_user_range_rb,("Process a specified packet range"), NULL);
1041   SIGNAL_CONNECT(select_user_range_rb, "toggled", toggle_select_user_range, NULL);
1042   gtk_widget_show(select_user_range_rb);
1043
1044   select_user_range_c_lb = gtk_label_new("?");
1045   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_c_lb, 1, 2, 5, 6);
1046   gtk_widget_show(select_user_range_c_lb);
1047   select_user_range_d_lb = gtk_label_new("?");
1048   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_d_lb, 2, 3, 5, 6);
1049   gtk_widget_show(select_user_range_d_lb);
1050
1051
1052   /* The entry part */
1053   select_user_range_entry = gtk_entry_new();
1054   gtk_entry_set_max_length (GTK_ENTRY (select_user_range_entry), 254);
1055   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_entry, 0, 1, 6, 7);
1056   gtk_tooltips_set_tip (tooltips,select_user_range_entry, 
1057         ("Specify a range of packet numbers :     \nExample :  1-10,18,25-100,332-"), NULL);
1058   SIGNAL_CONNECT(select_user_range_entry,"changed", range_entry, select_user_range_entry);      
1059   gtk_widget_set_sensitive(select_user_range_entry, FALSE);
1060   gtk_widget_show(select_user_range_entry);
1061
1062   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(captured_bt), TRUE);
1063   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(displayed_bt), FALSE);
1064   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_all_rb),  TRUE);
1065   
1066   /* File type row */
1067   ft_hb = gtk_hbox_new(FALSE, 3);
1068   gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1069   gtk_widget_show(ft_hb);
1070
1071   ft_lb = gtk_label_new("File type:");
1072   gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1073   gtk_widget_show(ft_lb);
1074
1075   ft_om = gtk_option_menu_new();
1076
1077   /* Generate the list of file types we can save. */
1078   set_file_type_list(ft_om);
1079   gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1080   gtk_widget_show(ft_om);
1081
1082   /*
1083    * Set the sensitivity of the "Save only marked packets" toggle
1084    * button
1085    *
1086    * This has to be done after we create the file type menu option,
1087    * as the routine that sets it also sets that menu.
1088    */
1089   file_set_save_marked_sensitive();
1090         
1091   /* dynamic values in the range frame */
1092   file_set_save_dynamics();
1093
1094 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1095   if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT)
1096   {
1097     file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1098   }
1099   else gtk_widget_destroy(file_save_as_w);
1100 #else
1101   /* Connect the ok_button to file_save_as_ok_cb function and pass along a
1102      pointer to the file selection box widget */
1103   SIGNAL_CONNECT(GTK_FILE_SELECTION (file_save_as_w)->ok_button, "clicked",
1104                  file_save_as_ok_cb, file_save_as_w);
1105
1106   /* Connect the cancel_button to destroy the widget */
1107   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_save_as_w)->cancel_button,
1108                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
1109                         file_save_as_w);
1110
1111   /* Catch the "key_press_event" signal in the window, so that we can catch
1112      the ESC key being pressed and act as if the "Cancel" button had
1113      been selected. */
1114   dlg_set_cancel(file_save_as_w, GTK_FILE_SELECTION(file_save_as_w)->cancel_button);
1115
1116   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w), "");
1117
1118   gtk_widget_show(file_save_as_w);
1119 #endif
1120 }
1121
1122 void
1123 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1124 {
1125   file_save_as_cmd(after_save_no_action, NULL);
1126 }
1127
1128 static void
1129 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1130   gchar *cf_name;
1131   gchar *dirname;
1132
1133 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1134   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1135 #else
1136   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1137 #endif
1138
1139   /* Perhaps the user specified a directory instead of a file.
1140      Check whether they did. */
1141   if (test_for_directory(cf_name) == EISDIR) {
1142         /* It's a directory - set the file selection box to display that
1143            directory, and leave the selection box displayed. */
1144         set_last_open_dir(cf_name);
1145         g_free(cf_name);
1146         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1147         return;
1148   }
1149
1150   /* don't show the dialog while saving */
1151   gtk_widget_hide(GTK_WIDGET (fs));
1152
1153   /* Write out the packets (all, or only the ones from the current
1154      range) to the file with the specified name. */
1155   if (! cf_save(cf_name, &cfile, &range, filetype)) {
1156     /* The write failed; don't dismiss the open dialog box,
1157        just leave it around so that the user can, after they
1158        dismiss the alert box popped up for the error, try again. */
1159     g_free(cf_name);
1160     gtk_widget_show(GTK_WIDGET (fs));
1161     return;
1162   }
1163
1164   /* The write succeeded; get rid of the file selection box. */
1165   /* cf_save might already closed our dialog! */
1166   if (file_save_as_w)
1167     gtk_widget_destroy(GTK_WIDGET (fs));
1168
1169   /* Save the directory name for future file dialogs. */
1170   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
1171   set_last_open_dir(dirname);
1172   g_free(cf_name);
1173
1174   /* we have finished saving, do we have pending things to do? */
1175   switch(action_after_save_g) {
1176   case(after_save_no_action):
1177       break;
1178   case(after_save_open_dialog):
1179       file_open_cmd(action_after_save_data_g);
1180       break;
1181   case(after_save_open_recent_file):
1182       menu_open_recent_file_cmd(action_after_save_data_g);
1183       break;
1184   case(after_save_open_dnd_file):
1185       dnd_open_file_cmd(action_after_save_data_g);
1186       break;
1187 #ifdef HAVE_LIBPCAP
1188   case(after_save_capture_dialog):
1189       capture_prep();
1190       break;
1191 #endif
1192   case(after_save_close_file):
1193       cf_close(&cfile);
1194       break;
1195   case(after_save_exit):
1196       main_do_quit();
1197       break;
1198   default:
1199       g_assert_not_reached();
1200   }
1201
1202   action_after_save_g = after_save_no_action;
1203 }
1204
1205 void
1206 file_save_as_destroy(void)
1207 {
1208   if (file_save_as_w)
1209     gtk_widget_destroy(file_save_as_w);
1210 }
1211
1212 static void
1213 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1214 {
1215   /* Note that we no longer have a "Save Capture File As" dialog box. */
1216   file_save_as_w = NULL;
1217 }
1218
1219 /* Reload a file using the current read and display filters */
1220 void
1221 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1222   gchar *filename;
1223   gboolean is_tempfile;
1224
1225   /* If the file could be opened, "cf_open()" calls "cf_close()"
1226      to get rid of state for the old capture file before filling in state
1227      for the new capture file.  "cf_close()" will remove the file if
1228      it's a temporary file; we don't want that to happen (for one thing,
1229      it'd prevent subsequent reopens from working).  Remember whether it's
1230      a temporary file, mark it as not being a temporary file, and then
1231      reopen it as the type of file it was.
1232
1233      Also, "cf_close()" will free "cfile.filename", so we must make
1234      a copy of it first. */
1235   filename = g_strdup(cfile.filename);
1236   is_tempfile = cfile.is_tempfile;
1237   cfile.is_tempfile = FALSE;
1238   if (cf_open(filename, is_tempfile, &cfile) == 0) {
1239     switch (cf_read(&cfile)) {
1240
1241     case READ_SUCCESS:
1242     case READ_ERROR:
1243       /* Just because we got an error, that doesn't mean we were unable
1244          to read any of the file; we handle what we could get from the
1245          file. */
1246       break;
1247
1248     case READ_ABORTED:
1249       /* The user bailed out of re-reading the capture file; the
1250          capture file has been closed - just free the capture file name
1251          string and return (without changing the last containing
1252          directory). */
1253       g_free(filename);
1254       return;
1255     }
1256   } else {
1257     /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
1258        Instead, the file was left open, so we should restore "cfile.is_tempfile"
1259        ourselves.
1260
1261        XXX - change the menu?  Presumably "cf_open()" will do that;
1262        make sure it does! */
1263     cfile.is_tempfile = is_tempfile;
1264   }
1265   /* "cf_open()" made a copy of the file name we handed it, so
1266      we should free up our copy. */
1267   g_free(filename);
1268 }
1269
1270 /******************** Color Filters *********************************/
1271 /*
1272  * Keep a static pointer to the current "Color Export" window, if
1273  * any, so that if somebody tries to do "Export"
1274  * while there's already a "Color Export" window up, we just pop
1275  * up the existing one, rather than creating a new one.
1276  */
1277 static GtkWidget *file_color_import_w;
1278
1279 /* sets the file path to the global color filter file.
1280    WARNING: called by both the import and the export dialog.
1281 */
1282 static void
1283 color_global_cb(GtkWidget *widget _U_, gpointer data)
1284 {
1285   GtkWidget *fs_widget = data;
1286   gchar *path;
1287
1288   /* decide what file to open (from dfilter code) */
1289   path = get_datafile_path("colorfilters");
1290
1291 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1292   gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1293 #else
1294   gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs_widget), path);
1295 #endif
1296   g_free((gchar *)path);
1297 }
1298
1299 /* Import color filters */
1300 void
1301 file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
1302 {
1303   GtkWidget     *main_vb, *cfglobal_but;
1304 #if GTK_MAJOR_VERSION < 2
1305   GtkAccelGroup *accel_group;
1306 #endif
1307   /* No Apply button, and "OK" just sets our text widget, it doesn't
1308      activate it (i.e., it doesn't cause us to try to open the file). */
1309
1310   if (file_color_import_w != NULL) {
1311     /* There's already an "Import Color Filters" dialog box; reactivate it. */
1312     reactivate_window(file_color_import_w);
1313     return;
1314   }
1315
1316 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1317   file_color_import_w = file_selection_new("Ethereal: Import Color Filters",
1318                                            GTK_FILE_CHOOSER_ACTION_OPEN);
1319 #else
1320   file_color_import_w = gtk_file_selection_new("Ethereal: Import Color Filters");
1321 #endif
1322   SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1323
1324 #if GTK_MAJOR_VERSION < 2
1325   /* Accelerator group for the accelerators (or, as they're called in
1326      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1327      Ctrl+<key> is an accelerator). */
1328   accel_group = gtk_accel_group_new();
1329   gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1330 #endif
1331
1332   /* If we've opened a file, start out by showing the files in the directory
1333      in which that file resided. */
1334   if (last_open_dir)
1335 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1336     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_color_import_w),
1337                                         last_open_dir);
1338 #else
1339     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_import_w),
1340                                     last_open_dir);
1341 #endif
1342
1343   /* Container for each row of widgets */
1344   main_vb = gtk_vbox_new(FALSE, 3);
1345   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1346 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1347   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_color_import_w),
1348                                     main_vb);
1349 #else
1350   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_import_w)->action_area),
1351                      main_vb, FALSE, FALSE, 0);
1352 #endif
1353   gtk_widget_show(main_vb);
1354
1355
1356   cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1357   gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1358   SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1359   gtk_widget_show(cfglobal_but);
1360
1361 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1362   OBJECT_SET_DATA(file_color_import_w, ARGUMENT_CL, data);
1363
1364   if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1365   {
1366       file_color_import_ok_cb(file_color_import_w, file_color_import_w);
1367   }
1368   else gtk_widget_destroy(file_color_import_w);
1369 #else
1370   /* Connect the ok_button to file_open_ok_cb function and pass along a
1371      pointer to the file selection box widget */
1372   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1373                  file_color_import_ok_cb, file_color_import_w);
1374
1375   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
1376                   ARGUMENT_CL, data);
1377
1378   /* Connect the cancel_button to destroy the widget */
1379   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_import_w)->cancel_button,
1380                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
1381                         file_color_import_w);
1382
1383   /* Catch the "key_press_event" signal in the window, so that we can catch
1384      the ESC key being pressed and act as if the "Cancel" button had
1385      been selected. */
1386   dlg_set_cancel(file_color_import_w, GTK_FILE_SELECTION(file_color_import_w)->cancel_button);
1387
1388   gtk_widget_show(file_color_import_w);
1389 #endif
1390 }
1391
1392 static void
1393 file_color_import_ok_cb(GtkWidget *w, gpointer fs) {
1394   gchar     *cf_name, *s;
1395   gpointer  argument;
1396
1397   argument = OBJECT_GET_DATA(w, ARGUMENT_CL);     /* to be passed back into read_other_filters */
1398   
1399 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1400   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1401 #else
1402   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1403 #endif
1404   /* Perhaps the user specified a directory instead of a file.
1405      Check whether they did. */
1406   if (test_for_directory(cf_name) == EISDIR) {
1407         /* It's a directory - set the file selection box to display that
1408            directory, don't try to open the directory as a capture file. */
1409         set_last_open_dir(cf_name);
1410         g_free(cf_name);
1411         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1412         return;
1413   }
1414
1415   /* Try to open the capture file. */
1416
1417   if (!read_other_filters(cf_name, argument)) {
1418     /* We couldn't open it; don't dismiss the open dialog box,
1419        just leave it around so that the user can, after they
1420        dismiss the alert box popped up for the open error,
1421        try again. */
1422     g_free(cf_name);
1423     return;
1424   }
1425
1426   /* We've crossed the Rubicon; get rid of the file selection box. */
1427   gtk_widget_hide(GTK_WIDGET (fs));
1428   gtk_widget_destroy(GTK_WIDGET (fs));
1429
1430   /* Save the name of the containing directory specified in the path name,
1431      if any; we can write over cf_name, which is a good thing, given that
1432      "get_dirname()" does write over its argument. */
1433   s = get_dirname(cf_name);
1434   set_last_open_dir(s);
1435   gtk_widget_grab_focus(packet_list);
1436
1437   g_free(cf_name);
1438 }
1439
1440 static void
1441 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1442 {
1443   /* Note that we no longer have a "Open Capture File" dialog box. */
1444   file_color_import_w = NULL;
1445 }
1446
1447 static GtkWidget *file_color_export_w;
1448 /*
1449  * Set the "Export only marked filters" toggle button as appropriate for
1450  * the current output file type and count of marked filters.
1451  *
1452  * Called when the "Export" dialog box is created and when the marked
1453  * count changes.
1454  */
1455 void
1456 color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
1457 {
1458   if (file_color_export_w == NULL) {
1459     /* We don't currently have an "Export" dialog box up. */
1460     return;
1461   }
1462
1463   /* We can request that only the marked filters be saved only if
1464         there *are* marked filters. */
1465   if (color_marked_count() != 0)
1466     gtk_widget_set_sensitive(cfmark_cb, TRUE);
1467   else {
1468     /* Force the "Export only marked filters" toggle to "false", turn
1469        off the flag it controls. */
1470     color_marked = FALSE;
1471     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1472     gtk_widget_set_sensitive(cfmark_cb, FALSE);
1473   }
1474 }
1475
1476 static void
1477 color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
1478 {
1479   color_marked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1480 }
1481
1482 void
1483 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1484 {
1485   GtkWidget *main_vb, *cfglobal_but;
1486
1487   if (file_color_export_w != NULL) {
1488     /* There's already an "Color Filter Export" dialog box; reactivate it. */
1489     reactivate_window(file_color_export_w);
1490     return;
1491   }
1492
1493   /* Default to saving all packets, in the file's current format. */
1494   color_marked   = FALSE;
1495   filetype = cfile.cd_t;
1496
1497 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1498   file_color_export_w = file_selection_new("Ethereal: Export Color Filters",
1499                                            GTK_FILE_CHOOSER_ACTION_SAVE);
1500 #else
1501   file_color_export_w = gtk_file_selection_new("Ethereal: Export Color Filters");
1502 #endif
1503   SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1504
1505   /* If we've opened a file, start out by showing the files in the directory
1506      in which that file resided. */
1507   if (last_open_dir)
1508 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1509     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_color_export_w),
1510                                         last_open_dir);
1511 #else
1512     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w),
1513                                     last_open_dir);
1514
1515 #endif
1516   /* Container for each row of widgets */
1517   main_vb = gtk_vbox_new(FALSE, 3);
1518   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1519 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1520   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_color_export_w),
1521                                     main_vb);
1522 #else
1523   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_export_w)->action_area),
1524     main_vb, FALSE, FALSE, 0);
1525 #endif
1526   gtk_widget_show(main_vb);
1527
1528   cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
1529   gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
1530   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1531   SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
1532   gtk_widget_show(cfmark_cb);
1533   color_set_export_marked_sensitive(cfmark_cb);
1534
1535   cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1536   gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1537   SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1538   gtk_widget_show(cfglobal_but);
1539
1540 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1541   if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1542   {
1543       file_color_export_ok_cb(file_color_export_w, file_color_export_w);
1544   }
1545   else gtk_widget_destroy(file_color_export_w);
1546 #else
1547   /* Connect the ok_button to file_export_ok_cb function and pass along a
1548      pointer to the file selection box widget */
1549   SIGNAL_CONNECT(GTK_FILE_SELECTION (file_color_export_w)->ok_button, "clicked",
1550                  file_color_export_ok_cb, file_color_export_w);
1551
1552   /* Connect the cancel_button to destroy the widget */
1553   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_export_w)->cancel_button,
1554                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
1555                         file_color_export_w);
1556
1557   /* Catch the "key_press_event" signal in the window, so that we can catch
1558      the ESC key being pressed and act as if the "Cancel" button had
1559      been selected. */
1560   dlg_set_cancel(file_color_export_w, GTK_FILE_SELECTION(file_color_export_w)->cancel_button);
1561
1562   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1563
1564   gtk_widget_show(file_color_export_w);
1565 #endif
1566 }
1567
1568 static void
1569 file_color_export_ok_cb(GtkWidget *w _U_, gpointer fs) {
1570   gchar *cf_name;
1571   gchar *dirname;
1572
1573 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1574   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1575 #else
1576   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1577 #endif
1578
1579   /* Perhaps the user specified a directory instead of a file.
1580      Check whether they did. */
1581   if (test_for_directory(cf_name) == EISDIR) {
1582         /* It's a directory - set the file selection box to display that
1583            directory, and leave the selection box displayed. */
1584         set_last_open_dir(cf_name);
1585         g_free(cf_name);
1586         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1587         return;
1588   }
1589
1590   /* Write out the filters (all, or only the ones that are currently
1591      displayed or marked) to the file with the specified name. */
1592
1593    if (!write_other_filters(cf_name, color_marked))
1594    {
1595     /* The write failed; don't dismiss the open dialog box,
1596        just leave it around so that the user can, after they
1597        dismiss the alert box popped up for the error, try again. */
1598
1599        g_free(cf_name);
1600        return;
1601    }
1602
1603   /* The write succeeded; get rid of the file selection box. */
1604   gtk_widget_hide(GTK_WIDGET (fs));
1605   gtk_widget_destroy(GTK_WIDGET (fs));
1606
1607   /* Save the directory name for future file dialogs. */
1608   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
1609   set_last_open_dir(dirname);
1610   g_free(cf_name);
1611 }
1612
1613 static void
1614 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1615 {
1616   file_color_export_w = NULL;
1617 }