The packet range stuff knows about capture_file structures, so it's
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 2de8633f7fc564c11215ffbb1760242c68d18c84..f4f2decf3fe7f9511e0e5585198dd81461b6c885 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.388 2004/07/08 10:36:26 guy Exp $
+ * $Id$
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include <epan/filesystem.h>
 
 #include "color.h"
+#include "color_filters.h"
 #include "column.h"
 #include <epan/packet.h>
-#include "range.h"
+#include "packet-range.h"
 #include "print.h"
 #include "file.h"
 #include "menu.h"
@@ -86,7 +87,7 @@
 #include <epan/epan_dissect.h>
 #include "tap.h"
 #include "tap_dfilter_dlg.h"
-#include "packet-data.h"
+#include <epan/dissectors/packet-data.h>
 
 /* Win32 needs the O_BINARY flag for open() */
 #ifndef O_BINARY
@@ -1494,7 +1495,6 @@ retap_packets(capture_file *cf)
 
 typedef struct {
   print_args_t *print_args;
-  FILE         *print_fh;
   gboolean      print_header_line;
   char         *header_line_buf;
   int           header_line_buf_len;
@@ -1518,29 +1518,44 @@ print_packet(capture_file *cf, frame_data *fdata,
   int             column_len;
   int             cp_off;
   gboolean        proto_tree_needed;
+  char            bookmark_name[9+10+1];       /* "__frameNNNNNNNNNN__\0" */
+  char            bookmark_title[6+10+1];      /* "Frame NNNNNNNNNN__\0" */
 
-  /* Create the protocol tree if we're printing the dissection or the hex
-     data. */
+  /* Create the protocol tree, and make it visible, if we're printing
+     the dissection or the hex data.
+     XXX - do we need it if we're just printing the hex data? */
   proto_tree_needed = 
       args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
-
-  /* Fill in the column information.
-     XXX - do we need to do so if we're not printing it? */
   edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
-  epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
-  epan_dissect_fill_in_columns(edt);
+
+  /* Fill in the column information if we're printing the summary
+     information. */
+  if (args->print_args->print_summary) {
+    epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
+    epan_dissect_fill_in_columns(edt);
+  } else
+    epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
 
   if (args->print_formfeed) {
-    print_formfeed(args->print_fh, args->print_args->format);
+    if (!new_page(args->print_args->stream))
+      goto fail;
   } else {
-      if (args->print_separator)
-        print_line(args->print_fh, 0, args->print_args->format, "");
+      if (args->print_separator) {
+        if (!print_line(args->print_args->stream, 0, ""))
+          goto fail;
+      }
   }
 
-  if (args->print_args->print_summary || args->print_args->format == PR_FMT_PS) {
+  /*
+   * We generate bookmarks, if the output format supports them.
+   * The name is "__frameN__".
+   */
+  sprintf(bookmark_name, "__frame%u__", fdata->num);
+
+  if (args->print_args->print_summary) {
     if (args->print_header_line) {
-      print_line(args->print_fh, 0, args->print_args->format,
-                 args->header_line_buf);
+      if (!print_line(args->print_args->stream, 0, args->header_line_buf))
+        goto fail;
       args->print_header_line = FALSE; /* we might not need to print any more */
     }
     cp = &args->line_buf[0];
@@ -1572,21 +1587,36 @@ print_packet(capture_file *cf, frame_data *fdata,
     }
     *cp = '\0';
 
-    print_packet_header(args->print_fh, args->print_args->format, fdata->num, args->line_buf);
+    /*
+     * Generate a bookmark, using the summary line as the title.
+     */
+    if (!print_bookmark(args->print_args->stream, bookmark_name,
+                        args->line_buf))
+      goto fail;
 
-    if (args->print_args->print_summary) {
-        print_line(args->print_fh, 0, args->print_args->format, args->line_buf);
-    }
+    if (!print_line(args->print_args->stream, 0, args->line_buf))
+      goto fail;
+  } else {
+    /*
+     * Generate a bookmark, using "Frame N" as the title, as we're not
+     * printing the summary line.
+     */
+    sprintf(bookmark_title, "Frame %u", fdata->num);
+    if (!print_bookmark(args->print_args->stream, bookmark_name,
+                        bookmark_title))
+      goto fail;
   } /* if (print_summary) */
-  
+
   if (args->print_args->print_dissections != print_dissections_none) {
     if (args->print_args->print_summary) {
       /* Separate the summary line from the tree with a blank line. */
-      print_line(args->print_fh, 0, args->print_args->format, "");
+      if (!print_line(args->print_args->stream, 0, ""))
+        goto fail;
     }
 
     /* Print the information in that tree. */
-    proto_tree_print(args->print_args, edt, args->print_fh);
+    if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
+      goto fail;
 
     /* Print a blank line if we print anything after this (aka more than one packet). */
     args->print_separator = TRUE;
@@ -1597,14 +1627,15 @@ print_packet(capture_file *cf, frame_data *fdata,
 
   if (args->print_args->print_hex) {
     /* Print the full packet data as hex. */
-    print_hex_data(args->print_fh, args->print_args->format, edt);
+    if (!print_hex_data(args->print_args->stream, edt))
+      goto fail;
 
     /* Print a blank line if we print anything after this (aka more than one packet). */
     args->print_separator = TRUE;
 
     /* Print a header line if we print any more packet summaries */
     args->print_header_line = TRUE;
-  } /* if (print_summary) */
+  } /* if (args->print_args->print_dissections != print_dissections_none) */
 
   epan_dissect_free(edt);
 
@@ -1613,7 +1644,11 @@ print_packet(capture_file *cf, frame_data *fdata,
     args->print_formfeed = TRUE;
   }
 
-  return !ferror(args->print_fh);
+  return TRUE;
+
+fail:
+  epan_dissect_free(edt);
+  return FALSE;
 }
 
 pp_return_t
@@ -1628,22 +1663,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
   int         line_len;
   psp_return_t ret;
 
-  if(print_args->to_file) {
-      callback_args.print_fh = open_print_dest(print_args->to_file,
-                                               print_args->file);
-  } else {
-      callback_args.print_fh = open_print_dest(print_args->to_file,
-                                               print_args->cmd);
-  }
-  if (callback_args.print_fh == NULL)
-    return PP_OPEN_ERROR;      /* attempt to open destination failed */
-
-  print_preamble(callback_args.print_fh, print_args->format, cf->filename);
-  if (ferror(callback_args.print_fh)) {
-    close_print_dest(print_args->to_file, callback_args.print_fh);
-    return PP_WRITE_ERROR;
-  }
-
   callback_args.print_args = print_args;
   callback_args.print_header_line = TRUE;
   callback_args.header_line_buf = NULL;
@@ -1653,7 +1672,13 @@ print_packets(capture_file *cf, print_args_t *print_args)
   callback_args.line_buf = NULL;
   callback_args.line_buf_len = 256;
   callback_args.col_widths = NULL;
-  if (print_args->print_summary || print_args->format == PR_FMT_PS) {
+
+  if (!print_preamble(print_args->stream, cf->filename)) {
+    destroy_print_stream(print_args->stream);
+    return PP_WRITE_ERROR;
+  }
+
+  if (print_args->print_summary) {
     /* We're printing packet summaries.  Allocate the header line buffer
        and get the column widths. */
     callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
@@ -1743,18 +1768,17 @@ print_packets(capture_file *cf, print_args_t *print_args)
        will get printed if we're piping to a print program; we'd
        have to write to a file and then hand that to the print
        program to make it actually not print anything. */
-    close_print_dest(print_args->to_file, callback_args.print_fh);
+    destroy_print_stream(print_args->stream);
     return PP_WRITE_ERROR;
   }
 
-  print_finale(callback_args.print_fh, print_args->format);
-  if (ferror(callback_args.print_fh)) {
-    close_print_dest(print_args->to_file, callback_args.print_fh);
+  if (!print_finale(print_args->stream)) {
+    destroy_print_stream(print_args->stream);
     return PP_WRITE_ERROR;
   }
 
-  /* XXX - check for an error */
-  close_print_dest(print_args->to_file, callback_args.print_fh);
+  if (!destroy_print_stream(print_args->stream))
+    return PP_WRITE_ERROR;
 
   return PP_OK;
 }
@@ -2467,21 +2491,44 @@ find_packet(capture_file *cf,
            * we need an API for popping up alert boxes with
            * {Verb} and "Cancel".
            */
-          simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                        "%sBeginning of capture exceeded!%s\n\n"
-                        "Search is continued from the end of the capture.",
-                        simple_dialog_primary_start(), simple_dialog_primary_end());
-          fdata = cf->plist_end;       /* wrap around */
+
+          if (prefs.gui_find_wrap)
+          {
+              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+                            "%sBeginning of capture exceeded!%s\n\n"
+                            "Search is continued from the end of the capture.",
+                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              fdata = cf->plist_end;   /* wrap around */
+          }
+          else
+          {
+              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+                            "%sBeginning of capture exceeded!%s\n\n"
+                            "Try searching forwards.",
+                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              fdata = start_fd;        /* stay on previous packet */
+          }
         }
       } else {
         /* Go on to the next frame. */
         fdata = fdata->next;
         if (fdata == NULL) {
-          simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                        "%sEnd of capture exceeded!%s\n\n"
-                        "Search is continued from the start of the capture.",
-                        simple_dialog_primary_start(), simple_dialog_primary_end());
-          fdata = cf->plist;   /* wrap around */
+          if (prefs.gui_find_wrap)
+          {
+              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+                            "%sEnd of capture exceeded!%s\n\n"
+                            "Search is continued from the start of the capture.",
+                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              fdata = cf->plist;       /* wrap around */
+          }
+          else
+          {
+              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+                            "%sEnd of capture exceeded!%s\n\n"
+                            "Try searching backwards.",
+                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              fdata = start_fd;     /* stay on previous packet */
+          }
         }
       }
 
@@ -2620,6 +2667,26 @@ goto_bottom_frame(capture_file *cf)
   return TRUE; /* we got to that packet */
 }
 
+/*
+ * Go to frame specified by currently selected protocol tree item.
+ */
+void
+goto_framenum(capture_file *cf)
+{
+  header_field_info       *hfinfo;
+  guint32                 framenum;
+
+  if (cf->finfo_selected) {
+    hfinfo = cf->finfo_selected->hfinfo;
+    g_assert(hfinfo);
+    if (hfinfo->type == FT_FRAMENUM) {
+      framenum = fvalue_get_integer(&cf->finfo_selected->value);
+      if (framenum != 0)
+        goto_frame(cf, framenum);
+      }
+  }
+}
+
 /* Select the packet on a given row. */
 void
 select_packet(capture_file *cf, int row)
@@ -2729,8 +2796,11 @@ unselect_field(capture_file *cf)
 void
 mark_frame(capture_file *cf, frame_data *frame)
 {
-  frame->flags.marked = TRUE;
-  cf->marked_count++;
+  if (! frame->flags.marked) {
+    frame->flags.marked = TRUE;
+    if (cf->count > cf->marked_count)
+      cf->marked_count++;
+  }
 }
 
 /*
@@ -2739,8 +2809,11 @@ mark_frame(capture_file *cf, frame_data *frame)
 void
 unmark_frame(capture_file *cf, frame_data *frame)
 {
-  frame->flags.marked = FALSE;
-  cf->marked_count--;
+  if (frame->flags.marked) {
+    frame->flags.marked = FALSE;
+    if (cf->marked_count > 0)
+      cf->marked_count--;
+  }
 }
 
 typedef struct {
@@ -3200,6 +3273,56 @@ cf_close_failure_alert_box(const char *filename, int err)
   }
 }
 
+/* Reload the current capture file. */
+void
+cf_reload() {
+  gchar *filename;
+  gboolean is_tempfile;
+
+  /* If the file could be opened, "cf_open()" calls "cf_close()"
+     to get rid of state for the old capture file before filling in state
+     for the new capture file.  "cf_close()" will remove the file if
+     it's a temporary file; we don't want that to happen (for one thing,
+     it'd prevent subsequent reopens from working).  Remember whether it's
+     a temporary file, mark it as not being a temporary file, and then
+     reopen it as the type of file it was.
+
+     Also, "cf_close()" will free "cfile.filename", so we must make
+     a copy of it first. */
+  filename = g_strdup(cfile.filename);
+  is_tempfile = cfile.is_tempfile;
+  cfile.is_tempfile = FALSE;
+  if (cf_open(filename, is_tempfile, &cfile) == 0) {
+    switch (cf_read(&cfile)) {
+
+    case READ_SUCCESS:
+    case READ_ERROR:
+      /* Just because we got an error, that doesn't mean we were unable
+         to read any of the file; we handle what we could get from the
+         file. */
+      break;
+
+    case READ_ABORTED:
+      /* The user bailed out of re-reading the capture file; the
+         capture file has been closed - just free the capture file name
+         string and return (without changing the last containing
+         directory). */
+      g_free(filename);
+      return;
+    }
+  } else {
+    /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
+       Instead, the file was left open, so we should restore "cfile.is_tempfile"
+       ourselves.
+
+       XXX - change the menu?  Presumably "cf_open()" will do that;
+       make sure it does! */
+    cfile.is_tempfile = is_tempfile;
+  }
+  /* "cf_open()" made a copy of the file name we handed it, so
+     we should free up our copy. */
+  g_free(filename);
+}
 
 /* Copies a file in binary mode, for those operating systems that care about
  * such things.