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