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