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