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