added compression support for capture file output. The Save/As dialog now has a check...
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id$
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 #include <time.h>
34
35 #ifdef HAVE_IO_H
36 #include <io.h>
37 #endif
38
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <signal.h>
45
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49
50 #ifdef NEED_STRERROR_H
51 #include "strerror.h"
52 #endif
53
54 #include <epan/epan.h>
55 #include <epan/filesystem.h>
56
57 #include "color.h"
58 #include "color_filters.h"
59 #include <epan/column.h>
60 #include <epan/packet.h>
61 #include "packet-range.h"
62 #include "print.h"
63 #include "file.h"
64 #include "fileset.h"
65 #include "util.h"
66 #include "merge.h"
67 #include "alert_box.h"
68 #include "simple_dialog.h"
69 #include "progress_dlg.h"
70 #include "ui_util.h"
71 #include <epan/prefs.h>
72 #include <epan/dfilter/dfilter.h>
73 #include <epan/conversation.h>
74 #include <epan/epan_dissect.h>
75 #include <epan/tap.h>
76 #include "stat_menu.h"
77 #include "tap_dfilter_dlg.h"
78 #include <epan/dissectors/packet-data.h>
79 #include <epan/timestamp.h>
80
81
82 /* Win32 needs the O_BINARY flag for open() */
83 #ifndef O_BINARY
84 #define O_BINARY        0
85 #endif
86
87 #ifdef HAVE_LIBPCAP
88 gboolean auto_scroll_live;
89 #endif
90
91 static nstime_t first_ts;
92 static nstime_t prev_ts;
93 static guint32 cum_bytes = 0;
94
95 static void cf_reset_state(capture_file *cf);
96
97 static void read_packet(capture_file *cf, long offset);
98
99 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
100         gboolean refilter, gboolean redissect);
101
102 static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
103         void *criterion);
104 static void match_subtree_text(proto_node *node, gpointer data);
105 static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
106         void *criterion);
107 static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
108         void *criterion);
109 static gboolean match_ascii(capture_file *cf, frame_data *fdata,
110         void *criterion);
111 static gboolean match_unicode(capture_file *cf, frame_data *fdata,
112         void *criterion);
113 static gboolean match_binary(capture_file *cf, frame_data *fdata,
114         void *criterion);
115 static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
116         void *criterion);
117 static gboolean find_packet(capture_file *cf,
118         gboolean (*match_function)(capture_file *, frame_data *, void *),
119         void *criterion);
120
121 static void cf_open_failure_alert_box(const char *filename, int err,
122                                       gchar *err_info, gboolean for_writing,
123                                       int file_type);
124 static const char *file_rename_error_message(int err);
125 static void cf_write_failure_alert_box(const char *filename, int err);
126 static void cf_close_failure_alert_box(const char *filename, int err);
127 static   gboolean copy_binary_file(const char *from_filename, const char *to_filename);
128
129 /* Update the progress bar this many times when reading a file. */
130 #define N_PROGBAR_UPDATES       100
131
132 /* Number of "frame_data" structures per memory chunk.
133    XXX - is this the right number? */
134 #define FRAME_DATA_CHUNK_SIZE   1024
135
136
137 /* one callback for now, we could have a list later */
138 static cf_callback_t cf_cb = NULL;
139 static gpointer cf_cb_user_data = NULL;
140
141 void
142 cf_callback_invoke(int event, gpointer data)
143 {
144     g_assert(cf_cb != NULL);
145     cf_cb(event, data, cf_cb_user_data);
146 }
147
148
149 void
150 cf_callback_add(cf_callback_t func, gpointer user_data)
151 {
152     /* More than one callback listener is currently not implemented,
153        but should be easy to do. */
154     g_assert(cf_cb == NULL);
155     cf_cb = func;
156     cf_cb_user_data = user_data;
157 }
158
159 void
160 cf_callback_remove(cf_callback_t func _U_)
161 {
162     g_assert(cf_cb != NULL);
163     cf_cb = NULL;
164     cf_cb_user_data = NULL;
165 }
166
167 void
168 cf_timestamp_auto_precision(capture_file *cf)
169 {
170         int prec = timestamp_get_precision();
171
172
173         /* don't try to get the file's precision if none is opened */
174         if(cf->state == FILE_CLOSED) {
175                 return;
176         }
177
178         /* if we are in auto mode, set precision of current file */
179         if(prec == TS_PREC_AUTO ||
180           prec == TS_PREC_AUTO_SEC ||
181           prec == TS_PREC_AUTO_DSEC ||
182           prec == TS_PREC_AUTO_CSEC ||
183           prec == TS_PREC_AUTO_MSEC ||
184           prec == TS_PREC_AUTO_USEC ||
185           prec == TS_PREC_AUTO_NSEC)
186         {
187                 switch(wtap_file_tsprecision(cf->wth)) {
188                 case(WTAP_FILE_TSPREC_SEC):
189                         timestamp_set_precision(TS_PREC_AUTO_SEC);
190                         break;
191                 case(WTAP_FILE_TSPREC_DSEC):
192                         timestamp_set_precision(TS_PREC_AUTO_DSEC);
193                         break;
194                 case(WTAP_FILE_TSPREC_CSEC):
195                         timestamp_set_precision(TS_PREC_AUTO_CSEC);
196                         break;
197                 case(WTAP_FILE_TSPREC_MSEC):
198                         timestamp_set_precision(TS_PREC_AUTO_MSEC);
199                         break;
200                 case(WTAP_FILE_TSPREC_USEC):
201                         timestamp_set_precision(TS_PREC_AUTO_USEC);
202                         break;
203                 case(WTAP_FILE_TSPREC_NSEC):
204                         timestamp_set_precision(TS_PREC_AUTO_NSEC);
205                         break;
206                 default:
207                         g_assert_not_reached();
208                 }
209         }
210 }
211
212
213 cf_status_t
214 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
215 {
216   wtap       *wth;
217   gchar       *err_info;
218
219   wth = wtap_open_offline(fname, err, &err_info, TRUE);
220   if (wth == NULL)
221     goto fail;
222
223   /* The open succeeded.  Close whatever capture file we had open,
224      and fill in the information for this file. */
225   cf_reset_state(cf);
226
227   /* Initialize all data structures used for dissection. */
228   init_dissection();
229
230   /* We're about to start reading the file. */
231   cf->state = FILE_READ_IN_PROGRESS;
232
233   cf->wth = wth;
234   cf->f_datalen = 0;
235
236   /* Set the file name because we need it to set the follow stream filter.
237      XXX - is that still true?  We need it for other reasons, though,
238      in any case. */
239   cf->filename = g_strdup(fname);
240
241   /* Indicate whether it's a permanent or temporary file. */
242   cf->is_tempfile = is_tempfile;
243
244   /* If it's a temporary capture buffer file, mark it as not saved. */
245   cf->user_saved = !is_tempfile;
246
247   cf->cd_t        = wtap_file_type(cf->wth);
248   cf->count     = 0;
249   cf->displayed_count = 0;
250   cf->marked_count = 0;
251   cf->drops_known = FALSE;
252   cf->drops     = 0;
253   cf->snap      = wtap_snapshot_length(cf->wth);
254   if (cf->snap == 0) {
255     /* Snapshot length not known. */
256     cf->has_snap = FALSE;
257     cf->snap = WTAP_MAX_PACKET_SIZE;
258   } else
259     cf->has_snap = TRUE;
260   nstime_set_zero(&cf->elapsed_time);
261   nstime_set_zero(&first_ts);
262   nstime_set_zero(&prev_ts);
263
264   cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
265         sizeof(frame_data),
266         FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
267         G_ALLOC_AND_FREE);
268   g_assert(cf->plist_chunk);
269
270   /* change the time formats now, as we might have a new precision */
271   cf_change_time_formats(cf);
272
273   fileset_file_opened(fname);
274
275   return CF_OK;
276
277 fail:
278   cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
279   return CF_ERROR;
280 }
281
282
283 /*
284  * Reset the state for the currently closed file, but don't do the
285  * UI callbacks; this is for use in "cf_open()", where we don't
286  * want the UI to go from "file open" to "file closed" back to
287  * "file open", we want it to go from "old file open" to "new file
288  * open and being read".
289  */
290 static void
291 cf_reset_state(capture_file *cf)
292 {
293   /* Die if we're in the middle of reading a file. */
294   g_assert(cf->state != FILE_READ_IN_PROGRESS);
295
296   if (cf->wth) {
297     wtap_close(cf->wth);
298     cf->wth = NULL;
299   }
300   /* We have no file open... */
301   if (cf->filename != NULL) {
302     /* If it's a temporary file, remove it. */
303     if (cf->is_tempfile)
304       unlink(cf->filename);
305     g_free(cf->filename);
306     cf->filename = NULL;
307   }
308   /* ...which means we have nothing to save. */
309   cf->user_saved = FALSE;
310
311   if (cf->plist_chunk != NULL) {
312     g_mem_chunk_destroy(cf->plist_chunk);
313     cf->plist_chunk = NULL;
314   }
315   if (cf->rfcode != NULL) {
316     dfilter_free(cf->rfcode);
317     cf->rfcode = NULL;
318   }
319   cf->plist = NULL;
320   cf->plist_end = NULL;
321   cf_unselect_packet(cf);       /* nothing to select */
322   cf->first_displayed = NULL;
323   cf->last_displayed = NULL;
324
325   /* No frame selected, no field in that frame selected. */
326   cf->current_frame = NULL;
327   cf->finfo_selected = NULL;
328
329   /* Clear the packet list. */
330   packet_list_freeze();
331   packet_list_clear();
332   packet_list_thaw();
333
334   cf->f_datalen = 0;
335   cf->count = 0;
336   nstime_set_zero(&cf->elapsed_time);
337
338   reset_tap_listeners();
339
340   /* We have no file open. */
341   cf->state = FILE_CLOSED;
342
343   fileset_file_closed();
344 }
345
346 /* Reset everything to a pristine state */
347 void
348 cf_close(capture_file *cf)
349 {
350   cf_reset_state(cf);
351
352   cleanup_dissection();
353
354   cf_callback_invoke(cf_cb_file_closed, cf);
355 }
356
357 cf_read_status_t
358 cf_read(capture_file *cf)
359 {
360   int         err;
361   gchar       *err_info;
362   const gchar *name_ptr;
363   const char  *errmsg;
364   char         errmsg_errno[1024+1];
365   gchar        err_str[2048+1];
366   long         data_offset;
367   progdlg_t   *progbar = NULL;
368   gboolean     stop_flag;
369   gint64       size, file_pos;
370   float        prog_val;
371   GTimeVal     start_time;
372   gchar        status_str[100];
373   gint64       progbar_nextstep;
374   gint64       progbar_quantum;
375
376   cum_bytes=0;
377
378   reset_tap_listeners();
379   tap_dfilter_dlg_update();
380
381   cf_callback_invoke(cf_cb_file_read_start, cf);
382
383   name_ptr = get_basename(cf->filename);
384
385   /* Find the size of the file. */
386   size = wtap_file_size(cf->wth, NULL);
387
388   /* Update the progress bar when it gets to this value. */
389   progbar_nextstep = 0;
390   /* When we reach the value that triggers a progress bar update,
391      bump that value by this amount. */
392   if (size >= 0)     
393     progbar_quantum = size/N_PROGBAR_UPDATES;
394   else
395     progbar_quantum = 0;
396
397   packet_list_freeze();
398
399   stop_flag = FALSE;
400   g_get_current_time(&start_time);
401
402   while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
403     if (size >= 0) {
404       /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
405          when we update it, we have to run the GTK+ main loop to get it
406          to repaint what's pending, and doing so may involve an "ioctl()"
407          to see if there's any pending input from an X server, and doing
408          that for every packet can be costly, especially on a big file. */
409       if (data_offset >= progbar_nextstep) {
410           file_pos = wtap_read_so_far(cf->wth, NULL);
411           prog_val = (gfloat) file_pos / (gfloat) size;
412           if (prog_val > 1.0) {
413             /* The file probably grew while we were reading it.
414                Update file size, and try again. */
415             size = wtap_file_size(cf->wth, NULL);
416             if (size >= 0)
417               prog_val = (gfloat) file_pos / (gfloat) size;
418             /* If it's still > 1, either "wtap_file_size()" failed (in which
419                case there's not much we can do about it), or the file
420                *shrank* (in which case there's not much we can do about
421                it); just clip the progress value at 1.0. */
422             if (prog_val > 1.0)
423               prog_val = 1.0;
424           }
425           if (progbar == NULL) {
426             /* Create the progress bar if necessary */
427             progbar = delayed_create_progress_dlg("Loading", name_ptr,
428               &stop_flag, &start_time, prog_val);
429           }
430           if (progbar != NULL) {
431             g_snprintf(status_str, sizeof(status_str),
432                        "%" PRId64 "KB of %" PRId64 "KB",
433                        file_pos / 1024, size / 1024);
434             update_progress_dlg(progbar, prog_val, status_str);
435           }
436          progbar_nextstep += progbar_quantum;
437       }
438     }
439
440     if (stop_flag) {
441       /* Well, the user decided to abort the read.  Destroy the progress
442          bar, close the capture file, and return CF_READ_ABORTED so our caller
443          can do whatever is appropriate when that happens. */
444       destroy_progress_dlg(progbar);
445       cf->state = FILE_READ_ABORTED;    /* so that we're allowed to close it */
446       packet_list_thaw();               /* undo our freeze */
447       cf_close(cf);
448       return CF_READ_ABORTED;
449     }
450     read_packet(cf, data_offset);
451   }
452
453   /* We're done reading the file; destroy the progress bar if it was created. */
454   if (progbar != NULL)
455     destroy_progress_dlg(progbar);
456
457   /* We're done reading sequentially through the file. */
458   cf->state = FILE_READ_DONE;
459
460   /* Close the sequential I/O side, to free up memory it requires. */
461   wtap_sequential_close(cf->wth);
462
463   /* Allow the protocol dissectors to free up memory that they
464    * don't need after the sequential run-through of the packets. */
465   postseq_cleanup_all_protocols();
466
467   /* Set the file encapsulation type now; we don't know what it is until
468      we've looked at all the packets, as we don't know until then whether
469      there's more than one type (and thus whether it's
470      WTAP_ENCAP_PER_PACKET). */
471   cf->lnk_t = wtap_file_encap(cf->wth);
472
473   cf->current_frame = cf->first_displayed;
474   packet_list_thaw();
475
476   cf_callback_invoke(cf_cb_file_read_finished, cf);
477
478   /* If we have any displayed packets to select, select the first of those
479      packets by making the first row the selected row. */
480   if (cf->first_displayed != NULL)
481     packet_list_select_row(0);
482
483   if (err != 0) {
484     /* Put up a message box noting that the read failed somewhere along
485        the line.  Don't throw out the stuff we managed to read, though,
486        if any. */
487     switch (err) {
488
489     case WTAP_ERR_UNSUPPORTED_ENCAP:
490       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
491                "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
492                err_info);
493       g_free(err_info);
494       errmsg = errmsg_errno;
495       break;
496
497     case WTAP_ERR_CANT_READ:
498       errmsg = "An attempt to read from the capture file failed for"
499                " some unknown reason.";
500       break;
501
502     case WTAP_ERR_SHORT_READ:
503       errmsg = "The capture file appears to have been cut short"
504                " in the middle of a packet.";
505       break;
506
507     case WTAP_ERR_BAD_RECORD:
508       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
509                "The capture file appears to be damaged or corrupt.\n(%s)",
510                err_info);
511       g_free(err_info);
512       errmsg = errmsg_errno;
513       break;
514
515     default:
516       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
517                "An error occurred while reading the"
518                " capture file: %s.", wtap_strerror(err));
519       errmsg = errmsg_errno;
520       break;
521     }
522     g_snprintf(err_str, sizeof err_str, errmsg);
523     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
524     return CF_READ_ERROR;
525   } else
526     return CF_READ_OK;
527 }
528
529 #ifdef HAVE_LIBPCAP
530 cf_status_t
531 cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
532 {
533   cf_status_t cf_status;
534
535   cf_status = cf_open(cf, fname, is_tempfile, err);
536   return cf_status;
537 }
538
539 cf_read_status_t
540 cf_continue_tail(capture_file *cf, int to_read, int *err)
541 {
542   long data_offset = 0;
543   gchar *err_info;
544
545   *err = 0;
546
547   packet_list_freeze();
548
549   while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
550     if (cf->state == FILE_READ_ABORTED) {
551       /* Well, the user decided to exit Ethereal.  Break out of the
552          loop, and let the code below (which is called even if there
553          aren't any packets left to read) exit. */
554       break;
555     }
556     read_packet(cf, data_offset);
557     to_read--;
558   }
559
560   packet_list_thaw();
561
562   /* XXX - this cheats and looks inside the packet list to find the final
563      row number. */
564   if (auto_scroll_live && cf->plist_end != NULL)
565     packet_list_moveto_end();
566
567   if (cf->state == FILE_READ_ABORTED) {
568     /* Well, the user decided to exit Ethereal.  Return CF_READ_ABORTED
569        so that our caller can kill off the capture child process;
570        this will cause an EOF on the pipe from the child, so
571        "cf_finish_tail()" will be called, and it will clean up
572        and exit. */
573     return CF_READ_ABORTED;
574   } else if (*err != 0) {
575     /* We got an error reading the capture file.
576        XXX - pop up a dialog box? */
577     return CF_READ_ERROR;
578   } else
579     return CF_READ_OK;
580 }
581
582 cf_read_status_t
583 cf_finish_tail(capture_file *cf, int *err)
584 {
585   gchar *err_info;
586   long data_offset;
587
588   if(cf->wth == NULL) {
589     cf_close(cf);
590     return CF_READ_ERROR;
591   }
592
593   packet_list_freeze();
594
595   while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
596     if (cf->state == FILE_READ_ABORTED) {
597       /* Well, the user decided to abort the read.  Break out of the
598          loop, and let the code below (which is called even if there
599          aren't any packets left to read) exit. */
600       break;
601     }
602     read_packet(cf, data_offset);
603   }
604
605   if (cf->state == FILE_READ_ABORTED) {
606     /* Well, the user decided to abort the read.  We're only called
607        when the child capture process closes the pipe to us (meaning
608        it's probably exited), so we can just close the capture
609        file; we return CF_READ_ABORTED so our caller can do whatever
610        is appropriate when that happens. */
611     cf_close(cf);
612     return CF_READ_ABORTED;
613   }
614
615   packet_list_thaw();
616   if (auto_scroll_live && cf->plist_end != NULL)
617     /* XXX - this cheats and looks inside the packet list to find the final
618        row number. */
619     packet_list_moveto_end();
620
621   /* We're done reading sequentially through the file. */
622   cf->state = FILE_READ_DONE;
623
624   /* We're done reading sequentially through the file; close the
625      sequential I/O side, to free up memory it requires. */
626   wtap_sequential_close(cf->wth);
627
628   /* Allow the protocol dissectors to free up memory that they
629    * don't need after the sequential run-through of the packets. */
630   postseq_cleanup_all_protocols();
631
632   /* Set the file encapsulation type now; we don't know what it is until
633      we've looked at all the packets, as we don't know until then whether
634      there's more than one type (and thus whether it's
635      WTAP_ENCAP_PER_PACKET). */
636   cf->lnk_t = wtap_file_encap(cf->wth);
637
638   if (*err != 0) {
639     /* We got an error reading the capture file.
640        XXX - pop up a dialog box? */
641     return CF_READ_ERROR;
642   } else {
643     return CF_READ_OK;
644   }
645 }
646 #endif /* HAVE_LIBPCAP */
647
648 const gchar *
649 cf_get_display_name(capture_file *cf)
650 {
651   const gchar *displayname;
652
653   /* Return a name to use in displays */
654   if (!cf->is_tempfile) {
655     /* Get the last component of the file name, and use that. */
656     if (cf->filename){
657       displayname = get_basename(cf->filename);
658     } else {
659       displayname="(No file)";
660     }
661   } else {
662     /* The file we read is a temporary file from a live capture;
663        we don't mention its name. */
664     displayname = "(Untitled)";
665   }
666   return displayname;
667 }
668
669 /* XXX - use a macro instead? */
670 int
671 cf_packet_count(capture_file *cf)
672 {
673     return cf->count;
674 }
675
676 /* XXX - use a macro instead? */
677 gboolean
678 cf_is_tempfile(capture_file *cf)
679 {
680     return cf->is_tempfile;
681 }
682
683 void cf_set_tempfile(capture_file *cf, gboolean is_tempfile)
684 {
685     cf->is_tempfile = is_tempfile;
686 }
687
688
689 /* XXX - use a macro instead? */
690 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
691 {
692     cf->drops_known = drops_known;
693 }
694
695 /* XXX - use a macro instead? */
696 void cf_set_drops(capture_file *cf, guint32 drops)
697 {
698     cf->drops = drops;
699 }
700
701 /* XXX - use a macro instead? */
702 gboolean cf_get_drops_known(capture_file *cf)
703 {
704     return cf->drops_known;
705 }
706
707 /* XXX - use a macro instead? */
708 guint32 cf_get_drops(capture_file *cf)
709 {
710     return cf->drops;
711 }
712
713 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
714 {
715     cf->rfcode = rfcode;
716 }
717
718 static int
719 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
720         union wtap_pseudo_header *pseudo_header, const guchar *buf,
721         gboolean refilter)
722 {
723   gint          row;
724   gboolean      create_proto_tree = FALSE;
725   epan_dissect_t *edt;
726
727   /* just add some value here until we know if it is being displayed or not */
728   fdata->cum_bytes  = cum_bytes + fdata->pkt_len;
729
730   /* If we don't have the time stamp of the first packet in the
731      capture, it's because this is the first packet.  Save the time
732      stamp of this packet as the time stamp of the first packet. */
733   if (nstime_is_zero(&first_ts)) {
734     first_ts  = fdata->abs_ts;
735   }
736   /* if this frames is marked as a reference time frame, reset
737      firstsec and firstusec to this frame */
738   if(fdata->flags.ref_time){
739     first_ts = fdata->abs_ts;
740   }
741
742   /* If we don't have the time stamp of the previous displayed packet,
743      it's because this is the first displayed packet.  Save the time
744      stamp of this packet as the time stamp of the previous displayed
745      packet. */
746   if (nstime_is_zero(&prev_ts)) {
747     prev_ts = fdata->abs_ts;
748   }
749
750   /* Get the time elapsed between the first packet and this packet. */
751   nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
752
753   /* If it's greater than the current elapsed time, set the elapsed time
754      to it (we check for "greater than" so as not to be confused by
755      time moving backwards). */
756   if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
757   || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
758     cf->elapsed_time = fdata->rel_ts;
759   }
760
761   /* Get the time elapsed between the previous displayed packet and
762      this packet. */
763   nstime_delta(&fdata->del_ts, &fdata->abs_ts, &prev_ts);
764
765   /* If either
766
767         we have a display filter and are re-applying it;
768
769         we have a list of color filters;
770
771         we have tap listeners;
772
773      allocate a protocol tree root node, so that we'll construct
774      a protocol tree against which a filter expression can be
775      evaluated. */
776   if ((cf->dfcode != NULL && refilter) || color_filters_used()
777         || num_tap_filters != 0)
778           create_proto_tree = TRUE;
779
780   /* Dissect the frame. */
781   edt = epan_dissect_new(create_proto_tree, FALSE);
782
783   if (cf->dfcode != NULL && refilter) {
784       epan_dissect_prime_dfilter(edt, cf->dfcode);
785   }
786   if (color_filters_used()) {
787       color_filters_prime_edt(edt);
788   }
789   tap_queue_init(edt);
790   epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
791   tap_push_tapped_queue(edt);
792
793   /* If we have a display filter, apply it if we're refiltering, otherwise
794      leave the "passed_dfilter" flag alone.
795
796      If we don't have a display filter, set "passed_dfilter" to 1. */
797   if (cf->dfcode != NULL) {
798     if (refilter) {
799       fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
800     }
801   } else
802     fdata->flags.passed_dfilter = 1;
803
804   if( (fdata->flags.passed_dfilter) 
805    || (edt->pi.fd->flags.ref_time) ){
806     /* This frame either passed the display filter list or is marked as
807        a time reference frame.  All time reference frames are displayed
808        even if they dont pass the display filter */
809     /* if this was a TIME REF frame we should reset the cul bytes field */
810     if(edt->pi.fd->flags.ref_time){
811       cum_bytes = fdata->pkt_len;
812       fdata->cum_bytes  = cum_bytes;
813     }
814
815     /* increase cum_bytes with this packets length */
816     cum_bytes += fdata->pkt_len;
817
818     epan_dissect_fill_in_columns(edt);
819
820     /* If we haven't yet seen the first frame, this is it.
821
822        XXX - we must do this before we add the row to the display,
823        as, if the display's GtkCList's selection mode is
824        GTK_SELECTION_BROWSE, when the first entry is added to it,
825        "cf_select_packet()" will be called, and it will fetch the row
826        data for the 0th row, and will get a null pointer rather than
827        "fdata", as "gtk_clist_append()" won't yet have returned and
828        thus "gtk_clist_set_row_data()" won't yet have been called.
829
830        We thus need to leave behind bread crumbs so that
831        "cf_select_packet()" can find this frame.  See the comment
832        in "cf_select_packet()". */
833     if (cf->first_displayed == NULL)
834       cf->first_displayed = fdata;
835
836     /* This is the last frame we've seen so far. */
837     cf->last_displayed = fdata;
838
839     row = packet_list_append(cf->cinfo.col_data, fdata);
840
841     /* colorize packet: if packet is marked, use preferences, 
842        otherwise try to apply color filters */
843       if (fdata->flags.marked) {
844           fdata->color_filter = NULL;
845           packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
846       } else {
847           fdata->color_filter = color_filters_colorize_packet(row, edt);
848       }
849
850     /* Set the time of the previous displayed frame to the time of this
851        frame. */
852     prev_ts = fdata->abs_ts;
853
854     cf->displayed_count++;
855   } else {
856     /* This frame didn't pass the display filter, so it's not being added
857        to the clist, and thus has no row. */
858     row = -1;
859   }
860   epan_dissect_free(edt);
861   return row;
862 }
863
864 static void
865 read_packet(capture_file *cf, long offset)
866 {
867   const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
868   union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
869   const guchar *buf = wtap_buf_ptr(cf->wth);
870   frame_data   *fdata;
871   int           passed;
872   frame_data   *plist_end;
873   epan_dissect_t *edt;
874
875   /* Allocate the next list entry, and add it to the list. */
876   fdata = g_mem_chunk_alloc(cf->plist_chunk);
877
878   fdata->num = 0;
879   fdata->next = NULL;
880   fdata->prev = NULL;
881   fdata->pfd  = NULL;
882   fdata->pkt_len  = phdr->len;
883   fdata->cap_len  = phdr->caplen;
884   fdata->file_off = offset;
885   fdata->lnk_t = phdr->pkt_encap;
886   fdata->flags.encoding = CHAR_ASCII;
887   fdata->flags.visited = 0;
888   fdata->flags.marked = 0;
889   fdata->flags.ref_time = 0;
890
891   fdata->abs_ts  = *((nstime_t *) &phdr->ts);
892
893   passed = TRUE;
894   if (cf->rfcode) {
895     edt = epan_dissect_new(TRUE, FALSE);
896     epan_dissect_prime_dfilter(edt, cf->rfcode);
897     epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
898     passed = dfilter_apply_edt(cf->rfcode, edt);
899     epan_dissect_free(edt);
900   }
901   if (passed) {
902     plist_end = cf->plist_end;
903     fdata->prev = plist_end;
904     if (plist_end != NULL)
905       plist_end->next = fdata;
906     else
907       cf->plist = fdata;
908     cf->plist_end = fdata;
909
910     cf->count++;
911     cf->f_datalen = offset + phdr->caplen;
912     fdata->num = cf->count;
913     add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
914   } else {
915     /* XXX - if we didn't have read filters, or if we could avoid
916        allocating the "frame_data" structure until we knew whether
917        the frame passed the read filter, we could use a G_ALLOC_ONLY
918        memory chunk...
919
920        ...but, at least in one test I did, where I just made the chunk
921        a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
922        seem to save a noticeable amount of time or space. */
923     g_mem_chunk_free(cf->plist_chunk, fdata);
924   }
925 }
926
927 cf_status_t
928 cf_merge_files(char **out_filenamep, int in_file_count,
929                char *const *in_filenames, int file_type, gboolean do_append)
930 {
931   merge_in_file_t  *in_files;
932   wtap             *wth;
933   char             *out_filename;
934   char              tmpname[128+1];
935   int               out_fd;
936   wtap_dumper      *pdh;
937   int               open_err, read_err, write_err, close_err;
938   gchar            *err_info;
939   int               err_fileno; 
940   int               i;
941   char              errmsg_errno[1024+1];
942   gchar             err_str[2048+1];
943   const char       *errmsg;
944   gboolean          got_read_error = FALSE, got_write_error = FALSE;
945   long              data_offset;
946   progdlg_t        *progbar = NULL;
947   gboolean          stop_flag;
948   gint64            f_len, file_pos;
949   float             prog_val;
950   GTimeVal          start_time;
951   gchar             status_str[100];
952   gint64            progbar_nextstep;
953   gint64            progbar_quantum;
954
955   /* open the input files */
956   if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
957                            &open_err, &err_info, &err_fileno)) {
958     free(in_files);
959     cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
960                               FALSE, 0);
961     return CF_ERROR;
962   }
963
964   if (*out_filenamep != NULL) {
965     out_filename = *out_filenamep;
966     out_fd = open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
967     if (out_fd == -1)
968       open_err = errno;
969   } else {
970     out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
971     if (out_fd == -1)
972       open_err = errno;
973     out_filename = g_strdup(tmpname);
974     *out_filenamep = out_filename;
975   }
976   if (out_fd == -1) {
977     err_info = NULL;
978     merge_close_in_files(in_file_count, in_files);
979     free(in_files);
980     cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
981     return CF_ERROR;
982   }
983
984   pdh = wtap_dump_fdopen(out_fd, file_type,
985       merge_select_frame_type(in_file_count, in_files),
986       merge_max_snapshot_length(in_file_count, in_files), 
987           FALSE /* compressed */, &open_err);
988   if (pdh == NULL) {
989     close(out_fd);
990     merge_close_in_files(in_file_count, in_files);
991     free(in_files);
992     cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
993                               file_type);
994     return CF_ERROR;
995   }
996
997   /* Get the sum of the sizes of all the files. */
998   f_len = 0;
999   for (i = 0; i < in_file_count; i++)
1000     f_len += in_files[i].size;
1001
1002   /* Update the progress bar when it gets to this value. */
1003   progbar_nextstep = 0;
1004   /* When we reach the value that triggers a progress bar update,
1005      bump that value by this amount. */
1006   progbar_quantum = f_len/N_PROGBAR_UPDATES;
1007
1008   stop_flag = FALSE;
1009   g_get_current_time(&start_time);
1010
1011   /* do the merge (or append) */
1012   for (;;) {
1013     if (do_append)
1014       wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1015                                      &err_info);
1016     else
1017       wth = merge_read_packet(in_file_count, in_files, &read_err,
1018                               &err_info);
1019     if (wth == NULL) {
1020       if (read_err != 0)
1021         got_read_error = TRUE;
1022       break;
1023     }
1024
1025     /* Get the sum of the data offsets in all of the files. */
1026     data_offset = 0;
1027     for (i = 0; i < in_file_count; i++)
1028       data_offset += in_files[i].data_offset;
1029
1030     if (data_offset >= progbar_nextstep) {
1031         /* Get the sum of the seek positions in all of the files. */
1032         file_pos = 0;
1033         for (i = 0; i < in_file_count; i++)
1034           file_pos += wtap_read_so_far(in_files[i].wth, NULL);
1035         prog_val = (gfloat) file_pos / (gfloat) f_len;
1036         if (prog_val > 1.0) {
1037           /* Some file probably grew while we were reading it.
1038              That "shouldn't happen", so we'll just clip the progress
1039              value at 1.0. */
1040           prog_val = 1.0;
1041         }
1042         if (progbar == NULL) {
1043           /* Create the progress bar if necessary */
1044           progbar = delayed_create_progress_dlg("Merging", "files",
1045             &stop_flag, &start_time, prog_val);
1046         }
1047         if (progbar != NULL) {
1048           g_snprintf(status_str, sizeof(status_str),
1049                      "%" PRId64 "KB of %" PRId64 "KB",
1050                      file_pos / 1024, f_len / 1024);
1051           update_progress_dlg(progbar, prog_val, status_str);
1052         }
1053         progbar_nextstep += progbar_quantum;
1054     }
1055
1056     if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1057          wtap_buf_ptr(wth), &write_err)) {
1058       got_write_error = TRUE;
1059       break;
1060     }
1061   }
1062
1063   /* We're done merging the files; destroy the progress bar if it was created. */
1064   if (progbar != NULL)
1065     destroy_progress_dlg(progbar);
1066
1067   merge_close_in_files(in_file_count, in_files);
1068   if (!got_read_error && !got_write_error) {
1069     if (!wtap_dump_close(pdh, &write_err))
1070       got_write_error = TRUE;
1071   } else
1072     wtap_dump_close(pdh, &close_err);
1073
1074   if (got_read_error) {
1075     /*
1076      * Find the file on which we got the error, and report the error.
1077      */
1078     for (i = 0; i < in_file_count; i++) {
1079       if (in_files[i].state == GOT_ERROR) {
1080         /* Put up a message box noting that a read failed somewhere along
1081            the line. */
1082         switch (read_err) {
1083
1084         case WTAP_ERR_UNSUPPORTED_ENCAP:
1085           g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1086                    "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1087                    err_info);
1088           g_free(err_info);
1089           errmsg = errmsg_errno;
1090           break;
1091
1092         case WTAP_ERR_CANT_READ:
1093           errmsg = "An attempt to read from the capture file %s failed for"
1094                    " some unknown reason.";
1095           break;
1096
1097         case WTAP_ERR_SHORT_READ:
1098           errmsg = "The capture file %s appears to have been cut short"
1099                    " in the middle of a packet.";
1100           break;
1101
1102         case WTAP_ERR_BAD_RECORD:
1103           g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1104                    "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1105                    err_info);
1106           g_free(err_info);
1107           errmsg = errmsg_errno;
1108           break;
1109
1110         default:
1111           g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1112                    "An error occurred while reading the"
1113                    " capture file %%s: %s.", wtap_strerror(read_err));
1114           errmsg = errmsg_errno;
1115           break;
1116         }
1117         g_snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1118         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1119       }
1120     }
1121   }
1122
1123   if (got_write_error) {
1124     /* Put up an alert box for the write error. */
1125     cf_write_failure_alert_box(out_filename, write_err);
1126   }
1127
1128   return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
1129 }
1130
1131 cf_status_t
1132 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1133 {
1134   dfilter_t  *dfcode;
1135   const char *filter_new = dftext ? dftext : "";
1136   const char *filter_old = cf->dfilter ? cf->dfilter : "";
1137
1138   /* if new filter equals old one, do nothing unless told to do so */
1139   if (!force && strcmp(filter_new, filter_old) == 0) {
1140     return CF_OK;
1141   }
1142
1143   if (dftext == NULL) {
1144     /* The new filter is an empty filter (i.e., display all packets). */
1145     dfcode = NULL;
1146   } else {
1147     /*
1148      * We have a filter; make a copy of it (as we'll be saving it),
1149      * and try to compile it.
1150      */
1151     dftext = g_strdup(dftext);
1152     if (!dfilter_compile(dftext, &dfcode)) {
1153       /* The attempt failed; report an error. */
1154       gchar *safe_dftext = simple_dialog_format_message(dftext);
1155       gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1156           dfilter_error_msg);
1157       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, 
1158           "%s%s%s\n"
1159           "\n"
1160           "The following display filter isn't a valid display filter:\n%s\n"
1161           "See the help for a description of the display filter syntax.",
1162           simple_dialog_primary_start(), safe_dfilter_error_msg,
1163           simple_dialog_primary_end(), safe_dftext);
1164       g_free(safe_dfilter_error_msg);
1165       g_free(safe_dftext);
1166       g_free(dftext);
1167       return CF_ERROR;
1168     }
1169
1170     /* Was it empty? */
1171     if (dfcode == NULL) {
1172       /* Yes - free the filter text, and set it to null. */
1173       g_free(dftext);
1174       dftext = NULL;
1175     }
1176   }
1177
1178   /* We have a valid filter.  Replace the current filter. */
1179   if (cf->dfilter != NULL)
1180     g_free(cf->dfilter);
1181   cf->dfilter = dftext;
1182   if (cf->dfcode != NULL)
1183     dfilter_free(cf->dfcode);
1184   cf->dfcode = dfcode;
1185
1186   /* Now rescan the packet list, applying the new filter, but not
1187      throwing away information constructed on a previous pass. */
1188   if (dftext == NULL) {
1189     rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1190   } else {
1191     rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1192   }
1193   return CF_OK;
1194 }
1195
1196 void
1197 cf_colorize_packets(capture_file *cf)
1198 {
1199   rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1200 }
1201
1202 void
1203 cf_reftime_packets(capture_file *cf)
1204 {
1205   rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1206 }
1207
1208 void
1209 cf_redissect_packets(capture_file *cf)
1210 {
1211   rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1212 }
1213
1214 /* Rescan the list of packets, reconstructing the CList.
1215
1216    "action" describes why we're doing this; it's used in the progress
1217    dialog box.
1218
1219    "action_item" describes what we're doing; it's used in the progress
1220    dialog box.
1221
1222    "refilter" is TRUE if we need to re-evaluate the filter expression.
1223
1224    "redissect" is TRUE if we need to make the dissectors reconstruct
1225    any state information they have (because a preference that affects
1226    some dissector has changed, meaning some dissector might construct
1227    its state differently from the way it was constructed the last time). */
1228 static void
1229 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1230                 gboolean refilter, gboolean redissect)
1231 {
1232   frame_data *fdata;
1233   progdlg_t  *progbar = NULL;
1234   gboolean    stop_flag;
1235   int         count;
1236   int         err;
1237   gchar      *err_info;
1238   frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1239   int         selected_row, prev_row, preceding_row, following_row;
1240   gboolean    selected_frame_seen;
1241   int         row;
1242   float       prog_val;
1243   GTimeVal    start_time;
1244   gchar       status_str[100];
1245   int         progbar_nextstep;
1246   int         progbar_quantum;
1247
1248   cum_bytes=0;
1249   reset_tap_listeners();
1250   /* Which frame, if any, is the currently selected frame?
1251      XXX - should the selected frame or the focus frame be the "current"
1252      frame, that frame being the one from which "Find Frame" searches
1253      start? */
1254   selected_frame = cf->current_frame;
1255
1256   /* We don't yet know what row that frame will be on, if any, after we
1257      rebuild the clist, however. */
1258   selected_row = -1;
1259
1260   if (redissect) {
1261     /* We need to re-initialize all the state information that protocols
1262        keep, because some preference that controls a dissector has changed,
1263        which might cause the state information to be constructed differently
1264        by that dissector. */
1265
1266     /* Initialize all data structures used for dissection. */
1267     init_dissection();
1268   }
1269
1270   /* Freeze the packet list while we redo it, so we don't get any
1271      screen updates while it happens. */
1272   packet_list_freeze();
1273
1274   /* Clear it out. */
1275   packet_list_clear();
1276
1277   /* We don't yet know which will be the first and last frames displayed. */
1278   cf->first_displayed = NULL;
1279   cf->last_displayed = NULL;
1280
1281   /* We currently don't display any packets */
1282   cf->displayed_count = 0;
1283
1284   /* Iterate through the list of frames.  Call a routine for each frame
1285      to check whether it should be displayed and, if so, add it to
1286      the display list. */
1287   nstime_set_zero(&first_ts);
1288   nstime_set_zero(&prev_ts);
1289
1290   /* Update the progress bar when it gets to this value. */
1291   progbar_nextstep = 0;
1292   /* When we reach the value that triggers a progress bar update,
1293      bump that value by this amount. */
1294   progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1295   /* Count of packets at which we've looked. */
1296   count = 0;
1297
1298   stop_flag = FALSE;
1299   g_get_current_time(&start_time);
1300
1301   row = -1;             /* no previous row yet */
1302   prev_row = -1;
1303   prev_frame = NULL;
1304
1305   preceding_row = -1;
1306   preceding_frame = NULL;
1307   following_row = -1;
1308   following_frame = NULL;
1309
1310   selected_frame_seen = FALSE;
1311
1312   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1313     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1314        when we update it, we have to run the GTK+ main loop to get it
1315        to repaint what's pending, and doing so may involve an "ioctl()"
1316        to see if there's any pending input from an X server, and doing
1317        that for every packet can be costly, especially on a big file. */
1318     if (count >= progbar_nextstep) {
1319       /* let's not divide by zero. I should never be started
1320        * with count == 0, so let's assert that
1321        */
1322       g_assert(cf->count > 0);
1323       prog_val = (gfloat) count / cf->count;
1324
1325       if (progbar == NULL)
1326         /* Create the progress bar if necessary */
1327         progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1328           &start_time, prog_val);
1329
1330       if (progbar != NULL) {
1331         g_snprintf(status_str, sizeof(status_str),
1332                   "%4u of %u frames", count, cf->count);
1333         update_progress_dlg(progbar, prog_val, status_str);
1334       }
1335
1336       progbar_nextstep += progbar_quantum;
1337     }
1338
1339     if (stop_flag) {
1340       /* Well, the user decided to abort the filtering.  Just stop.
1341
1342          XXX - go back to the previous filter?  Users probably just
1343          want not to wait for a filtering operation to finish;
1344          unless we cancel by having no filter, reverting to the
1345          previous filter will probably be even more expensive than
1346          continuing the filtering, as it involves going back to the
1347          beginning and filtering, and even with no filter we currently
1348          have to re-generate the entire clist, which is also expensive.
1349
1350          I'm not sure what Network Monitor does, but it doesn't appear
1351          to give you an unfiltered display if you cancel. */
1352       break;
1353     }
1354
1355     count++;
1356
1357     if (redissect) {
1358       /* Since all state for the frame was destroyed, mark the frame
1359        * as not visited, free the GSList referring to the state
1360        * data (the per-frame data itself was freed by
1361        * "init_dissection()"), and null out the GSList pointer. */
1362       fdata->flags.visited = 0;
1363       if (fdata->pfd) {
1364         g_slist_free(fdata->pfd);
1365         fdata->pfd = NULL;
1366       }
1367     }
1368
1369     if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1370         cf->pd, fdata->cap_len, &err, &err_info)) {
1371         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1372                       cf_read_error_message(err, err_info), cf->filename);
1373         break;
1374     }
1375
1376     /* If the previous frame is displayed, and we haven't yet seen the
1377        selected frame, remember that frame - it's the closest one we've
1378        yet seen before the selected frame. */
1379     if (prev_row != -1 && !selected_frame_seen) {
1380       preceding_row = prev_row;
1381       preceding_frame = prev_frame;
1382     }
1383     row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1384                                         refilter);
1385
1386     /* If this frame is displayed, and this is the first frame we've
1387        seen displayed after the selected frame, remember this frame -
1388        it's the closest one we've yet seen at or after the selected
1389        frame. */
1390     if (row != -1 && selected_frame_seen && following_row == -1) {
1391       following_row = row;
1392       following_frame = fdata;
1393     }
1394     if (fdata == selected_frame) {
1395       selected_row = row;
1396       selected_frame_seen = TRUE;
1397     }
1398
1399     /* Remember this row/frame - it'll be the previous row/frame
1400        on the next pass through the loop. */
1401     prev_row = row;
1402     prev_frame = fdata;
1403   }
1404
1405   if (redissect) {
1406     /* Clear out what remains of the visited flags and per-frame data
1407        pointers.
1408
1409        XXX - that may cause various forms of bogosity when dissecting
1410        these frames, as they won't have been seen by this sequential
1411        pass, but the only alternative I see is to keep scanning them
1412        even though the user requested that the scan stop, and that
1413        would leave the user stuck with an Ethereal grinding on
1414        until it finishes.  Should we just stick them with that? */
1415     for (; fdata != NULL; fdata = fdata->next) {
1416       fdata->flags.visited = 0;
1417       if (fdata->pfd) {
1418         g_slist_free(fdata->pfd);
1419         fdata->pfd = NULL;
1420       }
1421     }
1422   }
1423
1424   /* We're done filtering the packets; destroy the progress bar if it
1425      was created. */
1426   if (progbar != NULL)
1427     destroy_progress_dlg(progbar);
1428
1429   /* Unfreeze the packet list. */
1430   packet_list_thaw();
1431
1432   if (selected_row == -1) {
1433     /* The selected frame didn't pass the filter. */
1434     if (selected_frame == NULL) {
1435       /* That's because there *was* no selected frame.  Make the first
1436          displayed frame the current frame. */
1437       selected_row = 0;
1438     } else {
1439       /* Find the nearest displayed frame to the selected frame (whether
1440          it's before or after that frame) and make that the current frame.
1441          If the next and previous displayed frames are equidistant from the
1442          selected frame, choose the next one. */
1443       g_assert(following_frame == NULL ||
1444                following_frame->num >= selected_frame->num);
1445       g_assert(preceding_frame == NULL ||
1446                preceding_frame->num <= selected_frame->num);
1447       if (following_frame == NULL) {
1448         /* No frame after the selected frame passed the filter, so we
1449            have to select the last displayed frame before the selected
1450            frame. */
1451         selected_row = preceding_row;
1452       } else if (preceding_frame == NULL) {
1453         /* No frame before the selected frame passed the filter, so we
1454            have to select the first displayed frame after the selected
1455            frame. */
1456         selected_row = following_row;
1457       } else {
1458         /* Choose the closer of the last displayed frame before the
1459            selected frame and the first displayed frame after the
1460            selected frame; in case of a tie, choose the first displayed
1461            frame after the selected frame. */
1462         if (following_frame->num - selected_frame->num <=
1463             selected_frame->num - preceding_frame->num) {
1464           selected_row = following_row;
1465         } else {
1466           /* The previous frame is closer to the selected frame than the
1467              next frame. */
1468           selected_row = preceding_row;
1469         }
1470       }
1471     }
1472   }
1473
1474   if (selected_row == -1) {
1475     /* There are no frames displayed at all. */
1476     cf_unselect_packet(cf);
1477   } else {
1478     /* Either the frame that was selected passed the filter, or we've
1479        found the nearest displayed frame to that frame.  Select it, make
1480        it the focus row, and make it visible. */
1481     packet_list_set_selected_row(selected_row);
1482   }
1483 }
1484
1485 typedef enum {
1486   PSP_FINISHED,
1487   PSP_STOPPED,
1488   PSP_FAILED
1489 } psp_return_t;
1490
1491 static psp_return_t
1492 process_specified_packets(capture_file *cf, packet_range_t *range,
1493     const char *string1, const char *string2,
1494     gboolean (*callback)(capture_file *, frame_data *,
1495                          union wtap_pseudo_header *, const guint8 *, void *),
1496     void *callback_args)
1497 {
1498   frame_data *fdata;
1499   int         err;
1500   gchar      *err_info;
1501   union wtap_pseudo_header pseudo_header;
1502   guint8      pd[WTAP_MAX_PACKET_SIZE+1];
1503   psp_return_t ret = PSP_FINISHED;
1504
1505   progdlg_t  *progbar = NULL;
1506   int         progbar_count;
1507   float       progbar_val;
1508   gboolean    progbar_stop_flag;
1509   GTimeVal    progbar_start_time;
1510   gchar       progbar_status_str[100];
1511   int         progbar_nextstep;
1512   int         progbar_quantum;
1513   range_process_e process_this;
1514
1515   /* Update the progress bar when it gets to this value. */
1516   progbar_nextstep = 0;
1517   /* When we reach the value that triggers a progress bar update,
1518      bump that value by this amount. */
1519   progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1520   /* Count of packets at which we've looked. */
1521   progbar_count = 0;
1522
1523   progbar_stop_flag = FALSE;
1524   g_get_current_time(&progbar_start_time);
1525
1526   packet_range_process_init(range);
1527
1528   /* Iterate through the list of packets, printing the packets that
1529      were selected by the current display filter.  */
1530   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1531     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1532        when we update it, we have to run the GTK+ main loop to get it
1533        to repaint what's pending, and doing so may involve an "ioctl()"
1534        to see if there's any pending input from an X server, and doing
1535        that for every packet can be costly, especially on a big file. */
1536     if (progbar_count >= progbar_nextstep) {
1537       /* let's not divide by zero. I should never be started
1538        * with count == 0, so let's assert that
1539        */
1540       g_assert(cf->count > 0);
1541       progbar_val = (gfloat) progbar_count / cf->count;
1542
1543       if (progbar == NULL)
1544         /* Create the progress bar if necessary */
1545         progbar = delayed_create_progress_dlg(string1, string2,
1546                                               &progbar_stop_flag,
1547                                               &progbar_start_time,
1548                                               progbar_val);
1549
1550       if (progbar != NULL) {
1551         g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1552                    "%4u of %u packets", progbar_count, cf->count);
1553         update_progress_dlg(progbar, progbar_val, progbar_status_str);
1554       }
1555
1556       progbar_nextstep += progbar_quantum;
1557     }
1558
1559     if (progbar_stop_flag) {
1560       /* Well, the user decided to abort the operation.  Just stop,
1561          and arrange to return TRUE to our caller, so they know it
1562          was stopped explicitly. */
1563       ret = PSP_STOPPED;
1564       break;
1565     }
1566
1567     progbar_count++;
1568
1569     /* do we have to process this packet? */
1570     process_this = packet_range_process_packet(range, fdata);
1571     if (process_this == range_process_next) {
1572         /* this packet uninteresting, continue with next one */
1573         continue;
1574     } else if (process_this == range_processing_finished) {
1575         /* all interesting packets processed, stop the loop */
1576         break;
1577     }
1578
1579     /* Get the packet */
1580     if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1581                         pd, fdata->cap_len, &err, &err_info)) {
1582       /* Attempt to get the packet failed. */
1583       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1584                     cf_read_error_message(err, err_info), cf->filename);
1585       ret = PSP_FAILED;
1586       break;
1587     }
1588     /* Process the packet */
1589     if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1590       /* Callback failed.  We assume it reported the error appropriately. */
1591       ret = PSP_FAILED;
1592       break;
1593     }
1594   }
1595
1596   /* We're done printing the packets; destroy the progress bar if
1597      it was created. */
1598   if (progbar != NULL)
1599     destroy_progress_dlg(progbar);
1600
1601   return ret;
1602 }
1603
1604 static gboolean
1605 retap_packet(capture_file *cf _U_, frame_data *fdata,
1606              union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1607              void *argsp)
1608 {
1609   column_info *cinfo = argsp;
1610   epan_dissect_t *edt;
1611
1612   /* If we have tap listeners, allocate a protocol tree root node, so that
1613      we'll construct a protocol tree against which a filter expression can
1614      be evaluated. */
1615   edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1616   tap_queue_init(edt);
1617   epan_dissect_run(edt, pseudo_header, pd, fdata, cinfo);
1618   tap_push_tapped_queue(edt);
1619   epan_dissect_free(edt);
1620
1621   return TRUE;
1622 }
1623
1624 cf_read_status_t
1625 cf_retap_packets(capture_file *cf, gboolean do_columns)
1626 {
1627   packet_range_t range;
1628
1629   /* Reset the tap listeners. */
1630   reset_tap_listeners();
1631
1632   /* Iterate through the list of packets, dissecting all packets and
1633      re-running the taps. */
1634   packet_range_init(&range);
1635   packet_range_process_init(&range);
1636   switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1637                                     "all packets", retap_packet,
1638                                     do_columns ? &cf->cinfo : NULL)) {
1639   case PSP_FINISHED:
1640     /* Completed successfully. */
1641     return CF_OK;
1642
1643   case PSP_STOPPED:
1644     /* Well, the user decided to abort the refiltering.
1645        Return CF_READ_ABORTED so our caller knows they did that. */
1646     return CF_READ_ABORTED;
1647
1648   case PSP_FAILED:
1649     /* Error while retapping. */
1650     return CF_READ_ERROR;
1651   }
1652
1653   g_assert_not_reached();
1654   return CF_READ_OK;
1655 }
1656
1657 typedef struct {
1658   print_args_t *print_args;
1659   gboolean      print_header_line;
1660   char         *header_line_buf;
1661   int           header_line_buf_len;
1662   gboolean      print_formfeed;
1663   gboolean      print_separator;
1664   char         *line_buf;
1665   int           line_buf_len;
1666   gint         *col_widths;
1667 } print_callback_args_t;
1668
1669 static gboolean
1670 print_packet(capture_file *cf, frame_data *fdata,
1671              union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1672              void *argsp)
1673 {
1674   print_callback_args_t *args = argsp;
1675   epan_dissect_t *edt;
1676   int             i;
1677   char           *cp;
1678   int             line_len;
1679   int             column_len;
1680   int             cp_off;
1681   gboolean        proto_tree_needed;
1682   char            bookmark_name[9+10+1];        /* "__frameNNNNNNNNNN__\0" */
1683   char            bookmark_title[6+10+1];       /* "Frame NNNNNNNNNN__\0" */
1684
1685   /* Create the protocol tree, and make it visible, if we're printing
1686      the dissection or the hex data.
1687      XXX - do we need it if we're just printing the hex data? */
1688   proto_tree_needed = 
1689       args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1690   edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1691
1692   /* Fill in the column information if we're printing the summary
1693      information. */
1694   if (args->print_args->print_summary) {
1695     epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1696     epan_dissect_fill_in_columns(edt);
1697   } else
1698     epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1699
1700   if (args->print_formfeed) {
1701     if (!new_page(args->print_args->stream))
1702       goto fail;
1703   } else {
1704       if (args->print_separator) {
1705         if (!print_line(args->print_args->stream, 0, ""))
1706           goto fail;
1707       }
1708   }
1709
1710   /*
1711    * We generate bookmarks, if the output format supports them.
1712    * The name is "__frameN__".
1713    */
1714   g_snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
1715
1716   if (args->print_args->print_summary) {
1717     if (args->print_header_line) {
1718       if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1719         goto fail;
1720       args->print_header_line = FALSE;  /* we might not need to print any more */
1721     }
1722     cp = &args->line_buf[0];
1723     line_len = 0;
1724     for (i = 0; i < cf->cinfo.num_cols; i++) {
1725       /* Find the length of the string for this column. */
1726       column_len = strlen(cf->cinfo.col_data[i]);
1727       if (args->col_widths[i] > column_len)
1728          column_len = args->col_widths[i];
1729
1730       /* Make sure there's room in the line buffer for the column; if not,
1731          double its length. */
1732       line_len += column_len + 1;       /* "+1" for space */
1733       if (line_len > args->line_buf_len) {
1734         cp_off = cp - args->line_buf;
1735         args->line_buf_len = 2 * line_len;
1736         args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1737         cp = args->line_buf + cp_off;
1738       }
1739
1740       /* Right-justify the packet number column. */
1741       if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1742         sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1743       else
1744         sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1745       cp += column_len;
1746       if (i != cf->cinfo.num_cols - 1)
1747         *cp++ = ' ';
1748     }
1749     *cp = '\0';
1750
1751     /*
1752      * Generate a bookmark, using the summary line as the title.
1753      */
1754     if (!print_bookmark(args->print_args->stream, bookmark_name,
1755                         args->line_buf))
1756       goto fail;
1757
1758     if (!print_line(args->print_args->stream, 0, args->line_buf))
1759       goto fail;
1760   } else {
1761     /*
1762      * Generate a bookmark, using "Frame N" as the title, as we're not
1763      * printing the summary line.
1764      */
1765     g_snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
1766     if (!print_bookmark(args->print_args->stream, bookmark_name,
1767                         bookmark_title))
1768       goto fail;
1769   } /* if (print_summary) */
1770
1771   if (args->print_args->print_dissections != print_dissections_none) {
1772     if (args->print_args->print_summary) {
1773       /* Separate the summary line from the tree with a blank line. */
1774       if (!print_line(args->print_args->stream, 0, ""))
1775         goto fail;
1776     }
1777
1778     /* Print the information in that tree. */
1779     if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
1780       goto fail;
1781
1782     /* Print a blank line if we print anything after this (aka more than one packet). */
1783     args->print_separator = TRUE;
1784
1785     /* Print a header line if we print any more packet summaries */
1786     args->print_header_line = TRUE;
1787   }
1788
1789   if (args->print_args->print_hex) {
1790     /* Print the full packet data as hex. */
1791     if (!print_hex_data(args->print_args->stream, edt))
1792       goto fail;
1793
1794     /* Print a blank line if we print anything after this (aka more than one packet). */
1795     args->print_separator = TRUE;
1796
1797     /* Print a header line if we print any more packet summaries */
1798     args->print_header_line = TRUE;
1799   } /* if (args->print_args->print_dissections != print_dissections_none) */
1800
1801   epan_dissect_free(edt);
1802
1803   /* do we want to have a formfeed between each packet from now on? */
1804   if(args->print_args->print_formfeed) {
1805     args->print_formfeed = TRUE;
1806   }
1807
1808   return TRUE;
1809
1810 fail:
1811   epan_dissect_free(edt);
1812   return FALSE;
1813 }
1814
1815 cf_print_status_t
1816 cf_print_packets(capture_file *cf, print_args_t *print_args)
1817 {
1818   int         i;
1819   print_callback_args_t callback_args;
1820   gint        data_width;
1821   char        *cp;
1822   int         cp_off;
1823   int         column_len;
1824   int         line_len;
1825   psp_return_t ret;
1826
1827   callback_args.print_args = print_args;
1828   callback_args.print_header_line = TRUE;
1829   callback_args.header_line_buf = NULL;
1830   callback_args.header_line_buf_len = 256;
1831   callback_args.print_formfeed = FALSE;
1832   callback_args.print_separator = FALSE;
1833   callback_args.line_buf = NULL;
1834   callback_args.line_buf_len = 256;
1835   callback_args.col_widths = NULL;
1836
1837   if (!print_preamble(print_args->stream, cf->filename)) {
1838     destroy_print_stream(print_args->stream);
1839     return CF_PRINT_WRITE_ERROR;
1840   }
1841
1842   if (print_args->print_summary) {
1843     /* We're printing packet summaries.  Allocate the header line buffer
1844        and get the column widths. */
1845     callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1846
1847     /* Find the widths for each of the columns - maximum of the
1848        width of the title and the width of the data - and construct
1849        a buffer with a line containing the column titles. */
1850     callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1851     cp = &callback_args.header_line_buf[0];
1852     line_len = 0;
1853     for (i = 0; i < cf->cinfo.num_cols; i++) {
1854       /* Don't pad the last column. */
1855       if (i == cf->cinfo.num_cols - 1)
1856         callback_args.col_widths[i] = 0;
1857       else {
1858         callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1859         data_width = get_column_char_width(get_column_format(i));
1860         if (data_width > callback_args.col_widths[i])
1861           callback_args.col_widths[i] = data_width;
1862       }
1863
1864       /* Find the length of the string for this column. */
1865       column_len = strlen(cf->cinfo.col_title[i]);
1866       if (callback_args.col_widths[i] > column_len)
1867         column_len = callback_args.col_widths[i];
1868
1869       /* Make sure there's room in the line buffer for the column; if not,
1870          double its length. */
1871       line_len += column_len + 1;       /* "+1" for space */
1872       if (line_len > callback_args.header_line_buf_len) {
1873         cp_off = cp - callback_args.header_line_buf;
1874         callback_args.header_line_buf_len = 2 * line_len;
1875         callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1876                                                   callback_args.header_line_buf_len + 1);
1877         cp = callback_args.header_line_buf + cp_off;
1878       }
1879
1880       /* Right-justify the packet number column. */
1881 /*      if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1882         sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1883       else*/
1884         sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1885       cp += column_len;
1886       if (i != cf->cinfo.num_cols - 1)
1887         *cp++ = ' ';
1888     }
1889     *cp = '\0';
1890
1891     /* Now start out the main line buffer with the same length as the
1892        header line buffer. */
1893     callback_args.line_buf_len = callback_args.header_line_buf_len;
1894     callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1895   } /* if (print_summary) */
1896
1897   /* Iterate through the list of packets, printing the packets we were
1898      told to print. */
1899   ret = process_specified_packets(cf, &print_args->range, "Printing",
1900                                   "selected packets", print_packet,
1901                                   &callback_args);
1902
1903   if (callback_args.header_line_buf != NULL)
1904     g_free(callback_args.header_line_buf);
1905   if (callback_args.line_buf != NULL)
1906     g_free(callback_args.line_buf);
1907   if (callback_args.col_widths != NULL)
1908     g_free(callback_args.col_widths);
1909
1910   switch (ret) {
1911
1912   case PSP_FINISHED:
1913     /* Completed successfully. */
1914     break;
1915
1916   case PSP_STOPPED:
1917     /* Well, the user decided to abort the printing.
1918
1919        XXX - note that what got generated before they did that
1920        will get printed if we're piping to a print program; we'd
1921        have to write to a file and then hand that to the print
1922        program to make it actually not print anything. */
1923     break;
1924
1925   case PSP_FAILED:
1926     /* Error while printing.
1927
1928        XXX - note that what got generated before they did that
1929        will get printed if we're piping to a print program; we'd
1930        have to write to a file and then hand that to the print
1931        program to make it actually not print anything. */
1932     destroy_print_stream(print_args->stream);
1933     return CF_PRINT_WRITE_ERROR;
1934   }
1935
1936   if (!print_finale(print_args->stream)) {
1937     destroy_print_stream(print_args->stream);
1938     return CF_PRINT_WRITE_ERROR;
1939   }
1940
1941   if (!destroy_print_stream(print_args->stream))
1942     return CF_PRINT_WRITE_ERROR;
1943
1944   return CF_PRINT_OK;
1945 }
1946
1947 static gboolean
1948 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
1949                   union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1950                   void *argsp)
1951 {
1952   FILE *fh = argsp;
1953   epan_dissect_t *edt;
1954
1955   /* Create the protocol tree, but don't fill in the column information. */
1956   edt = epan_dissect_new(TRUE, TRUE);
1957   epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1958
1959   /* Write out the information in that tree. */
1960   proto_tree_write_pdml(edt, fh);
1961
1962   epan_dissect_free(edt);
1963
1964   return !ferror(fh);
1965 }
1966
1967 cf_print_status_t
1968 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
1969 {
1970   FILE        *fh;
1971   psp_return_t ret;
1972
1973   fh = fopen(print_args->file, "w");
1974   if (fh == NULL)
1975     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
1976
1977   write_pdml_preamble(fh);
1978   if (ferror(fh)) {
1979     fclose(fh);
1980     return CF_PRINT_WRITE_ERROR;
1981   }
1982
1983   /* Iterate through the list of packets, printing the packets we were
1984      told to print. */
1985   ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
1986                                   "selected packets", write_pdml_packet,
1987                                   fh);
1988
1989   switch (ret) {
1990
1991   case PSP_FINISHED:
1992     /* Completed successfully. */
1993     break;
1994
1995   case PSP_STOPPED:
1996     /* Well, the user decided to abort the printing. */
1997     break;
1998
1999   case PSP_FAILED:
2000     /* Error while printing. */
2001     fclose(fh);
2002     return CF_PRINT_WRITE_ERROR;
2003   }
2004
2005   write_pdml_finale(fh);
2006   if (ferror(fh)) {
2007     fclose(fh);
2008     return CF_PRINT_WRITE_ERROR;
2009   }
2010
2011   /* XXX - check for an error */
2012   fclose(fh);
2013
2014   return CF_PRINT_OK;
2015 }
2016
2017 static gboolean
2018 write_psml_packet(capture_file *cf, frame_data *fdata,
2019                   union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2020                   void *argsp)
2021 {
2022   FILE *fh = argsp;
2023   epan_dissect_t *edt;
2024
2025   /* Fill in the column information, but don't create the protocol tree. */
2026   edt = epan_dissect_new(FALSE, FALSE);
2027   epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2028   epan_dissect_fill_in_columns(edt);
2029
2030   /* Write out the information in that tree. */
2031   proto_tree_write_psml(edt, fh);
2032
2033   epan_dissect_free(edt);
2034
2035   return !ferror(fh);
2036 }
2037
2038 cf_print_status_t
2039 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2040 {
2041   FILE        *fh;
2042   psp_return_t ret;
2043
2044   fh = fopen(print_args->file, "w");
2045   if (fh == NULL)
2046     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2047
2048   write_psml_preamble(fh);
2049   if (ferror(fh)) {
2050     fclose(fh);
2051     return CF_PRINT_WRITE_ERROR;
2052   }
2053
2054   /* Iterate through the list of packets, printing the packets we were
2055      told to print. */
2056   ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2057                                   "selected packets", write_psml_packet,
2058                                   fh);
2059
2060   switch (ret) {
2061
2062   case PSP_FINISHED:
2063     /* Completed successfully. */
2064     break;
2065
2066   case PSP_STOPPED:
2067     /* Well, the user decided to abort the printing. */
2068     break;
2069
2070   case PSP_FAILED:
2071     /* Error while printing. */
2072     fclose(fh);
2073     return CF_PRINT_WRITE_ERROR;
2074   }
2075
2076   write_psml_finale(fh);
2077   if (ferror(fh)) {
2078     fclose(fh);
2079     return CF_PRINT_WRITE_ERROR;
2080   }
2081
2082   /* XXX - check for an error */
2083   fclose(fh);
2084
2085   return CF_PRINT_OK;
2086 }
2087
2088 static gboolean
2089 write_csv_packet(capture_file *cf, frame_data *fdata,
2090                  union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2091                  void *argsp)
2092 {
2093   FILE *fh = argsp;
2094   epan_dissect_t *edt;
2095
2096   /* Fill in the column information, but don't create the protocol tree. */
2097   edt = epan_dissect_new(FALSE, FALSE);
2098   epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2099   epan_dissect_fill_in_columns(edt);
2100
2101   /* Write out the information in that tree. */
2102   proto_tree_write_csv(edt, fh);
2103
2104   epan_dissect_free(edt);
2105
2106   return !ferror(fh);
2107 }
2108
2109 cf_print_status_t
2110 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
2111 {
2112   FILE        *fh;
2113   psp_return_t ret;
2114
2115   fh = fopen(print_args->file, "w");
2116   if (fh == NULL)
2117     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2118
2119   write_csv_preamble(fh);
2120   if (ferror(fh)) {
2121     fclose(fh);
2122     return CF_PRINT_WRITE_ERROR;
2123   }
2124
2125   /* Iterate through the list of packets, printing the packets we were
2126      told to print. */
2127   ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
2128                                   "selected packets", write_csv_packet,
2129                                   fh);
2130
2131   switch (ret) {
2132
2133   case PSP_FINISHED:
2134     /* Completed successfully. */
2135     break;
2136
2137   case PSP_STOPPED:
2138     /* Well, the user decided to abort the printing. */
2139     break;
2140
2141   case PSP_FAILED:
2142     /* Error while printing. */
2143     fclose(fh);
2144     return CF_PRINT_WRITE_ERROR;
2145   }
2146
2147   write_csv_finale(fh);
2148   if (ferror(fh)) {
2149     fclose(fh);
2150     return CF_PRINT_WRITE_ERROR;
2151   }
2152
2153   /* XXX - check for an error */
2154   fclose(fh);
2155
2156   return CF_PRINT_OK;
2157 }
2158
2159 /* Scan through the packet list and change all columns that use the
2160    "command-line-specified" time stamp format to use the current
2161    value of that format. */
2162 void
2163 cf_change_time_formats(capture_file *cf)
2164 {
2165   frame_data *fdata;
2166   progdlg_t  *progbar = NULL;
2167   gboolean    stop_flag;
2168   int         count;
2169   int         row;
2170   int         i;
2171   float       prog_val;
2172   GTimeVal    start_time;
2173   gchar       status_str[100];
2174   int         progbar_nextstep;
2175   int         progbar_quantum;
2176   int         first, last;
2177   gboolean    sorted_by_frame_column;
2178
2179
2180   /* adjust timestamp precision if auto is selected */
2181   cf_timestamp_auto_precision(cf);
2182
2183   /* Are there any columns with time stamps in the "command-line-specified"
2184      format?
2185
2186      XXX - we have to force the "column is writable" flag on, as it
2187      might be off from the last frame that was dissected. */
2188   col_set_writable(&cf->cinfo, TRUE);
2189   if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2190     /* No, there aren't any columns in that format, so we have no work
2191        to do. */
2192     return;
2193   }
2194   first = cf->cinfo.col_first[COL_CLS_TIME];
2195   g_assert(first >= 0);
2196   last = cf->cinfo.col_last[COL_CLS_TIME];
2197
2198   /* Freeze the packet list while we redo it, so we don't get any
2199      screen updates while it happens. */
2200   packet_list_freeze();
2201
2202   /* Update the progress bar when it gets to this value. */
2203   progbar_nextstep = 0;
2204   /* When we reach the value that triggers a progress bar update,
2205      bump that value by this amount. */
2206   progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2207   /* Count of packets at which we've looked. */
2208   count = 0;
2209
2210   /*  If the rows are currently sorted by the frame column then we know
2211    *  the row number of each packet: it's the row number of the previously
2212    *  displayed packet + 1.
2213    *
2214    *  Otherwise, if the display is sorted by a different column then we have
2215    *  to use the O(N) packet_list_find_row_from_data() (thus making the job
2216    *  of changing the time display format O(N**2)).
2217    *
2218    *  (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2219    *  the row number and walks that many elements down the clist to find
2220    *  the appropriate element.)
2221    */
2222   sorted_by_frame_column = FALSE;
2223   for (i = 0; i < cf->cinfo.num_cols; i++) {
2224     if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2225     {
2226       sorted_by_frame_column = (i == packet_list_get_sort_column());
2227       break;
2228     }
2229   }
2230
2231   stop_flag = FALSE;
2232   g_get_current_time(&start_time);
2233
2234   /* Iterate through the list of packets, checking whether the packet
2235      is in a row of the summary list and, if so, whether there are
2236      any columns that show the time in the "command-line-specified"
2237      format and, if so, update that row. */
2238   for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2239     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2240        when we update it, we have to run the GTK+ main loop to get it
2241        to repaint what's pending, and doing so may involve an "ioctl()"
2242        to see if there's any pending input from an X server, and doing
2243        that for every packet can be costly, especially on a big file. */
2244     if (count >= progbar_nextstep) {
2245       /* let's not divide by zero. I should never be started
2246        * with count == 0, so let's assert that
2247        */
2248       g_assert(cf->count > 0);
2249
2250       prog_val = (gfloat) count / cf->count;
2251
2252       if (progbar == NULL)
2253         /* Create the progress bar if necessary */
2254         progbar = delayed_create_progress_dlg("Changing", "time display", 
2255           &stop_flag, &start_time, prog_val);
2256
2257       if (progbar != NULL) {
2258         g_snprintf(status_str, sizeof(status_str),
2259                    "%4u of %u packets", count, cf->count);
2260         update_progress_dlg(progbar, prog_val, status_str);
2261       }
2262
2263       progbar_nextstep += progbar_quantum;
2264     }
2265
2266     if (stop_flag) {
2267       /* Well, the user decided to abort the redisplay.  Just stop.
2268
2269          XXX - this leaves the time field in the old format in
2270          frames we haven't yet processed.  So it goes; should we
2271          simply not offer them the option of stopping? */
2272       break;
2273     }
2274
2275     count++;
2276
2277     /* Find what row this packet is in. */
2278     if (!sorted_by_frame_column) {
2279       /* This function is O(N), so we try to avoid using it... */
2280       row = packet_list_find_row_from_data(fdata);
2281     } else {
2282       /* ...which we do by maintaining a count of packets that are
2283          being displayed (i.e., that have passed the display filter),
2284          and using the current value of that count as the row number
2285          (which is why we can only do it when the display is sorted
2286          by the frame number). */
2287       if (fdata->flags.passed_dfilter)
2288         row++;
2289       else
2290         continue;
2291     }
2292
2293     if (row != -1) {
2294       /* This packet is in the summary list, on row "row". */
2295
2296       for (i = first; i <= last; i++) {
2297         if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2298           /* This is one of the columns that shows the time in
2299              "command-line-specified" format; update it. */
2300           cf->cinfo.col_buf[i][0] = '\0';
2301           col_set_cls_time(fdata, &cf->cinfo, i);
2302           packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2303         }
2304       }
2305     }
2306   }
2307
2308   /* We're done redisplaying the packets; destroy the progress bar if it
2309      was created. */
2310   if (progbar != NULL)
2311     destroy_progress_dlg(progbar);
2312
2313   /* Set the column widths of those columns that show the time in
2314      "command-line-specified" format. */
2315   for (i = first; i <= last; i++) {
2316     if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2317       packet_list_set_cls_time_width(i);
2318     }
2319   }
2320
2321   /* Unfreeze the packet list. */
2322   packet_list_thaw();
2323 }
2324
2325 typedef struct {
2326         const char      *string;
2327         size_t          string_len;
2328         capture_file    *cf;
2329         gboolean        frame_matched;
2330 } match_data;
2331
2332 gboolean
2333 cf_find_packet_protocol_tree(capture_file *cf, const char *string)
2334 {
2335   match_data            mdata;
2336
2337   mdata.string = string;
2338   mdata.string_len = strlen(string);
2339   return find_packet(cf, match_protocol_tree, &mdata);
2340 }
2341
2342 static gboolean
2343 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2344 {
2345   match_data            *mdata = criterion;
2346   epan_dissect_t        *edt;
2347
2348   /* Construct the protocol tree, including the displayed text */
2349   edt = epan_dissect_new(TRUE, TRUE);
2350   /* We don't need the column information */
2351   epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2352
2353   /* Iterate through all the nodes, seeing if they have text that matches. */
2354   mdata->cf = cf;
2355   mdata->frame_matched = FALSE;
2356   proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2357   epan_dissect_free(edt);
2358   return mdata->frame_matched;
2359 }
2360
2361 static void
2362 match_subtree_text(proto_node *node, gpointer data)
2363 {
2364   match_data    *mdata = (match_data*) data;
2365   const gchar   *string = mdata->string;
2366   size_t        string_len = mdata->string_len;
2367   capture_file  *cf = mdata->cf;
2368   field_info    *fi = PITEM_FINFO(node);
2369   gchar         label_str[ITEM_LABEL_LENGTH];
2370   gchar         *label_ptr;
2371   size_t        label_len;
2372   guint32       i;
2373   guint8        c_char;
2374   size_t        c_match = 0;
2375
2376   if (mdata->frame_matched) {
2377     /* We already had a match; don't bother doing any more work. */
2378     return;
2379   }
2380
2381   /* Don't match invisible entries. */
2382   if (PROTO_ITEM_IS_HIDDEN(node))
2383     return;
2384
2385   /* was a free format label produced? */
2386   if (fi->rep) {
2387     label_ptr = fi->rep->representation;
2388   } else {
2389     /* no, make a generic label */
2390     label_ptr = label_str;
2391     proto_item_fill_label(fi, label_str);
2392   }
2393     
2394   /* Does that label match? */
2395   label_len = strlen(label_ptr);
2396   for (i = 0; i < label_len; i++) {
2397     c_char = label_ptr[i];
2398     if (cf->case_type)
2399       c_char = toupper(c_char);
2400     if (c_char == string[c_match]) {
2401       c_match++;
2402       if (c_match == string_len) {
2403         /* No need to look further; we have a match */
2404         mdata->frame_matched = TRUE;
2405         return;
2406       }
2407     } else
2408       c_match = 0;
2409   }
2410   
2411   /* Recurse into the subtree, if it exists */
2412   if (node->first_child != NULL)
2413     proto_tree_children_foreach(node, match_subtree_text, mdata);
2414 }
2415
2416 gboolean
2417 cf_find_packet_summary_line(capture_file *cf, const char *string)
2418 {
2419   match_data            mdata;
2420
2421   mdata.string = string;
2422   mdata.string_len = strlen(string);
2423   return find_packet(cf, match_summary_line, &mdata);
2424 }
2425
2426 static gboolean
2427 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2428 {
2429   match_data            *mdata = criterion;
2430   const gchar           *string = mdata->string;
2431   size_t                string_len = mdata->string_len;
2432   epan_dissect_t        *edt;
2433   const char            *info_column;
2434   size_t                info_column_len;
2435   gboolean              frame_matched = FALSE;
2436   gint                  colx;
2437   guint32               i;
2438   guint8                c_char;
2439   size_t                c_match = 0;
2440
2441   /* Don't bother constructing the protocol tree */
2442   edt = epan_dissect_new(FALSE, FALSE);
2443   /* Get the column information */
2444   epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2445
2446   /* Find the Info column */
2447   for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2448     if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2449       /* Found it.  See if we match. */
2450       info_column = edt->pi.cinfo->col_data[colx];
2451       info_column_len = strlen(info_column);
2452       for (i = 0; i < info_column_len; i++) {
2453         c_char = info_column[i];
2454         if (cf->case_type)
2455           c_char = toupper(c_char);
2456         if (c_char == string[c_match]) {
2457           c_match++;
2458           if (c_match == string_len) {
2459             frame_matched = TRUE;
2460             break;
2461           }
2462         } else
2463           c_match = 0;
2464       }
2465       break;
2466     }
2467   }
2468   epan_dissect_free(edt);
2469   return frame_matched;
2470 }
2471
2472 typedef struct {
2473         const guint8 *data;
2474         size_t data_len;
2475 } cbs_t;        /* "Counted byte string" */
2476
2477 gboolean
2478 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2479 {
2480   cbs_t info;
2481
2482   info.data = string;
2483   info.data_len = string_size;
2484
2485   /* String or hex search? */
2486   if (cf->string) {
2487     /* String search - what type of string? */
2488     switch (cf->scs_type) {
2489
2490     case SCS_ASCII_AND_UNICODE:
2491       return find_packet(cf, match_ascii_and_unicode, &info);
2492
2493     case SCS_ASCII:
2494       return find_packet(cf, match_ascii, &info);
2495
2496     case SCS_UNICODE:
2497       return find_packet(cf, match_unicode, &info);
2498
2499     default:
2500       g_assert_not_reached();
2501       return FALSE;
2502     }
2503   } else
2504     return find_packet(cf, match_binary, &info);
2505 }
2506
2507 static gboolean
2508 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2509 {
2510   cbs_t         *info = criterion;
2511   const char    *ascii_text = info->data;
2512   size_t        textlen = info->data_len;
2513   gboolean      frame_matched;
2514   guint32       buf_len;
2515   guint32       i;
2516   guint8        c_char;
2517   size_t        c_match = 0;
2518
2519   frame_matched = FALSE;
2520   buf_len = fdata->pkt_len;
2521   for (i = 0; i < buf_len; i++) {
2522     c_char = cf->pd[i];
2523     if (cf->case_type)
2524       c_char = toupper(c_char);
2525     if (c_char != 0) {
2526       if (c_char == ascii_text[c_match]) {
2527         c_match++;
2528         if (c_match == textlen) {
2529           frame_matched = TRUE;
2530           break;
2531         }
2532       } else
2533         c_match = 0;
2534     }
2535   }
2536   return frame_matched;
2537 }
2538
2539 static gboolean
2540 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2541 {
2542   cbs_t         *info = criterion;
2543   const char    *ascii_text = info->data;
2544   size_t        textlen = info->data_len;
2545   gboolean      frame_matched;
2546   guint32       buf_len;
2547   guint32       i;
2548   guint8        c_char;
2549   size_t        c_match = 0;
2550
2551   frame_matched = FALSE;
2552   buf_len = fdata->pkt_len;
2553   for (i = 0; i < buf_len; i++) {
2554     c_char = cf->pd[i];
2555     if (cf->case_type)
2556       c_char = toupper(c_char);
2557     if (c_char == ascii_text[c_match]) {
2558       c_match++;
2559       if (c_match == textlen) {
2560         frame_matched = TRUE;
2561         break;
2562       }
2563     } else
2564       c_match = 0;
2565   }
2566   return frame_matched;
2567 }
2568
2569 static gboolean
2570 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2571 {
2572   cbs_t         *info = criterion;
2573   const char    *ascii_text = info->data;
2574   size_t        textlen = info->data_len;
2575   gboolean      frame_matched;
2576   guint32       buf_len;
2577   guint32       i;
2578   guint8        c_char;
2579   size_t        c_match = 0;
2580
2581   frame_matched = FALSE;
2582   buf_len = fdata->pkt_len;
2583   for (i = 0; i < buf_len; i++) {
2584     c_char = cf->pd[i];
2585     if (cf->case_type)
2586       c_char = toupper(c_char);
2587     if (c_char == ascii_text[c_match]) {
2588       c_match++;
2589       i++;
2590       if (c_match == textlen) {
2591         frame_matched = TRUE;
2592         break;
2593       }
2594     } else
2595       c_match = 0;
2596   }
2597   return frame_matched;
2598 }
2599
2600 static gboolean
2601 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2602 {
2603   cbs_t         *info = criterion;
2604   const guint8  *binary_data = info->data;
2605   size_t        datalen = info->data_len;
2606   gboolean      frame_matched;
2607   guint32       buf_len;
2608   guint32       i;
2609   size_t        c_match = 0;
2610
2611   frame_matched = FALSE;
2612   buf_len = fdata->pkt_len;
2613   for (i = 0; i < buf_len; i++) {
2614     if (cf->pd[i] == binary_data[c_match]) {
2615       c_match++;
2616       if (c_match == datalen) {
2617         frame_matched = TRUE;
2618         break;
2619       }
2620     } else
2621       c_match = 0;
2622   }
2623   return frame_matched;
2624 }
2625
2626 gboolean
2627 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2628 {
2629   return find_packet(cf, match_dfilter, sfcode);
2630 }
2631
2632 static gboolean
2633 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2634 {
2635   dfilter_t             *sfcode = criterion;
2636   epan_dissect_t        *edt;
2637   gboolean              frame_matched;
2638
2639   edt = epan_dissect_new(TRUE, FALSE);
2640   epan_dissect_prime_dfilter(edt, sfcode);
2641   epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2642   frame_matched = dfilter_apply_edt(sfcode, edt);
2643   epan_dissect_free(edt);
2644   return frame_matched;
2645 }
2646
2647 static gboolean
2648 find_packet(capture_file *cf,
2649             gboolean (*match_function)(capture_file *, frame_data *, void *),
2650             void *criterion)
2651 {
2652   frame_data *start_fd;
2653   frame_data *fdata;
2654   frame_data *new_fd = NULL;
2655   progdlg_t  *progbar = NULL;
2656   gboolean    stop_flag;
2657   int         count;
2658   int         err;
2659   gchar      *err_info;
2660   int         row;
2661   float       prog_val;
2662   GTimeVal    start_time;
2663   gchar       status_str[100];
2664   int         progbar_nextstep;
2665   int         progbar_quantum;
2666
2667   start_fd = cf->current_frame;
2668   if (start_fd != NULL)  {
2669     /* Iterate through the list of packets, starting at the packet we've
2670        picked, calling a routine to run the filter on the packet, see if
2671        it matches, and stop if so.  */
2672     count = 0;
2673     fdata = start_fd;
2674
2675     progbar_nextstep = 0;
2676     /* When we reach the value that triggers a progress bar update,
2677        bump that value by this amount. */
2678     progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2679
2680     stop_flag = FALSE;
2681     g_get_current_time(&start_time);
2682
2683     fdata = start_fd;
2684     for (;;) {
2685       /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2686          when we update it, we have to run the GTK+ main loop to get it
2687          to repaint what's pending, and doing so may involve an "ioctl()"
2688          to see if there's any pending input from an X server, and doing
2689          that for every packet can be costly, especially on a big file. */
2690       if (count >= progbar_nextstep) {
2691         /* let's not divide by zero. I should never be started
2692          * with count == 0, so let's assert that
2693          */
2694         g_assert(cf->count > 0);
2695
2696         prog_val = (gfloat) count / cf->count;
2697
2698         /* Create the progress bar if necessary */
2699         if (progbar == NULL)
2700            progbar = delayed_create_progress_dlg("Searching", cf->sfilter, 
2701              &stop_flag, &start_time, prog_val);
2702
2703         if (progbar != NULL) {
2704           g_snprintf(status_str, sizeof(status_str),
2705                      "%4u of %u packets", count, cf->count);
2706           update_progress_dlg(progbar, prog_val, status_str);
2707         }
2708
2709         progbar_nextstep += progbar_quantum;
2710       }
2711
2712       if (stop_flag) {
2713         /* Well, the user decided to abort the search.  Go back to the
2714            frame where we started. */
2715         new_fd = start_fd;
2716         break;
2717       }
2718
2719       /* Go past the current frame. */
2720       if (cf->sbackward) {
2721         /* Go on to the previous frame. */
2722         fdata = fdata->prev;
2723         if (fdata == NULL) {
2724           /*
2725            * XXX - other apps have a bit more of a detailed message
2726            * for this, and instead of offering "OK" and "Cancel",
2727            * they offer things such as "Continue" and "Cancel";
2728            * we need an API for popping up alert boxes with
2729            * {Verb} and "Cancel".
2730            */
2731
2732           if (prefs.gui_find_wrap)
2733           {
2734               simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2735                             "%sBeginning of capture exceeded!%s\n\n"
2736                             "Search is continued from the end of the capture.",
2737                             simple_dialog_primary_start(), simple_dialog_primary_end());
2738               fdata = cf->plist_end;    /* wrap around */
2739           }
2740           else
2741           {
2742               simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2743                             "%sBeginning of capture exceeded!%s\n\n"
2744                             "Try searching forwards.",
2745                             simple_dialog_primary_start(), simple_dialog_primary_end());
2746               fdata = start_fd;        /* stay on previous packet */
2747           }
2748         }
2749       } else {
2750         /* Go on to the next frame. */
2751         fdata = fdata->next;
2752         if (fdata == NULL) {
2753           if (prefs.gui_find_wrap)
2754           {
2755               simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2756                             "%sEnd of capture exceeded!%s\n\n"
2757                             "Search is continued from the start of the capture.",
2758                             simple_dialog_primary_start(), simple_dialog_primary_end());
2759               fdata = cf->plist;        /* wrap around */
2760           }
2761           else
2762           {
2763               simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2764                             "%sEnd of capture exceeded!%s\n\n"
2765                             "Try searching backwards.",
2766                             simple_dialog_primary_start(), simple_dialog_primary_end());
2767               fdata = start_fd;     /* stay on previous packet */
2768           }
2769         }
2770       }
2771
2772       count++;
2773
2774       /* Is this packet in the display? */
2775       if (fdata->flags.passed_dfilter) {
2776         /* Yes.  Load its data. */
2777         if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2778                         cf->pd, fdata->cap_len, &err, &err_info)) {
2779           /* Read error.  Report the error, and go back to the frame
2780              where we started. */
2781           simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2782                         cf_read_error_message(err, err_info), cf->filename);
2783           new_fd = start_fd;
2784           break;
2785         }
2786
2787         /* Does it match the search criterion? */
2788         if ((*match_function)(cf, fdata, criterion)) {
2789           new_fd = fdata;
2790           break;        /* found it! */
2791         }
2792       }
2793
2794       if (fdata == start_fd) {
2795         /* We're back to the frame we were on originally, and that frame
2796            doesn't match the search filter.  The search failed. */
2797         break;
2798       }
2799     }
2800
2801     /* We're done scanning the packets; destroy the progress bar if it
2802        was created. */
2803     if (progbar != NULL)
2804       destroy_progress_dlg(progbar);
2805   }
2806
2807   if (new_fd != NULL) {
2808     /* We found a frame.  Find what row it's in. */
2809     row = packet_list_find_row_from_data(new_fd);
2810     g_assert(row != -1);
2811
2812     /* Select that row, make it the focus row, and make it visible. */
2813     packet_list_set_selected_row(row);
2814     return TRUE;        /* success */
2815   } else
2816     return FALSE;       /* failure */
2817 }
2818
2819 gboolean
2820 cf_goto_frame(capture_file *cf, guint fnumber)
2821 {
2822   frame_data *fdata;
2823   int row;
2824
2825   for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2826     ;
2827
2828   if (fdata == NULL) {
2829     /* we didn't find a packet with that packet number */
2830     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2831                   "There is no packet with the packet number %u.", fnumber);
2832     return FALSE;       /* we failed to go to that packet */
2833   }
2834   if (!fdata->flags.passed_dfilter) {
2835     /* that packet currently isn't displayed */
2836     /* XXX - add it to the set of displayed packets? */
2837     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2838                   "The packet number %u isn't currently being displayed.", fnumber);
2839     return FALSE;       /* we failed to go to that packet */
2840   }
2841
2842   /* We found that packet, and it's currently being displayed.
2843      Find what row it's in. */
2844   row = packet_list_find_row_from_data(fdata);
2845   g_assert(row != -1);
2846
2847   /* Select that row, make it the focus row, and make it visible. */
2848   packet_list_set_selected_row(row);
2849   return TRUE;  /* we got to that packet */
2850 }
2851
2852 gboolean
2853 cf_goto_top_frame(capture_file *cf)
2854 {
2855   frame_data *fdata;
2856   int row;
2857   frame_data *lowest_fdata = NULL;
2858
2859   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2860     if (fdata->flags.passed_dfilter) {
2861         lowest_fdata = fdata;
2862         break;
2863     }
2864   }
2865
2866   if (lowest_fdata == NULL) {
2867       return FALSE;
2868   }
2869
2870   /* We found that packet, and it's currently being displayed.
2871      Find what row it's in. */
2872   row = packet_list_find_row_from_data(lowest_fdata);
2873   g_assert(row != -1);
2874
2875   /* Select that row, make it the focus row, and make it visible. */
2876   packet_list_set_selected_row(row);
2877   return TRUE;  /* we got to that packet */
2878 }
2879
2880 gboolean
2881 cf_goto_bottom_frame(capture_file *cf)
2882 {
2883   frame_data *fdata;
2884   int row;
2885   frame_data *highest_fdata = NULL;
2886
2887   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2888     if (fdata->flags.passed_dfilter) {
2889         highest_fdata = fdata;
2890     }
2891   }
2892
2893   if (highest_fdata == NULL) {
2894       return FALSE;
2895   }
2896
2897   /* We found that packet, and it's currently being displayed.
2898      Find what row it's in. */
2899   row = packet_list_find_row_from_data(highest_fdata);
2900   g_assert(row != -1);
2901
2902   /* Select that row, make it the focus row, and make it visible. */
2903   packet_list_set_selected_row(row);
2904   return TRUE;  /* we got to that packet */
2905 }
2906
2907 /*
2908  * Go to frame specified by currently selected protocol tree item.
2909  */
2910 gboolean
2911 cf_goto_framenum(capture_file *cf)
2912 {
2913   header_field_info       *hfinfo;
2914   guint32                 framenum;
2915
2916   if (cf->finfo_selected) {
2917     hfinfo = cf->finfo_selected->hfinfo;
2918     g_assert(hfinfo);
2919     if (hfinfo->type == FT_FRAMENUM) {
2920       framenum = fvalue_get_integer(&cf->finfo_selected->value);
2921       if (framenum != 0)
2922         return cf_goto_frame(cf, framenum);
2923       }
2924   }
2925
2926   return FALSE;
2927 }
2928
2929 /* Select the packet on a given row. */
2930 void
2931 cf_select_packet(capture_file *cf, int row)
2932 {
2933   frame_data *fdata;
2934   int err;
2935   gchar *err_info;
2936
2937   /* Get the frame data struct pointer for this frame */
2938   fdata = (frame_data *)packet_list_get_row_data(row);
2939
2940   if (fdata == NULL) {
2941     /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
2942        the first entry is added to it by "real_insert_row()", that row
2943        is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
2944        our version and the vanilla GTK+ version).
2945
2946        This means that a "select-row" signal is emitted; this causes
2947        "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
2948        to be called.
2949
2950        "cf_select_packet()" fetches, above, the data associated with the
2951        row that was selected; however, as "gtk_clist_append()", which
2952        called "real_insert_row()", hasn't yet returned, we haven't yet
2953        associated any data with that row, so we get back a null pointer.
2954
2955        We can't assume that there's only one frame in the frame list,
2956        either, as we may be filtering the display.
2957
2958        We therefore assume that, if "row" is 0, i.e. the first row
2959        is being selected, and "cf->first_displayed" equals
2960        "cf->last_displayed", i.e. there's only one frame being
2961        displayed, that frame is the frame we want.
2962
2963        This means we have to set "cf->first_displayed" and
2964        "cf->last_displayed" before adding the row to the
2965        GtkCList; see the comment in "add_packet_to_packet_list()". */
2966
2967        if (row == 0 && cf->first_displayed == cf->last_displayed)
2968          fdata = cf->first_displayed;
2969   }
2970
2971   /* Get the data in that frame. */
2972   if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
2973                        cf->pd, fdata->cap_len, &err, &err_info)) {
2974     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2975                   cf_read_error_message(err, err_info), cf->filename);
2976     return;
2977   }
2978
2979   /* Record that this frame is the current frame. */
2980   cf->current_frame = fdata;
2981
2982   /* Create the logical protocol tree. */
2983   if (cf->edt != NULL) {
2984     epan_dissect_free(cf->edt);
2985     cf->edt = NULL;
2986   }
2987   /* We don't need the columns here. */
2988   cf->edt = epan_dissect_new(TRUE, TRUE);
2989   epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
2990           NULL);
2991
2992   cf_callback_invoke(cf_cb_packet_selected, cf);
2993 }
2994
2995 /* Unselect the selected packet, if any. */
2996 void
2997 cf_unselect_packet(capture_file *cf)
2998 {
2999   /* Destroy the epan_dissect_t for the unselected packet. */
3000   if (cf->edt != NULL) {
3001     epan_dissect_free(cf->edt);
3002     cf->edt = NULL;
3003   }
3004
3005   /* No packet is selected. */
3006   cf->current_frame = NULL;
3007
3008   cf_callback_invoke(cf_cb_packet_unselected, cf);
3009
3010   /* No protocol tree means no selected field. */
3011   cf_unselect_field(cf);
3012 }
3013
3014 /* Unset the selected protocol tree field, if any. */
3015 void
3016 cf_unselect_field(capture_file *cf)
3017 {
3018   cf->finfo_selected = NULL;
3019
3020   cf_callback_invoke(cf_cb_field_unselected, cf);
3021 }
3022
3023 /*
3024  * Mark a particular frame.
3025  */
3026 void
3027 cf_mark_frame(capture_file *cf, frame_data *frame)
3028 {
3029   if (! frame->flags.marked) {
3030     frame->flags.marked = TRUE;
3031     if (cf->count > cf->marked_count)
3032       cf->marked_count++;
3033   }
3034 }
3035
3036 /*
3037  * Unmark a particular frame.
3038  */
3039 void
3040 cf_unmark_frame(capture_file *cf, frame_data *frame)
3041 {
3042   if (frame->flags.marked) {
3043     frame->flags.marked = FALSE;
3044     if (cf->marked_count > 0)
3045       cf->marked_count--;
3046   }
3047 }
3048
3049 typedef struct {
3050   wtap_dumper *pdh;
3051   const char  *fname;
3052 } save_callback_args_t;
3053
3054 /*
3055  * Save a capture to a file, in a particular format, saving either
3056  * all packets, all currently-displayed packets, or all marked packets.
3057  *
3058  * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3059  * up a message box for the failure.
3060  */
3061 static gboolean
3062 save_packet(capture_file *cf _U_, frame_data *fdata,
3063             union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3064             void *argsp)
3065 {
3066   save_callback_args_t *args = argsp;
3067   struct wtap_pkthdr hdr;
3068   int           err;
3069
3070   /* init the wtap header for saving */
3071   hdr.ts         = *(struct wtap_nstime *) &fdata->abs_ts;
3072   hdr.caplen     = fdata->cap_len;
3073   hdr.len        = fdata->pkt_len;
3074   hdr.pkt_encap  = fdata->lnk_t;
3075
3076   /* and save the packet */
3077   if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3078     cf_write_failure_alert_box(args->fname, err);
3079     return FALSE;
3080   }
3081   return TRUE;
3082 }
3083
3084 cf_status_t
3085 cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed)
3086 {
3087   gchar        *from_filename;
3088   int           err;
3089   gboolean      do_copy;
3090   wtap_dumper  *pdh;
3091   save_callback_args_t callback_args;
3092
3093   cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname);
3094
3095   /* don't write over an existing file. */
3096   /* this should've been already checked by our caller, just to be sure... */
3097   if (file_exists(fname)) {
3098     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3099       "%sCapture file: \"%s\" already exists!%s\n\n"
3100       "Please choose a different filename.",
3101       simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3102     goto fail;
3103   }
3104
3105   packet_range_process_init(range);
3106
3107   /* Used to be :
3108    * if (!save_filtered && !save_marked && !save_manual_range && 
3109    *     !save_marked_range && !save_curr && save_format == cf->cd_t) {
3110    */ 
3111         
3112   if (packet_range_process_all(range) && save_format == cf->cd_t) {
3113     /* We're not filtering packets, and we're saving it in the format
3114        it's already in, so we can just move or copy the raw data. */
3115
3116     if (cf->is_tempfile) {
3117       /* The file being saved is a temporary file from a live
3118          capture, so it doesn't need to stay around under that name;
3119          first, try renaming the capture buffer file to the new name. */
3120 #ifndef _WIN32
3121       if (rename(cf->filename, fname) == 0) {
3122         /* That succeeded - there's no need to copy the source file. */
3123         from_filename = NULL;
3124         do_copy = FALSE;
3125       } else {
3126         if (errno == EXDEV) {
3127           /* They're on different file systems, so we have to copy the
3128              file. */
3129           do_copy = TRUE;
3130           from_filename = cf->filename;
3131         } else {
3132           /* The rename failed, but not because they're on different
3133              file systems - put up an error message.  (Or should we
3134              just punt and try to copy?  The only reason why I'd
3135              expect the rename to fail and the copy to succeed would
3136              be if we didn't have permission to remove the file from
3137              the temporary directory, and that might be fixable - but
3138              is it worth requiring the user to go off and fix it?) */
3139           simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3140                                 file_rename_error_message(errno), fname);
3141           goto fail;
3142         }
3143       }
3144 #else
3145       do_copy = TRUE;
3146       from_filename = cf->filename;
3147 #endif
3148     } else {
3149       /* It's a permanent file, so we should copy it, and not remove the
3150          original. */
3151       do_copy = TRUE;
3152       from_filename = cf->filename;
3153     }
3154
3155     if (do_copy) {
3156       /* Copy the file, if we haven't moved it. */
3157       if (!copy_binary_file(from_filename, fname))
3158         goto fail;
3159     }
3160   } else {
3161     /* Either we're filtering packets, or we're saving in a different
3162        format; we can't do that by copying or moving the capture file,
3163        we have to do it by writing the packets out in Wiretap. */
3164     pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, 
3165                 compressed, &err);
3166     if (pdh == NULL) {
3167       cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3168       goto fail;
3169     }
3170
3171     /* XXX - we let the user save a subset of the packets.
3172
3173        If we do that, should we make that file the current file?  If so,
3174        it means we can no longer get at the other packets.  What does
3175        NetMon do? */
3176
3177     /* Iterate through the list of packets, processing the packets we were
3178        told to process.
3179
3180        XXX - we've already called "packet_range_process_init(range)", but
3181        "process_specified_packets()" will do it again.  Fortunately,
3182        that's harmless in this case, as we haven't done anything to
3183        "range" since we initialized it. */
3184     callback_args.pdh = pdh;
3185     callback_args.fname = fname;
3186     switch (process_specified_packets(cf, range, "Saving",
3187                                       "selected packets", save_packet,
3188                                       &callback_args)) {
3189
3190     case PSP_FINISHED:
3191       /* Completed successfully. */
3192       break;
3193
3194     case PSP_STOPPED:
3195       /* The user decided to abort the saving.
3196          XXX - remove the output file? */
3197       break;
3198
3199     case PSP_FAILED:
3200       /* Error while saving. */
3201       wtap_dump_close(pdh, &err);
3202       goto fail;
3203     }
3204
3205     if (!wtap_dump_close(pdh, &err)) {
3206       cf_close_failure_alert_box(fname, err);
3207       goto fail;
3208     }
3209   }
3210
3211   cf_callback_invoke(cf_cb_file_safe_finished, NULL);
3212
3213   if (packet_range_process_all(range)) {
3214     /* We saved the entire capture, not just some packets from it.
3215        Open and read the file we saved it to.
3216
3217        XXX - this is somewhat of a waste; we already have the
3218        packets, all this gets us is updated file type information
3219        (which we could just stuff into "cf"), and having the new
3220        file be the one we have opened and from which we're reading
3221        the data, and it means we have to spend time opening and
3222        reading the file, which could be a significant amount of
3223        time if the file is large. */
3224     cf->user_saved = TRUE;
3225
3226     if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
3227       /* XXX - report errors if this fails?
3228          What should we return if it fails or is aborted? */
3229       switch (cf_read(cf)) {
3230
3231       case CF_READ_OK:
3232       case CF_READ_ERROR:
3233         /* Just because we got an error, that doesn't mean we were unable
3234            to read any of the file; we handle what we could get from the
3235            file. */
3236         break;
3237
3238       case CF_READ_ABORTED:
3239         /* The user bailed out of re-reading the capture file; the
3240            capture file has been closed - just return (without
3241            changing any menu settings; "cf_close()" set them
3242            correctly for the "no capture file open" state). */
3243         break;
3244       }
3245       cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL);
3246     }
3247   }
3248   return CF_OK;
3249
3250 fail:
3251   cf_callback_invoke(cf_cb_file_safe_failed, NULL);
3252   return CF_ERROR;
3253 }
3254
3255 static void
3256 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3257                           gboolean for_writing, int file_type)
3258 {
3259   if (err < 0) {
3260     /* Wiretap error. */
3261     switch (err) {
3262
3263     case WTAP_ERR_NOT_REGULAR_FILE:
3264       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3265                     "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3266                     filename);
3267       break;
3268
3269     case WTAP_ERR_RANDOM_OPEN_PIPE:
3270       /* Seen only when opening a capture file for reading. */
3271       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3272                     "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
3273                     filename);
3274       break;
3275
3276     case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3277       /* Seen only when opening a capture file for reading. */
3278       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3279                     "The file \"%s\" isn't a capture file in a format Ethereal understands.",
3280                     filename);
3281       break;
3282
3283     case WTAP_ERR_UNSUPPORTED:
3284       /* Seen only when opening a capture file for reading. */
3285       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3286                     "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
3287                     "(%s)",
3288                     filename, err_info);
3289       g_free(err_info);
3290       break;
3291
3292     case WTAP_ERR_CANT_WRITE_TO_PIPE:
3293       /* Seen only when opening a capture file for writing. */
3294       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3295                     "The file \"%s\" is a pipe, and %s capture files can't be "
3296                     "written to a pipe.",
3297                     filename, wtap_file_type_string(file_type));
3298       break;
3299
3300     case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3301       /* Seen only when opening a capture file for writing. */
3302       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3303                     "Ethereal doesn't support writing capture files in that format.");
3304       break;
3305
3306     case WTAP_ERR_UNSUPPORTED_ENCAP:
3307       if (for_writing) {
3308         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3309                       "Ethereal can't save this capture in that format.");
3310       } else {
3311         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3312                       "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
3313                       "(%s)",
3314                       filename, err_info);
3315         g_free(err_info);
3316       }
3317       break;
3318
3319     case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3320       if (for_writing) {
3321         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3322                       "Ethereal can't save this capture in that format.");
3323       } else {
3324         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3325                       "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3326                       filename);
3327       }
3328       break;
3329
3330     case WTAP_ERR_BAD_RECORD:
3331       /* Seen only when opening a capture file for reading. */
3332       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3333                     "The file \"%s\" appears to be damaged or corrupt.\n"
3334                     "(%s)",
3335                     filename, err_info);
3336       g_free(err_info);
3337       break;
3338
3339     case WTAP_ERR_CANT_OPEN:
3340       if (for_writing) {
3341         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3342                       "The file \"%s\" could not be created for some unknown reason.",
3343                       filename);
3344       } else {
3345         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3346                       "The file \"%s\" could not be opened for some unknown reason.",
3347                       filename);
3348       }
3349       break;
3350
3351     case WTAP_ERR_SHORT_READ:
3352       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3353                     "The file \"%s\" appears to have been cut short"
3354                     " in the middle of a packet or other data.",
3355                     filename);
3356       break;
3357
3358     case WTAP_ERR_SHORT_WRITE:
3359       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3360                     "A full header couldn't be written to the file \"%s\".",
3361                     filename);
3362       break;
3363
3364     case WTAP_ERR_COMPRESSION_NOT_SUPPORTED:
3365       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3366                     "Gzip compression not supported by this file type.");
3367       break;
3368
3369     default:
3370       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3371                     "The file \"%s\" could not be %s: %s.",
3372                     filename,
3373                     for_writing ? "created" : "opened",
3374                     wtap_strerror(err));
3375       break;
3376     }
3377   } else {
3378     /* OS error. */
3379     open_failure_alert_box(filename, err, for_writing);
3380   }
3381 }
3382
3383 static const char *
3384 file_rename_error_message(int err)
3385 {
3386   const char *errmsg;
3387   static char errmsg_errno[1024+1];
3388
3389   switch (err) {
3390
3391   case ENOENT:
3392     errmsg = "The path to the file \"%s\" doesn't exist.";
3393     break;
3394
3395   case EACCES:
3396     errmsg = "You don't have permission to move the capture file to \"%s\".";
3397     break;
3398
3399   default:
3400     g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3401                     "The file \"%%s\" could not be moved: %s.",
3402                                 wtap_strerror(err));
3403     errmsg = errmsg_errno;
3404     break;
3405   }
3406   return errmsg;
3407 }
3408
3409 char *
3410 cf_read_error_message(int err, const gchar *err_info)
3411 {
3412   static char errmsg_errno[1024+1];
3413
3414   switch (err) {
3415
3416   case WTAP_ERR_UNSUPPORTED_ENCAP:
3417       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3418                "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3419                err_info);
3420       break;
3421
3422   case WTAP_ERR_BAD_RECORD:
3423     g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3424              "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3425              wtap_strerror(err), err_info);
3426     break;
3427
3428   default:
3429     g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3430              "An error occurred while reading from the file \"%%s\": %s.",
3431              wtap_strerror(err));
3432     break;
3433   }
3434   return errmsg_errno;
3435 }
3436
3437 static void
3438 cf_write_failure_alert_box(const char *filename, int err)
3439 {
3440   if (err < 0) {
3441     /* Wiretap error. */
3442     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3443                   "An error occurred while writing to the file \"%s\": %s.",
3444                   filename, wtap_strerror(err));
3445   } else {
3446     /* OS error. */
3447     write_failure_alert_box(filename, err);
3448   }
3449 }
3450
3451 /* Check for write errors - if the file is being written to an NFS server,
3452    a write error may not show up until the file is closed, as NFS clients
3453    might not send writes to the server until the "write()" call finishes,
3454    so that the write may fail on the server but the "write()" may succeed. */
3455 static void
3456 cf_close_failure_alert_box(const char *filename, int err)
3457 {
3458   if (err < 0) {
3459     /* Wiretap error. */
3460     switch (err) {
3461
3462     case WTAP_ERR_CANT_CLOSE:
3463       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3464                     "The file \"%s\" couldn't be closed for some unknown reason.",
3465                     filename);
3466       break;
3467
3468     case WTAP_ERR_SHORT_WRITE:
3469       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3470                     "Not all the packets could be written to the file \"%s\".",
3471                     filename);
3472       break;
3473
3474     default:
3475       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3476                     "An error occurred while closing the file \"%s\": %s.",
3477                     filename, wtap_strerror(err));
3478       break;
3479     }
3480   } else {
3481     /* OS error.
3482        We assume that a close error from the OS is really a write error. */
3483     write_failure_alert_box(filename, err);
3484   }
3485 }
3486
3487 /* Reload the current capture file. */
3488 void
3489 cf_reload(capture_file *cf) {
3490   gchar *filename;
3491   gboolean is_tempfile;
3492   int err;
3493
3494   /* If the file could be opened, "cf_open()" calls "cf_close()"
3495      to get rid of state for the old capture file before filling in state
3496      for the new capture file.  "cf_close()" will remove the file if
3497      it's a temporary file; we don't want that to happen (for one thing,
3498      it'd prevent subsequent reopens from working).  Remember whether it's
3499      a temporary file, mark it as not being a temporary file, and then
3500      reopen it as the type of file it was.
3501
3502      Also, "cf_close()" will free "cf->filename", so we must make
3503      a copy of it first. */
3504   filename = g_strdup(cf->filename);
3505   is_tempfile = cf->is_tempfile;
3506   cf->is_tempfile = FALSE;
3507   if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
3508     switch (cf_read(cf)) {
3509
3510     case CF_READ_OK:
3511     case CF_READ_ERROR:
3512       /* Just because we got an error, that doesn't mean we were unable
3513          to read any of the file; we handle what we could get from the
3514          file. */
3515       break;
3516
3517     case CF_READ_ABORTED:
3518       /* The user bailed out of re-reading the capture file; the
3519          capture file has been closed - just free the capture file name
3520          string and return (without changing the last containing
3521          directory). */
3522       g_free(filename);
3523       return;
3524     }
3525   } else {
3526     /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
3527        Instead, the file was left open, so we should restore "cf->is_tempfile"
3528        ourselves.
3529
3530        XXX - change the menu?  Presumably "cf_open()" will do that;
3531        make sure it does! */
3532     cf->is_tempfile = is_tempfile;
3533   }
3534   /* "cf_open()" made a copy of the file name we handed it, so
3535      we should free up our copy. */
3536   g_free(filename);
3537 }
3538
3539 /* Copies a file in binary mode, for those operating systems that care about
3540  * such things.
3541  * Returns TRUE on success, FALSE on failure. If a failure, it also
3542  * displays a simple dialog window with the error message.
3543  */
3544 static gboolean
3545 copy_binary_file(const char *from_filename, const char *to_filename)
3546 {
3547   int           from_fd, to_fd, nread, nwritten, err;
3548   guint8        pd[65536];
3549
3550   /* Copy the raw bytes of the file. */
3551   from_fd = open(from_filename, O_RDONLY | O_BINARY);
3552   if (from_fd < 0) {
3553     open_failure_alert_box(from_filename, errno, FALSE);
3554     goto done;
3555   }
3556
3557   /* Use open() instead of creat() so that we can pass the O_BINARY
3558      flag, which is relevant on Win32; it appears that "creat()"
3559      may open the file in text mode, not binary mode, but we want
3560      to copy the raw bytes of the file, so we need the output file
3561      to be open in binary mode. */
3562   to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3563   if (to_fd < 0) {
3564     open_failure_alert_box(to_filename, errno, TRUE);
3565     close(from_fd);
3566     goto done;
3567   }
3568
3569   while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3570     nwritten = write(to_fd, pd, nread);
3571     if (nwritten < nread) {
3572       if (nwritten < 0)
3573         err = errno;
3574       else
3575         err = WTAP_ERR_SHORT_WRITE;
3576       write_failure_alert_box(to_filename, err);
3577       close(from_fd);
3578       close(to_fd);
3579       goto done;
3580     }
3581   }
3582   if (nread < 0) {
3583     err = errno;
3584     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3585                   "An error occurred while reading from the file \"%s\": %s.",
3586                   from_filename, strerror(err));
3587     close(from_fd);
3588     close(to_fd);
3589     goto done;
3590   }
3591   close(from_fd);
3592   if (close(to_fd) < 0) {
3593     write_failure_alert_box(to_filename, errno);
3594     goto done;
3595   }
3596
3597   return TRUE;
3598
3599 done:
3600   return FALSE;
3601 }