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