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