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