ea4e63d4aa13892c7f8a333d80ee695dc6aaa818
[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.57 2003/07/22 03:14:30 gerald 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 <epan/filesystem.h>
32
33 #include "globals.h"
34 #include "gtkglobals.h"
35 #include <epan/resolv.h>
36 #include "keys.h"
37 #include "filter_prefs.h"
38 #include "ui_util.h"
39 #include "simple_dialog.h"
40 #include "menu.h"
41 #include "file_dlg.h"
42 #include "dlg_utils.h"
43 #include "main.h"
44 #include "compat_macros.h"
45 #include "prefs.h"
46
47 static void file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs);
48 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
49 static void select_file_type_cb(GtkWidget *w, gpointer data);
50 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
51 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
52
53 #define E_FILE_M_RESOLVE_KEY      "file_dlg_mac_resolve_key"
54 #define E_FILE_N_RESOLVE_KEY      "file_dlg_network_resolve_key"
55 #define E_FILE_T_RESOLVE_KEY      "file_dlg_transport_resolve_key"
56
57 /*
58  * Keep a static pointer to the current "Open Capture File" window, if
59  * any, so that if somebody tries to do "File:Open" while there's already
60  * an "Open Capture File" window up, we just pop up the existing one,
61  * rather than creating a new one.
62  */
63 static GtkWidget *file_open_w;
64
65 /* Open a file */
66 void
67 file_open_cmd_cb(GtkWidget *w, gpointer data _U_)
68 {
69   GtkWidget     *main_vb, *filter_hbox, *filter_bt, *filter_te,
70                 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
71 #if GTK_MAJOR_VERSION < 2
72   GtkAccelGroup *accel_group;
73 #endif
74   /* No Apply button, and "OK" just sets our text widget, it doesn't
75      activate it (i.e., it doesn't cause us to try to open the file). */
76   static construct_args_t args = {
77         "Ethereal: Read Filter",
78         FALSE,
79         FALSE
80   };
81
82   if (file_open_w != NULL) {
83     /* There's already an "Open Capture File" dialog box; reactivate it. */
84     reactivate_window(file_open_w);
85     return;
86   }
87
88   file_open_w = gtk_file_selection_new ("Ethereal: Open Capture File");
89   SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
90
91 #if GTK_MAJOR_VERSION < 2
92   /* Accelerator group for the accelerators (or, as they're called in
93      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
94      Ctrl+<key> is an accelerator). */
95   accel_group = gtk_accel_group_new();
96   gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
97 #endif
98
99   /* If we've opened a file, start out by showing the files in the directory
100      in which that file resided. */
101   if (last_open_dir)
102     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w), last_open_dir);
103
104   /* Container for each row of widgets */
105   main_vb = gtk_vbox_new(FALSE, 3);
106   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
107   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_open_w)->action_area),
108     main_vb, FALSE, FALSE, 0);
109   gtk_widget_show(main_vb);
110
111   filter_hbox = gtk_hbox_new(FALSE, 1);
112   gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
113   gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
114   gtk_widget_show(filter_hbox);
115
116   filter_bt = gtk_button_new_with_label("Filter:");
117   SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
118   SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
119   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
120   gtk_widget_show(filter_bt);
121
122   filter_te = gtk_entry_new();
123   OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
124   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
125   gtk_widget_show(filter_te);
126
127   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
128                   E_RFILTER_TE_KEY, filter_te);
129
130 #if GTK_MAJOR_VERSION < 2
131   m_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
132                   "Enable _MAC name resolution", accel_group);
133 #else
134   m_resolv_cb = gtk_check_button_new_with_mnemonic(
135                   "Enable _MAC name resolution");
136 #endif
137   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(m_resolv_cb),
138         g_resolv_flags & RESOLV_MAC);
139   gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
140   gtk_widget_show(m_resolv_cb);
141   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
142                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
143
144 #if GTK_MAJOR_VERSION < 2
145   n_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
146                   "Enable _network name resolution", accel_group);
147 #else
148   n_resolv_cb = gtk_check_button_new_with_mnemonic(
149                   "Enable _network name resolution");
150 #endif
151   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(n_resolv_cb),
152         g_resolv_flags & RESOLV_NETWORK);
153   gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
154   gtk_widget_show(n_resolv_cb);
155   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
156                   E_FILE_N_RESOLVE_KEY, n_resolv_cb);
157
158 #if GTK_MAJOR_VERSION < 2
159   t_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
160                   "Enable _transport name resolution", accel_group);
161 #else
162   t_resolv_cb = gtk_check_button_new_with_mnemonic(
163                   "Enable _transport name resolution");
164 #endif
165   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(t_resolv_cb),
166         g_resolv_flags & RESOLV_TRANSPORT);
167   gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
168   gtk_widget_show(t_resolv_cb);
169   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
170                   E_FILE_T_RESOLVE_KEY, t_resolv_cb);
171
172   /* Connect the ok_button to file_open_ok_cb function and pass along a
173      pointer to the file selection box widget */
174   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
175                  file_open_ok_cb, file_open_w);
176
177   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
178                   E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
179
180   /* Connect the cancel_button to destroy the widget */
181   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_open_w)->cancel_button,
182                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
183                         file_open_w);
184
185   /* Catch the "key_press_event" signal in the window, so that we can catch
186      the ESC key being pressed and act as if the "Cancel" button had
187      been selected. */
188   dlg_set_cancel(file_open_w, GTK_FILE_SELECTION(file_open_w)->cancel_button);
189
190   gtk_widget_show(file_open_w);
191 }
192
193 static void
194 file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
195   gchar     *cf_name, *rfilter, *s;
196   GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
197   dfilter_t *rfcode = NULL;
198   int        err;
199
200   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
201   filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
202   rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
203   if (!dfilter_compile(rfilter, &rfcode)) {
204     g_free(cf_name);
205     simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
206     return;
207   }
208
209   /* Perhaps the user specified a directory instead of a file.
210      Check whether they did. */
211   if (test_for_directory(cf_name) == EISDIR) {
212         /* It's a directory - set the file selection box to display that
213            directory, don't try to open the directory as a capture file. */
214         set_last_open_dir(cf_name);
215         g_free(cf_name);
216         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
217         return;
218   }
219
220   /* Try to open the capture file. */
221   if ((err = open_cap_file(cf_name, FALSE, &cfile)) != 0) {
222     /* We couldn't open it; don't dismiss the open dialog box,
223        just leave it around so that the user can, after they
224        dismiss the alert box popped up for the open error,
225        try again. */
226     if (rfcode != NULL)
227       dfilter_free(rfcode);
228     g_free(cf_name);
229     return;
230   }
231
232   /* Attach the new read filter to "cf" ("open_cap_file()" succeeded, so
233      it closed the previous capture file, and thus destroyed any
234      previous read filter attached to "cf"). */
235   cfile.rfcode = rfcode;
236
237   /* Set the global resolving variable */
238   g_resolv_flags = prefs.name_resolve & RESOLV_CONCURRENT;
239   m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
240   g_resolv_flags |= GTK_TOGGLE_BUTTON (m_resolv_cb)->active ? RESOLV_MAC : RESOLV_NONE;
241   n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
242   g_resolv_flags |= GTK_TOGGLE_BUTTON (n_resolv_cb)->active ? RESOLV_NETWORK : RESOLV_NONE;
243   t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
244   g_resolv_flags |= GTK_TOGGLE_BUTTON (t_resolv_cb)->active ? RESOLV_TRANSPORT : RESOLV_NONE;
245
246   /* We've crossed the Rubicon; get rid of the file selection box. */
247   gtk_widget_hide(GTK_WIDGET (fs));
248   gtk_widget_destroy(GTK_WIDGET (fs));
249
250   switch (read_cap_file(&cfile, &err)) {
251
252   case READ_SUCCESS:
253   case READ_ERROR:
254     /* Just because we got an error, that doesn't mean we were unable
255        to read any of the file; we handle what we could get from the
256        file. */
257     break;
258
259   case READ_ABORTED:
260     /* The user bailed out of re-reading the capture file; the
261        capture file has been closed - just free the capture file name
262        string and return (without changing the last containing
263        directory). */
264     g_free(cf_name);
265     return;
266   }
267
268   /* Save the name of the containing directory specified in the path name,
269      if any; we can write over cf_name, which is a good thing, given that
270      "get_dirname()" does write over its argument. */
271   s = get_dirname(cf_name);
272   set_last_open_dir(s);
273   gtk_widget_grab_focus(packet_list);
274
275   g_free(cf_name);
276 }
277
278 static void
279 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
280 {
281   /* Note that we no longer have a "Open Capture File" dialog box. */
282   file_open_w = NULL;
283 }
284
285 /* Close a file */
286 void
287 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
288   close_cap_file(&cfile);
289 }
290
291 void
292 file_save_cmd_cb(GtkWidget *w, gpointer data) {
293   /* If the file's already been saved, do nothing.  */
294   if (cfile.user_saved)
295     return;
296
297   /* Do a "Save As". */
298   file_save_as_cmd_cb(w, data);
299 }
300
301 /* XXX - can we make these not be static? */
302 static gboolean filtered;
303 static gboolean marked;
304 static int filetype;
305 static GtkWidget *filter_cb;
306 static GtkWidget *mark_cb;
307 static GtkWidget *ft_om;
308
309 static gboolean
310 can_save_with_wiretap(int ft)
311 {
312   /* To save a file with Wiretap, Wiretap has to handle that format,
313      and its code to handle that format must be able to write a file
314      with this file's encapsulation type. */
315   return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
316 }
317
318 /* Generate a list of the file types we can save this file as.
319
320    "filetype" is the type it has now.
321
322    "encap" is the encapsulation for its packets (which could be
323    "unknown" or "per-packet").
324
325    "filtered" is TRUE if we're to save only the packets that passed
326    the display filter (in which case we have to save it using Wiretap)
327    and FALSE if we're to save the entire file (in which case, if we're
328    saving it in the type it has already, we can just copy it).
329
330    "marked" is TRUE if we have to save only the marked packets,
331    the same remark as "filtered" applies.
332 */
333 static void
334 set_file_type_list(GtkWidget *option_menu)
335 {
336   GtkWidget *ft_menu, *ft_menu_item;
337   int ft;
338   guint index;
339   guint item_to_select;
340
341   /* Default to the first supported file type, if the file's current
342      type isn't supported. */
343   item_to_select = 0;
344
345   ft_menu = gtk_menu_new();
346
347   /* Check all file types. */
348   index = 0;
349   for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
350     if (filtered || marked || ft != cfile.cd_t) {
351       /* Filtered, marked or a different file type.  We have to use Wiretap. */
352       if (!can_save_with_wiretap(ft))
353         continue;       /* We can't. */
354     }
355
356     /* OK, we can write it out in this type. */
357     ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
358     if (ft == filetype) {
359       /* Default to the same format as the file, if it's supported. */
360       item_to_select = index;
361     }
362     SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
363                    GINT_TO_POINTER(ft));
364     gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
365     gtk_widget_show(ft_menu_item);
366     index++;
367   }
368
369   gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
370   gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
371 }
372
373 static void
374 select_file_type_cb(GtkWidget *w _U_, gpointer data)
375 {
376   int new_filetype = GPOINTER_TO_INT(data);
377
378   if (filetype != new_filetype) {
379     /* We can select only the filtered or marked packets to be saved if we can
380        use Wiretap to save the file. */
381     gtk_widget_set_sensitive(filter_cb, can_save_with_wiretap(new_filetype));
382     filetype = new_filetype;
383     file_set_save_marked_sensitive();
384   }
385 }
386
387 static void
388 toggle_filtered_cb(GtkWidget *widget, gpointer data _U_)
389 {
390   gboolean new_filtered;
391
392   new_filtered = GTK_TOGGLE_BUTTON (widget)->active;
393
394   if (filtered != new_filtered) {
395     /* They changed the state of the "filtered" button. */
396     filtered = new_filtered;
397     set_file_type_list(ft_om);
398   }
399 }
400
401 static void
402 toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
403 {
404   gboolean new_marked;
405
406   new_marked = GTK_TOGGLE_BUTTON (widget)->active;
407
408   if (marked != new_marked) {
409     /* They changed the state of the "marked" button. */
410     marked = new_marked;
411     set_file_type_list(ft_om);
412   }
413 }
414
415 /*
416  * Keep a static pointer to the current "Save Capture File As" window, if
417  * any, so that if somebody tries to do "File:Save" or "File:Save As"
418  * while there's already a "Save Capture File As" window up, we just pop
419  * up the existing one, rather than creating a new one.
420  */
421 static GtkWidget *file_save_as_w;
422
423 void
424 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
425 {
426   GtkWidget *ok_bt, *main_vb, *ft_hb, *ft_lb;
427
428   if (file_save_as_w != NULL) {
429     /* There's already an "Save Capture File As" dialog box; reactivate it. */
430     reactivate_window(file_save_as_w);
431     return;
432   }
433
434   /* Default to saving all packets, in the file's current format. */
435   filtered = FALSE;
436   marked   = FALSE;
437   filetype = cfile.cd_t;
438
439   file_save_as_w = gtk_file_selection_new ("Ethereal: Save Capture File As");
440   SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
441
442   /* If we've opened a file, start out by showing the files in the directory
443      in which that file resided. */
444   if (last_open_dir)
445     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w), last_open_dir);
446
447   /* Connect the ok_button to file_save_as_ok_cb function and pass along a
448      pointer to the file selection box widget */
449   ok_bt = GTK_FILE_SELECTION (file_save_as_w)->ok_button;
450   SIGNAL_CONNECT(ok_bt, "clicked", file_save_as_ok_cb, file_save_as_w);
451
452   /* Container for each row of widgets */
453   main_vb = gtk_vbox_new(FALSE, 3);
454   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
455   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_save_as_w)->action_area),
456     main_vb, FALSE, FALSE, 0);
457   gtk_widget_show(main_vb);
458
459   /*
460    * XXX - should this be sensitive only if the current display filter
461    * has rejected some packets, so that not all packets are currently
462    * being displayed, and if it has accepted some packets, so that some
463    * packets are currently being displayed?
464    *
465    * I'd say "no", as that complicates the UI code, and as one could,
466    * I guess, argue that the user may want to "save all the displayed
467    * packets" even if there aren't any, i.e. save an empty file.
468    */
469   filter_cb = gtk_check_button_new_with_label("Save only packets currently being displayed");
470   gtk_container_add(GTK_CONTAINER(main_vb), filter_cb);
471   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_cb), FALSE);
472   SIGNAL_CONNECT(filter_cb, "toggled", toggle_filtered_cb, NULL);
473   gtk_widget_set_sensitive(filter_cb, can_save_with_wiretap(filetype));
474   gtk_widget_show(filter_cb);
475
476   /*
477    * The argument above could, I guess, be applied to the marked packets,
478    * except that you can't easily tell whether there are any marked
479    * packets, so I could imagine users doing "Save only marked packets"
480    * when there aren't any marked packets, not knowing that they'd
481    * failed to mark them, so I'm more inclined to have the "Save only
482    * marked packets" toggle button enabled only if there are marked
483    * packets to save.
484    */
485   mark_cb = gtk_check_button_new_with_label("Save only marked packets");
486   gtk_container_add(GTK_CONTAINER(main_vb), mark_cb);
487   marked = FALSE;
488   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(mark_cb), FALSE);
489   SIGNAL_CONNECT(mark_cb, "toggled", toggle_marked_cb, NULL);
490   gtk_widget_show(mark_cb);
491
492   /* File type row */
493   ft_hb = gtk_hbox_new(FALSE, 3);
494   gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
495   gtk_widget_show(ft_hb);
496
497   ft_lb = gtk_label_new("File type:");
498   gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
499   gtk_widget_show(ft_lb);
500
501   ft_om = gtk_option_menu_new();
502
503   /* Generate the list of file types we can save. */
504   set_file_type_list(ft_om);
505   gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
506   gtk_widget_show(ft_om);
507
508   /*
509    * Set the sensitivity of the "Save only marked packets" toggle
510    * button
511    *
512    * This has to be done after we create the file type menu option,
513    * as the routine that sets it also sets that menu.
514    */
515   file_set_save_marked_sensitive();
516
517   /* Connect the cancel_button to destroy the widget */
518   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_save_as_w)->cancel_button,
519                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
520                         file_save_as_w);
521
522   /* Catch the "key_press_event" signal in the window, so that we can catch
523      the ESC key being pressed and act as if the "Cancel" button had
524      been selected. */
525   dlg_set_cancel(file_save_as_w, GTK_FILE_SELECTION(file_save_as_w)->cancel_button);
526
527   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w), "");
528
529   gtk_widget_show(file_save_as_w);
530 }
531
532 /*
533  * Set the "Save only marked packets" toggle button as appropriate for
534  * the current output file type and count of marked packets.
535  *
536  * Called when the "Save As..." dialog box is created and when either
537  * the file type or the marked count changes.
538  */
539 void
540 file_set_save_marked_sensitive(void)
541 {
542   if (file_save_as_w == NULL) {
543     /* We don't currently have a "Save As..." dialog box up. */
544     return;
545   }
546
547   /* We can request that only the marked packets be saved only if we
548      can use Wiretap to save the file and if there *are* marked packets. */
549   if (can_save_with_wiretap(filetype) && cfile.marked_count != 0)
550     gtk_widget_set_sensitive(mark_cb, TRUE);
551   else {
552     /* Force the "Save only marked packets" toggle to "false", turn
553        off the flag it controls, and update the list of types we can
554        save the file as. */
555     marked = FALSE;
556     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(mark_cb), FALSE);
557     set_file_type_list(ft_om);
558     gtk_widget_set_sensitive(mark_cb, FALSE);
559   }
560 }
561
562 static void
563 file_save_as_ok_cb(GtkWidget *w _U_, GtkFileSelection *fs) {
564   gchar *cf_name;
565   gchar *dirname;
566
567   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
568
569   /* Perhaps the user specified a directory instead of a file.
570      Check whether they did. */
571   if (test_for_directory(cf_name) == EISDIR) {
572         /* It's a directory - set the file selection box to display that
573            directory, and leave the selection box displayed. */
574         set_last_open_dir(cf_name);
575         g_free(cf_name);
576         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
577         return;
578   }
579
580   /* Write out the packets (all, or only the ones that are currently
581      displayed or marked) to the file with the specified name. */
582
583   if (! save_cap_file(cf_name, &cfile, filtered, marked, filetype)) {
584     /* The write failed; don't dismiss the open dialog box,
585        just leave it around so that the user can, after they
586        dismiss the alert box popped up for the error, try again. */
587     g_free(cf_name);
588     return;
589   }
590
591   /* The write succeeded; get rid of the file selection box. */
592   gtk_widget_hide(GTK_WIDGET (fs));
593   gtk_widget_destroy(GTK_WIDGET (fs));
594
595   /* Save the directory name for future file dialogs. */
596   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
597   set_last_open_dir(dirname);
598   g_free(cf_name);
599 }
600
601 static void
602 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
603 {
604   /* Note that we no longer have a "Save Capture File As" dialog box. */
605   file_save_as_w = NULL;
606 }
607
608 /* Reload a file using the current read and display filters */
609 void
610 file_reload_cmd_cb(GtkWidget *w, gpointer data _U_) {
611   GtkWidget *filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY);
612   gchar *filename;
613   gboolean is_tempfile;
614   int err;
615
616   if (cfile.dfilter)
617     g_free(cfile.dfilter);
618   cfile.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
619
620   /* If the file could be opened, "open_cap_file()" calls "close_cap_file()"
621      to get rid of state for the old capture file before filling in state
622      for the new capture file.  "close_cap_file()" will remove the file if
623      it's a temporary file; we don't want that to happen (for one thing,
624      it'd prevent subsequent reopens from working).  Remember whether it's
625      a temporary file, mark it as not being a temporary file, and then
626      reopen it as the type of file it was.
627
628      Also, "close_cap_file()" will free "cfile.filename", so we must make
629      a copy of it first. */
630   filename = g_strdup(cfile.filename);
631   is_tempfile = cfile.is_tempfile;
632   cfile.is_tempfile = FALSE;
633   if (open_cap_file(filename, is_tempfile, &cfile) == 0) {
634     switch (read_cap_file(&cfile, &err)) {
635
636     case READ_SUCCESS:
637     case READ_ERROR:
638       /* Just because we got an error, that doesn't mean we were unable
639          to read any of the file; we handle what we could get from the
640          file. */
641       break;
642
643     case READ_ABORTED:
644       /* The user bailed out of re-reading the capture file; the
645          capture file has been closed - just free the capture file name
646          string and return (without changing the last containing
647          directory). */
648       g_free(filename);
649       return;
650     }
651   } else {
652     /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
653        Instead, the file was left open, so we should restore "cfile.is_tempfile"
654        ourselves.
655
656        XXX - change the menu?  Presumably "open_cap_file()" will do that;
657        make sure it does! */
658     cfile.is_tempfile = is_tempfile;
659   }
660   /* "open_cap_file()" made a copy of the file name we handed it, so
661      we should free up our copy. */
662   g_free(filename);
663 }