/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.14 1998/12/17 05:42:23 gram Exp $
+ * $Id: file.c,v 1.112 1999/10/22 08:30:02 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
#include <gtk/gtk.h>
-#ifdef WITH_WIRETAP
-#include <pcap.h>
-#endif
-
#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
+
+#include <time.h>
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
#ifdef NEED_SNPRINTF_H
# ifdef HAVE_STDARG_H
# include "snprintf.h"
#endif
+#ifdef NEED_STRERROR_H
+#include "strerror.h"
+#endif
+
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
# include <netinet/in.h>
#endif
-#include "ethereal.h"
-#include "menu.h"
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include "gtk/main.h"
+#include "column.h"
+#include "gtk/menu.h"
#include "packet.h"
+#include "print.h"
#include "file.h"
#include "util.h"
+#include "gtk/proto_draw.h"
+#include "dfilter.h"
+#include "timestamp.h"
+#include "conversation.h"
+
+#ifndef __RESOLV_H__
+#include "resolv.h"
+#endif
+
+#include "packet-atalk.h"
+
+#include "packet-ipv6.h"
+
+#include "packet-ncp.h"
extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
extern guint file_ctx;
+extern int sync_pipe[];
-static guint32 ssec, susec;
-static guint32 lastsec, lastusec;
+guint cap_input_id;
+gboolean auto_scroll_live = FALSE;
+
+static guint32 firstsec, firstusec;
+static guint32 prevsec, prevusec;
-#ifdef WITH_WIRETAP
static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
const u_char *);
-#else
-static void pcap_dispatch_cb(u_char *, const struct pcap_pkthdr *,
- const u_char *);
-#endif
+
+static void freeze_clist(capture_file *cf);
+static void thaw_clist(capture_file *cf);
+
+/* Update the progress bar this many times when reading a file. */
+#define N_PROGBAR_UPDATES 100
int
open_cap_file(char *fname, capture_file *cf) {
-#ifndef WITH_WIRETAP
- guint32 magic[2];
- char err_str[PCAP_ERRBUF_SIZE];
-#endif
+ wtap *wth;
+ int err;
+ FILE_T fh;
+ int fd;
struct stat cf_stat;
- /* First, make sure the file is valid */
- if (stat(fname, &cf_stat)) {
- simple_dialog(ESD_TYPE_WARN, NULL, "File does not exist.");
- return 1;
- }
- if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode)) {
- simple_dialog(ESD_TYPE_WARN, NULL, "The file you have chosen is invalid.");
- return 1;
+ wth = wtap_open_offline(fname, &err);
+ if (wth == NULL)
+ goto fail;
+
+ /* Find the size of the file. */
+ fh = wtap_file(wth);
+ fd = wtap_fd(wth);
+ if (fstat(fd, &cf_stat) < 0) {
+ err = errno;
+ wtap_close(wth);
+ goto fail;
}
- /* Next, try to open the file */
- cf->fh = fopen(fname, "r");
- if (cf->fh == NULL)
- return (errno);
+ /* The open succeeded. Close whatever capture file we had open,
+ and fill in the information for this file. */
+ close_cap_file(cf, info_bar, file_ctx);
- fseek(cf->fh, 0L, SEEK_END);
- cf->f_len = ftell(cf->fh);
-#ifndef WITH_WIRETAP
- fseek(cf->fh, 0L, SEEK_SET);
- fread(magic, sizeof(guint32), 2, cf->fh);
- fseek(cf->fh, 0L, SEEK_SET);
-#endif
- fclose(cf->fh);
- cf->fh = NULL;
- /* set the file name beacuse we need it to set the follow stream filter */
- cf->filename = g_strdup( fname );
-
- /* Next, find out what type of file we're dealing with */
-#ifdef WITH_WIRETAP
- cf->cd_t = WTAP_FILE_UNKNOWN;
- cf->lnk_t = WTAP_ENCAP_NONE;
-#else
- cf->cd_t = CD_UNKNOWN;
- cf->lnk_t = DLT_NULL;
-#endif
- cf->swap = 0;
- cf->count = 0;
- cf->drops = 0;
- cf->esec = 0;
- cf->eusec = 0;
- cf->snap = 0;
- if (cf->plist == NULL) {
- cf->plist = g_list_alloc();
- cf->plist->data = (frame_data *) g_malloc(sizeof(frame_data));
- } else {
- cf->plist = g_list_first(cf->plist);
- }
- ssec = 0, susec = 0;
- lastsec = 0, lastusec = 0;
-
-#ifndef WITH_WIRETAP
- if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) {
-
- /* Pcap/Tcpdump file */
- cf->pfh = pcap_open_offline(fname, err_str);
- if (cf->pfh == NULL) {
-#else
- cf->wth = wtap_open_offline(fname, WTAP_FILE_UNKNOWN);
- if (cf->wth == NULL) {
-#endif
+ /* Initialize the table of conversations. */
+ conversation_init();
- simple_dialog(ESD_TYPE_WARN, NULL, "Could not open file.");
- return 1;
- }
+ /* Initialize protocol-specific variables */
+ afs_init_protocol();
+ ncp_init_protocol();
+ smb_init_protocol();
-#ifndef WITH_WIRETAP
- if (cf->dfilter) {
- if (pcap_compile(cf->pfh, &cf->fcode, cf->dfilter, 1, 0) < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
- "\"%s\".", cf->dfilter);
- } else if (pcap_setfilter(cf->pfh, &cf->fcode) < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
- }
- }
+ cf->wth = wth;
+ cf->fh = fh;
+ cf->filed = fd;
+ cf->f_len = cf_stat.st_size;
- cf->fh = pcap_file(cf->pfh);
- cf->swap = pcap_is_swapped(cf->pfh);
- if ((cf->swap && BYTE_ORDER == BIG_ENDIAN) ||
- (!cf->swap && BYTE_ORDER == LITTLE_ENDIAN)) {
- /* Data is big-endian */
- cf->cd_t = CD_PCAP_BE;
- } else {
- cf->cd_t = CD_PCAP_LE;
- }
- cf->vers = ( ((pcap_major_version(cf->pfh) & 0x0000ffff) << 16) |
- pcap_minor_version(cf->pfh) );
- cf->snap = pcap_snapshot(cf->pfh);
- cf->lnk_t = pcap_datalink(cf->pfh);
- } else if (ntohl(magic[0]) == SNOOP_MAGIC_1 && ntohl(magic[1]) == SNOOP_MAGIC_2) {
- /* Snoop file */
- simple_dialog(ESD_TYPE_WARN, NULL, "The snoop format is not yet supported.");
- return 1;
- /*
- fread(&sfh, sizeof(snoop_file_hdr), 1, cf->fh);
- cf->cd_t = CD_SNOOP;
- cf->vers = ntohl(sfh.vers);
- if (cf->vers < SNOOP_MIN_VERSION || cf->vers > SNOOP_MAX_VERSION) {
- g_warning("ethereal:open_cap_file:%s:bad snoop file version(%d)",
- fname, cf->vers);
- return 1;
- }
- switch (ntohl(sfh.s_lnk_t)) {
- case 4:
- cf->lnk_t = DLT_EN10MB;
- break;
- }
- */
- }
-
- if (cf->cd_t == CD_UNKNOWN) {
- simple_dialog(ESD_TYPE_WARN, NULL, "Can't determine file type.");
- return 1;
- }
-#else
- cf->fh = wtap_file(cf->wth);
- cf->cd_t = wtap_file_type(cf->wth);
- cf->snap = wtap_snapshot_length(cf->wth);
- cf->lnk_t = wtap_encapsulation(cf->wth);
-#endif
+ /* set the file name because we need it to set the follow stream filter */
+ cf->filename = g_strdup(fname);
+
+ cf->cd_t = wtap_file_type(cf->wth);
+ cf->cd_t_desc = wtap_file_type_string(cf->wth);
+ cf->count = 0;
+ cf->drops = 0;
+ cf->esec = 0;
+ cf->eusec = 0;
+ cf->snap = wtap_snapshot_length(cf->wth);
+ cf->update_progbar = FALSE;
+ cf->progbar_quantum = 0;
+ cf->progbar_nextstep = 0;
+ firstsec = 0, firstusec = 0;
+ prevsec = 0, prevusec = 0;
+
+ return (0);
- return 0;
+fail:
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_open_error_message(err, FALSE), fname);
+ return (err);
}
/* Reset everything to a pristine state */
void
-close_cap_file(capture_file *cf, GtkWidget *w, guint context) {
+close_cap_file(capture_file *cf, void *w, guint context) {
+ frame_data *fd, *fd_next;
+
if (cf->fh) {
- fclose(cf->fh);
+ file_close(cf->fh);
cf->fh = NULL;
}
-#ifdef WITH_WIRETAP
if (cf->wth) {
- wtap_close(cf->wth);
- cf->wth = NULL;
- }
-#else
- if (cf->pfh) {
- pcap_close(cf->pfh);
- cf->pfh = NULL;
+ wtap_close(cf->wth);
+ cf->wth = NULL;
}
-#endif
- gtk_text_freeze(GTK_TEXT(byte_view));
- gtk_text_set_point(GTK_TEXT(byte_view), 0);
- gtk_text_forward_delete(GTK_TEXT(byte_view),
- gtk_text_get_length(GTK_TEXT(byte_view)));
- gtk_text_thaw(GTK_TEXT(byte_view));
- gtk_tree_clear_items(GTK_TREE(tree_view), 0,
- g_list_length(GTK_TREE(tree_view)->children));
+ for (fd = cf->plist; fd != NULL; fd = fd_next) {
+ fd_next = fd->next;
+ g_free(fd);
+ }
+ if (cf->rfcode != NULL) {
+ dfilter_destroy(cf->rfcode);
+ cf->rfcode = NULL;
+ }
+ cf->plist = NULL;
+ cf->plist_end = NULL;
+ unselect_packet(cf); /* nothing to select */
gtk_clist_freeze(GTK_CLIST(packet_list));
gtk_clist_clear(GTK_CLIST(packet_list));
gtk_clist_thaw(GTK_CLIST(packet_list));
gtk_statusbar_pop(GTK_STATUSBAR(w), context);
+
+ /* Disable all menu items that make sense only if you have a capture. */
+ set_menu_sensitivity("/File/Save", FALSE);
+ set_menu_sensitivity("/File/Save As...", FALSE);
+ set_menu_sensitivity("/File/Close", FALSE);
+ set_menu_sensitivity("/File/Reload", FALSE);
+ set_menu_sensitivity("/File/Print...", FALSE);
+ set_menu_sensitivity("/Display/Options...", FALSE);
+ set_menu_sensitivity("/Tools/Summary", FALSE);
}
int
-load_cap_file(char *fname, capture_file *cf) {
+read_cap_file(capture_file *cf) {
gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
gchar *done_fmt = " File: %s Drops: %d";
- gchar *err_fmt = " Error: Could not load '%s'";
- gint timeout;
- size_t msg_len;
+ int success;
int err;
+ size_t msg_len;
+ char *errmsg;
+ char errmsg_errno[1024+1];
+ gchar err_str[2048+1];
- close_cap_file(cf, info_bar, file_ctx);
-
- if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
- name_ptr = fname;
+ if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
+ name_ptr = cf->filename;
else
name_ptr++;
+
load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
sprintf(load_msg, load_fmt, name_ptr);
gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
+
+ cf->update_progbar = TRUE;
+ /* Update the progress bar when it gets to this value. */
+ cf->progbar_nextstep = 0;
+ /* When we reach the value that triggers a progress bar update,
+ bump that value by this amount. */
+ cf->progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
+
+ freeze_clist(cf);
+ proto_tree_is_visible = FALSE;
+ success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
+ wtap_close(cf->wth);
+ cf->wth = NULL;
+ cf->filed = open(cf->filename, O_RDONLY);
+ cf->fh = filed_open(cf->filed, "r");
+ cf->unfiltered_count = cf->count;
+ thaw_clist(cf);
+
+ gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
+ gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
+
+ gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+
+ msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
+ load_msg = g_realloc(load_msg, msg_len);
+
+ if (cf->user_saved || !cf->save_file)
+ snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
+ else
+ snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
+
+ gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
+ g_free(load_msg);
+
+ /* Enable menu items that make sense if you have a capture. */
+ set_menu_sensitivity("/File/Close", TRUE);
+ set_menu_sensitivity("/File/Reload", TRUE);
+ set_menu_sensitivity("/File/Print...", TRUE);
+ set_menu_sensitivity("/Display/Options...", TRUE);
+ set_menu_sensitivity("/Tools/Summary", TRUE);
+
+ if (!success) {
+ /* Put up a message box noting that the read failed somewhere along
+ the line. Don't throw out the stuff we managed to read, though,
+ if any. */
+ switch (err) {
+
+ case WTAP_ERR_CANT_READ:
+ errmsg = "An attempt to read from the file failed for"
+ " some unknown reason.";
+ break;
+
+ case WTAP_ERR_SHORT_READ:
+ errmsg = "The capture file appears to have been cut short"
+ " in the middle of a packet.";
+ break;
+
+ case WTAP_ERR_BAD_RECORD:
+ errmsg = "The capture file appears to be damaged or corrupt.";
+ break;
+
+ default:
+ sprintf(errmsg_errno, "An error occurred while reading the"
+ " capture file: %s.", wtap_strerror(err));
+ errmsg = errmsg_errno;
+ break;
+ }
+ snprintf(err_str, sizeof err_str, errmsg);
+ simple_dialog(ESD_TYPE_WARN, NULL, err_str);
+ return (err);
+ } else
+ return (0);
+}
+
+#ifdef HAVE_LIBPCAP
+void
+cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
- timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf);
-
- err = open_cap_file(fname, cf);
-#ifdef WITH_WIRETAP
- if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
-#else
- if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
-#endif
+ capture_file *cf = (capture_file *)data;
+ char buffer[256+1], *p = buffer, *q = buffer;
+ int nread;
+ int to_read = 0;
+ gboolean exit_loop = FALSE;
+ int err;
+ int wstatus;
+ int wsignal;
+ char *msg;
+ char *sigmsg;
+ char sigmsg_buf[6+1+3+1];
+ char *coredumped;
+
+ /* avoid reentrancy problems and stack overflow */
+ gtk_input_remove(cap_input_id);
+
+ if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
+
+ /* The child has closed the sync pipe, meaning it's not going to be
+ capturing any more packets. Pick up its exit status, and
+ complain if it died of a signal. */
+ if (wait(&wstatus) != -1) {
+ /* XXX - are there any platforms on which we can run that *don't*
+ support POSIX.1's <sys/wait.h> and macros therein? */
+ wsignal = wstatus & 0177;
+ coredumped = "";
+ if (wstatus == 0177) {
+ /* It stopped, rather than exiting. "Should not happen." */
+ msg = "stopped";
+ wsignal = (wstatus >> 8) & 0xFF;
+ } else {
+ msg = "terminated";
+ if (wstatus & 0200)
+ coredumped = " - core dumped";
+ }
+ if (wsignal != 0) {
+ switch (wsignal) {
+
+ case SIGHUP:
+ sigmsg = "Hangup";
+ break;
+
+ case SIGINT:
+ sigmsg = "Interrupted";
+ break;
+
+ case SIGQUIT:
+ sigmsg = "Quit";
+ break;
+
+ case SIGILL:
+ sigmsg = "Illegal instruction";
+ break;
+
+ case SIGTRAP:
+ sigmsg = "Trace trap";
+ break;
+
+ case SIGABRT:
+ sigmsg = "Abort";
+ break;
+
+ case SIGFPE:
+ sigmsg = "Arithmetic exception";
+ break;
+
+ case SIGKILL:
+ sigmsg = "Killed";
+ break;
+
+ case SIGBUS:
+ sigmsg = "Bus error";
+ break;
+
+ case SIGSEGV:
+ sigmsg = "Segmentation violation";
+ break;
+
+ /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
+ Linux is POSIX compliant. These are not POSIX-defined signals ---
+ ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
+
+ ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
+ were omitted from POSIX.1 because their behavior is
+ implementation dependent and could not be adequately catego-
+ rized. Conforming implementations may deliver these sig-
+ nals, but must document the circumstances under which they
+ are delivered and note any restrictions concerning their
+ delivery.''
+ */
+
+ #ifdef SIGSYS
+ case SIGSYS:
+ sigmsg = "Bad system call";
+ break;
+ #endif
+
+ case SIGPIPE:
+ sigmsg = "Broken pipe";
+ break;
+
+ case SIGALRM:
+ sigmsg = "Alarm clock";
+ break;
+
+ case SIGTERM:
+ sigmsg = "Terminated";
+ break;
+
+ default:
+ sprintf(sigmsg_buf, "Signal %d", wsignal);
+ sigmsg = sigmsg_buf;
+ break;
+ }
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Child capture process %s: %s%s", msg, sigmsg, coredumped);
+ }
+ }
+
+ /* Read what remains of the capture file, and stop capture (restore
+ menu items) */
gtk_clist_freeze(GTK_CLIST(packet_list));
-#ifdef WITH_WIRETAP
- wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);
+
+ /* XXX - do something if this fails? */
+ wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
+
+ thaw_clist(cf);
+ if (auto_scroll_live)
+ gtk_clist_moveto(GTK_CLIST(packet_list),
+ cf->plist_end->row, -1, 1.0, 1.0);
+
wtap_close(cf->wth);
cf->wth = NULL;
-#else
- pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
- pcap_close(cf->pfh);
- cf->pfh = NULL;
-#endif
- cf->plist = g_list_first(cf->plist);
- cf->fh = fopen(fname, "r");
- gtk_clist_thaw(GTK_CLIST(packet_list));
+ set_menu_sensitivity("/File/Open...", TRUE);
+ set_menu_sensitivity("/File/Close", TRUE);
+ set_menu_sensitivity("/File/Save As...", TRUE);
+ set_menu_sensitivity("/File/Print...", TRUE);
+ set_menu_sensitivity("/File/Reload", TRUE);
+ set_menu_sensitivity("/Capture/Start...", TRUE);
+ set_menu_sensitivity("/Tools/Summary", TRUE);
+ gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
+ return;
}
-
- gtk_timeout_remove(timeout);
- gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
- gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+ buffer[nread] = '\0';
- if (err == 0) {
- msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
- load_msg = g_realloc(load_msg, msg_len);
- snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
- gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
- g_free(load_msg);
+ while(!exit_loop) {
+ /* look for (possibly multiple) '*' */
+ switch (*q) {
+ case '*' :
+ to_read += atoi(p);
+ p = q + 1;
+ q++;
+ break;
+ case '\0' :
+ /* XXX should handle the case of a pipe full (i.e. no star found) */
+ exit_loop = TRUE;
+ break;
+ default :
+ q++;
+ break;
+ }
+ }
- name_ptr[-1] = '\0';
-#ifdef USE_ITEM
- set_menu_sensitivity("/File/Close", TRUE);
- set_menu_sensitivity("/File/Reload", TRUE);
-#else
- set_menu_sensitivity("<Main>/File/Close", TRUE);
- set_menu_sensitivity("<Main>/File/Reload", TRUE);
-#endif
+ gtk_clist_freeze(GTK_CLIST(packet_list));
+ /* XXX - do something if this fails? */
+ wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
+ gtk_clist_thaw(GTK_CLIST(packet_list));
+ if (auto_scroll_live)
+ gtk_clist_moveto(GTK_CLIST(packet_list), cf->plist_end->row, -1, 1.0, 1.0);
+
+ /* restore pipe handler */
+ cap_input_id = gtk_input_add_full (sync_pipe[0],
+ GDK_INPUT_READ,
+ cap_file_input_cb,
+ NULL,
+ (gpointer) cf,
+ NULL);
+}
+
+int
+tail_cap_file(char *fname, capture_file *cf) {
+ int err;
+ int i;
+
+ err = open_cap_file(fname, cf);
+ if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
+
+ set_menu_sensitivity("/File/Open...", FALSE);
+ set_menu_sensitivity("/Display/Options...", TRUE);
+ set_menu_sensitivity("/Capture/Start...", FALSE);
+
+ for (i = 0; i < cf->cinfo.num_cols; i++) {
+ if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
+ gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
+ else {
+ gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
+ gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
+ cf->cinfo.col_width[i]);
+ gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
+ }
+ }
+
+ cf->fh = file_open(fname, "r");
+
+ cap_input_id = gtk_input_add_full (sync_pipe[0],
+ GDK_INPUT_READ,
+ cap_file_input_cb,
+ NULL,
+ (gpointer) cf,
+ NULL);
+ gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx,
+ " <live capture in progress>");
+ }
+ else {
+ close(sync_pipe[0]);
+ }
+ return err;
+}
+#endif /* HAVE_LIBPCAP */
+
+/* To do: Add check_col checks to the col_add* routines */
+
+static void
+col_set_abs_time(frame_data *fd, int col)
+{
+ struct tm *tmp;
+ time_t then;
+
+ then = fd->abs_secs;
+ tmp = localtime(&then);
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
+ tmp->tm_hour,
+ tmp->tm_min,
+ tmp->tm_sec,
+ (long)fd->abs_usecs/100);
+}
+
+static void
+col_set_rel_time(frame_data *fd, int col)
+{
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
+ fd->rel_usecs);
+}
+
+static void
+col_set_delta_time(frame_data *fd, int col)
+{
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
+ fd->del_usecs);
+}
+
+/* Add "command-line-specified" time. */
+static void
+col_set_cls_time(frame_data *fd, int col)
+{
+ switch (timestamp_type) {
+ case ABSOLUTE:
+ col_set_abs_time(fd, col);
+ break;
+
+ case RELATIVE:
+ col_set_rel_time(fd, col);
+ break;
+
+ case DELTA:
+ col_set_delta_time(fd, col);
+ break;
+ }
+}
+
+static void
+col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
+{
+ u_int ipv4_addr;
+ struct e_in6_addr ipv6_addr;
+ struct atalk_ddp_addr ddp_addr;
+
+ switch (addr->type) {
+
+ case AT_ETHER:
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
+ else
+ strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
+ break;
+
+ case AT_IPv4:
+ memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
+ else
+ strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
+ break;
+
+ case AT_IPv6:
+ memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
+ else
+ strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+ break;
+
+ case AT_IPX:
+ strncpy(fd->cinfo->col_data[col],
+ ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
+ break;
+
+ case AT_SNA:
+ switch (addr->len) {
+
+ case 1:
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]);
+ break;
+
+ case 2:
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X",
+ pntohs(&addr->data[0]));
+ break;
+ }
+ break;
+
+ case AT_ATALK:
+ memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
+ strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr),
+ COL_MAX_LEN);
+ break;
+
+ case AT_VINES:
+ strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]),
+ COL_MAX_LEN);
+ break;
+
+ default:
+ break;
+ }
+ fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
+
+static void
+col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
+ gboolean is_res)
+{
+ switch (ptype) {
+
+ case PT_TCP:
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN);
+ else
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+ break;
+
+ case PT_UDP:
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN);
+ else
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+ break;
+
+ default:
+ break;
+ }
+ fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
+
+static void
+fill_in_columns(frame_data *fd)
+{
+ int i;
+
+ for (i = 0; i < fd->cinfo->num_cols; i++) {
+ switch (fd->cinfo->col_fmt[i]) {
+
+ case COL_NUMBER:
+ snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
+ break;
+
+ case COL_CLS_TIME:
+ col_set_cls_time(fd, i);
+ break;
+
+ case COL_ABS_TIME:
+ col_set_abs_time(fd, i);
+ break;
+
+ case COL_REL_TIME:
+ col_set_rel_time(fd, i);
+ break;
+
+ case COL_DELTA_TIME:
+ col_set_delta_time(fd, i);
+ break;
+
+ case COL_DEF_SRC:
+ case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */
+ col_set_addr(fd, i, &pi.src, TRUE);
+ break;
+
+ case COL_UNRES_SRC:
+ col_set_addr(fd, i, &pi.src, FALSE);
+ break;
+
+ case COL_DEF_DL_SRC:
+ case COL_RES_DL_SRC:
+ col_set_addr(fd, i, &pi.dl_src, TRUE);
+ break;
+
+ case COL_UNRES_DL_SRC:
+ col_set_addr(fd, i, &pi.dl_src, FALSE);
+ break;
+
+ case COL_DEF_NET_SRC:
+ case COL_RES_NET_SRC:
+ col_set_addr(fd, i, &pi.net_src, TRUE);
+ break;
+
+ case COL_UNRES_NET_SRC:
+ col_set_addr(fd, i, &pi.net_src, FALSE);
+ break;
+
+ case COL_DEF_DST:
+ case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */
+ col_set_addr(fd, i, &pi.dst, TRUE);
+ break;
+
+ case COL_UNRES_DST:
+ col_set_addr(fd, i, &pi.dst, FALSE);
+ break;
+
+ case COL_DEF_DL_DST:
+ case COL_RES_DL_DST:
+ col_set_addr(fd, i, &pi.dl_dst, TRUE);
+ break;
+
+ case COL_UNRES_DL_DST:
+ col_set_addr(fd, i, &pi.dl_dst, FALSE);
+ break;
+
+ case COL_DEF_NET_DST:
+ case COL_RES_NET_DST:
+ col_set_addr(fd, i, &pi.net_dst, TRUE);
+ break;
+
+ case COL_UNRES_NET_DST:
+ col_set_addr(fd, i, &pi.net_dst, FALSE);
+ break;
+
+ case COL_DEF_SRC_PORT:
+ case COL_RES_SRC_PORT: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
+ col_set_port(fd, i, pi.ptype, pi.srcport, TRUE);
+ break;
+
+ case COL_UNRES_SRC_PORT:
+ col_set_port(fd, i, pi.ptype, pi.srcport, FALSE);
+ break;
+
+ case COL_DEF_DST_PORT:
+ case COL_RES_DST_PORT: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
+ col_set_port(fd, i, pi.ptype, pi.destport, TRUE);
+ break;
+
+ case COL_UNRES_DST_PORT:
+ col_set_port(fd, i, pi.ptype, pi.destport, FALSE);
+ break;
+
+ case COL_PROTOCOL: /* currently done by dissectors */
+ case COL_INFO: /* currently done by dissectors */
+ break;
+
+ case COL_PACKET_LENGTH:
+ snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
+ break;
+
+ case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
+ break;
+ }
+ }
+}
+
+static void
+add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
+{
+ gint i, row;
+ gint crow;
+ gint color;
+ proto_tree *protocol_tree;
+
+ fdata->num = cf->count;
+
+ /* If we don't have the time stamp of the first packet in the
+ capture, it's because this is the first packet. Save the time
+ stamp of this packet as the time stamp of the first packet. */
+ if (!firstsec && !firstusec) {
+ firstsec = fdata->abs_secs;
+ firstusec = fdata->abs_usecs;
+ }
+
+ /* Get the time elapsed between the first packet and this packet. */
+ cf->esec = fdata->abs_secs - firstsec;
+ if (firstusec <= fdata->abs_usecs) {
+ cf->eusec = fdata->abs_usecs - firstusec;
} else {
- msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
- load_msg = g_realloc(load_msg, msg_len);
- snprintf(load_msg, msg_len, err_fmt, name_ptr);
- gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
- g_free(load_msg);
-#ifdef USE_ITEM
- set_menu_sensitivity("<Main>/File/Close", FALSE);
- set_menu_sensitivity("<Main>/File/Reload", FALSE);
-#else
- set_menu_sensitivity("<Main>/File/Close", FALSE);
- set_menu_sensitivity("<Main>/File/Reload", FALSE);
-#endif
+ cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
+ cf->esec--;
}
- return err;
+ fdata->cinfo = &cf->cinfo;
+ for (i = 0; i < fdata->cinfo->num_cols; i++) {
+ fdata->cinfo->col_data[i][0] = '\0';
+ }
+
+ /* Apply the filters */
+ if (cf->dfcode != NULL ||
+ CFILTERS_CONTAINS_FILTER(cf)) {
+ protocol_tree = proto_tree_create_root();
+ dissect_packet(buf, fdata, protocol_tree);
+ if (cf->dfcode != NULL)
+ fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
+ else
+ fdata->passed_dfilter = TRUE;
+ /* Apply color filters. */
+ color = -1;
+ for(crow = 0; cf->colors->num_of_filters &&
+ crow < cf->colors->num_of_filters; crow++) {
+
+ if(color_filter(cf,crow)->c_colorfilter == NULL) {
+ continue;
+ }
+ if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
+ cf->pd)){
+ color = crow;
+ break;
+ }
+ }
+
+ proto_tree_free(protocol_tree);
+ }
+ else {
+ dissect_packet(buf, fdata, NULL);
+ fdata->passed_dfilter = TRUE;
+ color = -1;
+ }
+ if (fdata->passed_dfilter) {
+ /* If we don't have the time stamp of the previous displayed packet,
+ it's because this is the first displayed packet. Save the time
+ stamp of this packet as the time stamp of the previous displayed
+ packet. */
+ if (!prevsec && !prevusec) {
+ prevsec = fdata->abs_secs;
+ prevusec = fdata->abs_usecs;
+ }
+
+ /* Get the time elapsed between the first packet and this packet. */
+ fdata->rel_secs = cf->esec;
+ fdata->rel_usecs = cf->eusec;
+
+ /* Get the time elapsed between the previous displayed packet and
+ this packet. */
+ fdata->del_secs = fdata->abs_secs - prevsec;
+ if (prevusec <= fdata->abs_usecs) {
+ fdata->del_usecs = fdata->abs_usecs - prevusec;
+ } else {
+ fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
+ fdata->del_secs--;
+ }
+ prevsec = fdata->abs_secs;
+ prevusec = fdata->abs_usecs;
+
+ fill_in_columns(fdata);
+
+ row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
+ fdata->row = row;
+
+ if (cf->colors->color_filters && (color != -1)){
+ gtk_clist_set_background(GTK_CLIST(packet_list), row,
+ &(color_filter(cf,color)->bg_color));
+ gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
+ &(color_filter(cf,color)->fg_color));
+ } else {
+ gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
+ gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
+ }
+
+ /* If this was the selected packet, remember the row it's in, so
+ we can re-select it. ("selected_packet" is 0-origin, as it's
+ a GList index; "num", however, is 1-origin.) */
+ if (cf->selected_packet == fdata->num - 1)
+ cf->selected_row = row;
+ } else
+ fdata->row = -1; /* not in the display */
+ fdata->cinfo = NULL;
}
static void
-#ifdef WITH_WIRETAP
wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
-#else
-pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr,
-#endif
const u_char *buf) {
frame_data *fdata;
- gint i, row;
capture_file *cf = (capture_file *) user;
- guint32 tssecs, tsusecs;
-
- while (gtk_events_pending())
- gtk_main_iteration();
+ int passed;
+ proto_tree *protocol_tree;
+ frame_data *plist_end;
+ int file_pos;
+ float prog_val;
+
+ /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
+ when we update it, we have to run the GTK+ main loop to get it
+ to repaint what's pending, and doing so may involve an "ioctl()"
+ to see if there's any pending input from an X server, and doing
+ that for every packet can be costly, especially on a big file.
+
+ Do so only if we were told to do so; when reading a capture file
+ being updated by a live capture, we don't do so (as we're not
+ "done" until the capture stops, so we don't know how close to
+ "done" we are. */
- fdata = cf->plist->data;
- cf->cur = fdata;
- cf->count++;
+ if (cf->update_progbar && offset >= cf->progbar_nextstep) {
+ file_pos = lseek(cf->filed, 0, SEEK_CUR);
+ prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), prog_val);
+ cf->progbar_nextstep += cf->progbar_quantum;
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+
+ /* Allocate the next list entry, and add it to the list. */
+ fdata = (frame_data *) g_malloc(sizeof(frame_data));
+ fdata->next = NULL;
fdata->pkt_len = phdr->len;
fdata->cap_len = phdr->caplen;
-#ifdef WITH_WIRETAP
fdata->file_off = offset;
-#else
- fdata->file_off = ftell(cf->fh) - phdr->caplen;
-#endif
- fdata->secs = phdr->ts.tv_sec;
- fdata->usecs = phdr->ts.tv_usec;
+ fdata->lnk_t = phdr->pkt_encap;
+ fdata->abs_secs = phdr->ts.tv_sec;
+ fdata->abs_usecs = phdr->ts.tv_usec;
+ fdata->pseudo_header = phdr->pseudo_header;
+ fdata->cinfo = NULL;
+
+ passed = TRUE;
+ if (cf->rfcode) {
+ protocol_tree = proto_tree_create_root();
+ dissect_packet(buf, fdata, protocol_tree);
+ passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
+ proto_tree_free(protocol_tree);
+ }
+ if (passed) {
+ plist_end = cf->plist_end;
+ if (plist_end != NULL)
+ plist_end->next = fdata;
+ else
+ cf->plist = fdata;
+ cf->plist_end = fdata;
+
+ cf->count++;
+ add_packet_to_packet_list(fdata, cf, buf);
+ } else
+ g_free(fdata);
+}
+
+void
+filter_packets(capture_file *cf, gchar *dftext)
+{
+ dfilter *dfcode;
+
+ if (dftext == NULL) {
+ /* The new filter is an empty filter (i.e., display all packets). */
+ dfcode = NULL;
+ } else {
+ /*
+ * We have a filter; try to compile it.
+ */
+ if (dfilter_compile(dftext, &dfcode) != 0) {
+ /* The attempt failed; report an error. */
+ simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+ return;
+ }
- /* If we don't have the time stamp of the first packet, it's because this
- is the first packet. Save the time stamp of this packet as the time
- stamp of the first packet. */
- if (!ssec && !susec) {
- ssec = fdata->secs;
- susec = fdata->usecs;
+ /* Was it empty? */
+ if (dfcode == NULL) {
+ /* Yes - free the filter text, and set it to null. */
+ g_free(dftext);
+ dftext = NULL;
+ }
}
- /* Do the same for the time stamp of the previous packet. */
- if (!lastsec && !lastusec) {
- lastsec = fdata->secs;
- lastusec = fdata->usecs;
+ /* We have a valid filter. Replace the current filter. */
+ if (cf->dfilter != NULL)
+ g_free(cf->dfilter);
+ cf->dfilter = dftext;
+ if (cf->dfcode != NULL)
+ dfilter_destroy(cf->dfcode);
+ cf->dfcode = dfcode;
+
+ /* Now go through the list of packets we've read from the capture file,
+ applying the current display filter, and, if the packet passes the
+ display filter, add it to the summary display, appropriately
+ colored. (That's how we colorize the display - it's like filtering
+ the display, only we don't install a new filter.) */
+ colorize_packets(cf);
+}
+
+void
+colorize_packets(capture_file *cf)
+{
+ frame_data *fd;
+ guint32 progbar_quantum;
+ guint32 progbar_nextstep;
+
+ gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
+
+ /* Freeze the packet list while we redo it, so we don't get any
+ screen updates while it happens. */
+ gtk_clist_freeze(GTK_CLIST(packet_list));
+
+ /* Clear it out. */
+ gtk_clist_clear(GTK_CLIST(packet_list));
+
+ /* If a packet was selected, we don't know yet what row, if any, it'll
+ get. */
+ cf->selected_row = -1;
+
+ /* Iterate through the list of packets, calling a routine
+ to run the filter on the packet, see if it matches, and
+ put it in the display list if so. */
+ firstsec = 0;
+ firstusec = 0;
+ prevsec = 0;
+ prevusec = 0;
+ cf->unfiltered_count = cf->count;
+ cf->count = 0;
+
+ proto_tree_is_visible = FALSE;
+
+ /* Update the progress bar when it gets to this value. */
+ progbar_nextstep = 0;
+ /* When we reach the value that triggers a progress bar update,
+ bump that value by this amount. */
+ progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
+ gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
+
+ for (fd = cf->plist; fd != NULL; fd = fd->next) {
+ /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
+ when we update it, we have to run the GTK+ main loop to get it
+ to repaint what's pending, and doing so may involve an "ioctl()"
+ to see if there's any pending input from an X server, and doing
+ that for every packet can be costly, especially on a big file. */
+ if (cf->count >= progbar_nextstep) {
+ /* let's not divide by zero. I should never be started
+ * with unfiltered_count == 0, so let's assert that
+ */
+ g_assert(cf->unfiltered_count > 0);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
+ (gfloat) cf->count / cf->unfiltered_count);
+
+ progbar_nextstep += progbar_quantum;
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+
+ cf->count++;
+
+ wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+
+ add_packet_to_packet_list(fd, cf, cf->pd);
}
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
- /* Get the time elapsed between the first packet and this packet. */
- cf->esec = fdata->secs - ssec;
- if (susec <= fdata->usecs) {
- cf->eusec = fdata->usecs - susec;
+ if (cf->selected_row != -1) {
+ /* We had a selected packet and it passed the filter. */
+ gtk_clist_select_row(GTK_CLIST(packet_list), cf->selected_row, -1);
} else {
- cf->eusec = (fdata->usecs + 1000000) - susec;
- cf->esec--;
+ /* If we had one, it didn't pass the filter. */
+ unselect_packet(cf);
}
- /* Compute the time stamp. */
- switch (timestamp_type) {
- case RELATIVE: /* Relative to the first packet */
- tssecs = cf->esec;
- tsusecs = cf->eusec;
- break;
- case DELTA: /* Relative to the previous packet */
- tssecs = fdata->secs - lastsec;
- if (lastusec <= fdata->usecs) {
- tsusecs = fdata->usecs - lastusec;
+ /* Unfreeze the packet list. */
+ gtk_clist_thaw(GTK_CLIST(packet_list));
+}
+
+int
+print_packets(capture_file *cf, print_args_t *print_args)
+{
+ int i;
+ frame_data *fd;
+ guint32 progbar_quantum;
+ guint32 progbar_nextstep;
+ guint32 count;
+ proto_tree *protocol_tree;
+ gint *col_widths = NULL;
+ gint data_width;
+ gboolean print_separator;
+
+ cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
+ if (cf->print_fh == NULL)
+ return FALSE; /* attempt to open destination failed */
+
+ /* XXX - printing multiple frames in PostScript looks as if it's
+ tricky - you have to deal with page boundaries, I think -
+ and I'll have to spend some time learning enough about
+ PostScript to figure it out, so, for now, we only print
+ multiple frames as text. */
+#if 0
+ print_preamble(cf->print_fh);
+#endif
+
+ if (print_args->print_summary) {
+ /* We're printing packet summaries.
+
+ Find the widths for each of the columns - maximum of the
+ width of the title and the width of the data - and print
+ the column titles. */
+ col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
+ for (i = 0; i < cf->cinfo.num_cols; i++) {
+ /* Don't pad the last column. */
+ if (i == cf->cinfo.num_cols - 1)
+ col_widths[i] = 0;
+ else {
+ col_widths[i] = strlen(cf->cinfo.col_title[i]);
+ data_width = get_column_char_width(get_column_format(i));
+ if (data_width > col_widths[i])
+ col_widths[i] = data_width;
+ }
+
+ /* Right-justify the packet number column. */
+ if (cf->cinfo.col_fmt[i] == COL_NUMBER)
+ fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_title[i]);
+ else
+ fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
+ if (i == cf->cinfo.num_cols - 1)
+ fputc('\n', cf->print_fh);
+ else
+ fputc(' ', cf->print_fh);
+ }
+ }
+
+ print_separator = FALSE;
+ proto_tree_is_visible = TRUE;
+
+ /* Update the progress bar when it gets to this value. */
+ progbar_nextstep = 0;
+ /* When we reach the value that triggers a progress bar update,
+ bump that value by this amount. */
+ progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
+ /* Count of packets we've looked at. */
+ count = 0;
+
+ /* Iterate through the list of packets, printing the packets that
+ were selected by the current display filter. */
+ for (fd = cf->plist; fd != NULL; fd = fd->next) {
+ /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
+ when we update it, we have to run the GTK+ main loop to get it
+ to repaint what's pending, and doing so may involve an "ioctl()"
+ to see if there's any pending input from an X server, and doing
+ that for every packet can be costly, especially on a big file. */
+ if (count >= progbar_nextstep) {
+ /* let's not divide by zero. I should never be started
+ * with unfiltered_count == 0, so let's assert that
+ */
+ g_assert(cf->unfiltered_count > 0);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
+ (gfloat) count / cf->unfiltered_count);
+ progbar_nextstep += progbar_quantum;
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+ count++;
+
+ if (fd->passed_dfilter) {
+ wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+ if (print_args->print_summary) {
+ /* Fill in the column information, but don't bother creating
+ the logical protocol tree. */
+ fd->cinfo = &cf->cinfo;
+ for (i = 0; i < fd->cinfo->num_cols; i++) {
+ fd->cinfo->col_data[i][0] = '\0';
+ }
+ dissect_packet(cf->pd, fd, NULL);
+ fill_in_columns(fd);
+ for (i = 0; i < cf->cinfo.num_cols; i++) {
+ /* Right-justify the packet number column. */
+ if (cf->cinfo.col_fmt[i] == COL_NUMBER)
+ fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_data[i]);
+ else
+ fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
+ if (i == cf->cinfo.num_cols - 1)
+ fputc('\n', cf->print_fh);
+ else
+ fputc(' ', cf->print_fh);
+ }
} else {
- tsusecs = (fdata->usecs + 1000000) - lastusec;
- tssecs--;
+ if (print_separator)
+ fputc('\n', cf->print_fh);
+
+ /* Create the logical protocol tree. */
+ protocol_tree = proto_tree_create_root();
+ dissect_packet(cf->pd, fd, protocol_tree);
+
+ /* Print the information in that tree. */
+ proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
+ cf->pd, fd, cf->print_fh);
+
+ proto_tree_free(protocol_tree);
+
+ if (print_args->print_hex) {
+ /* Print the full packet data as hex. */
+ print_hex_data(cf->print_fh, cf->pd, fd->cap_len);
+ }
+
+ /* Print a blank line if we print anything after this. */
+ print_separator = TRUE;
}
- break;
- default: /* Absolute time, or bogus timestamp_type value */
- tssecs = 0; /* Not used */
- tsusecs = 0;
- break;
+ }
}
- fdata->cinfo = &cf->cinfo;
- for (i = 0; i < fdata->cinfo->num_cols; i++) {
- fdata->cinfo->col_data[i][0] = '\0';
+
+ if (col_widths != NULL)
+ g_free(col_widths);
+
+#if 0
+ print_finale(cf->print_fh);
+#endif
+
+ close_print_dest(print_args->to_file, cf->print_fh);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
+
+ cf->print_fh = NULL;
+ return TRUE;
+}
+
+/* Scan through the packet list and change all columns that use the
+ "command-line-specified" time stamp format to use the current
+ value of that format. */
+void
+change_time_formats(capture_file *cf)
+{
+ frame_data *fd;
+ int i;
+ GtkStyle *pl_style;
+
+ /* Freeze the packet list while we redo it, so we don't get any
+ screen updates while it happens. */
+ freeze_clist(cf);
+
+ /* Iterate through the list of packets, checking whether the packet
+ is in a row of the summary list and, if so, whether there are
+ any columns that show the time in the "command-line-specified"
+ format and, if so, update that row. */
+ for (fd = cf->plist; fd != NULL; fd = fd->next) {
+ if (fd->row != -1) {
+ /* This packet is in the summary list, on row "fd->row". */
+
+ /* XXX - there really should be a way of checking "cf->cinfo" for this;
+ the answer isn't going to change from packet to packet, so we should
+ simply skip all the "change_time_formats()" work if we're not
+ changing anything. */
+ fd->cinfo = &cf->cinfo;
+ if (check_col(fd, COL_CLS_TIME)) {
+ /* There are columns that show the time in the "command-line-specified"
+ format; update them. */
+ for (i = 0; i < cf->cinfo.num_cols; i++) {
+ if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
+ /* This is one of the columns that shows the time in
+ "command-line-specified" format; update it. */
+ cf->cinfo.col_data[i][0] = '\0';
+ col_set_cls_time(fd, i);
+ gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
+ cf->cinfo.col_data[i]);
+ }
+ }
+ }
+ }
}
- if (check_col(fdata, COL_NUMBER))
- col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
- dissect_packet(buf, tssecs, tsusecs, fdata, NULL);
- row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
- fdata->cinfo = NULL;
- /* Make sure we always have an available list entry */
- if (cf->plist->next == NULL) {
- fdata = (frame_data *) g_malloc(sizeof(frame_data));
- g_list_append(cf->plist, (gpointer) fdata);
+ /* Set the column widths of those columns that show the time in
+ "command-line-specified" format. */
+ pl_style = gtk_widget_get_style(packet_list);
+ for (i = 0; i < cf->cinfo.num_cols; i++) {
+ if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
+ gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
+ get_column_width(COL_CLS_TIME, pl_style->font));
+ }
}
- cf->plist = cf->plist->next;
+
+ /* Unfreeze the packet list. */
+ thaw_clist(cf);
}
-/* Uncomment when we handle snoop files again.
-
-size_t
-read_frame_header(capture_file *cf) {
- snoop_frame_hdr shdr;
- pcap_frame_hdr phdr;
- gint16 pkt_len, cap_len;
- guint32 secs, usecs;
- frame_data *fdata;
- size_t err;
-
- if ((cf->cd_t == CD_PCAP_BE) || (cf->cd_t == CD_PCAP_LE)) {
- err = fread((char *)&phdr, sizeof(pcap_frame_hdr), 1, cf->fh);
- if (!err) { return err; }
- fdata = (frame_data *) g_malloc(sizeof(frame_data));
- if (cf->swap) {
- pkt_len = SWAP32(phdr.pkt_len);
- cap_len = SWAP32(phdr.cap_len);
- secs = SWAP32(phdr.tm.tv_sec);
- usecs = SWAP32(phdr.tm.tv_usec);
- } else {
- pkt_len = phdr.pkt_len;
- cap_len = phdr.cap_len;
- secs = phdr.tm.tv_sec;
- usecs = phdr.tm.tv_usec;
- }
- } else if (cf->cd_t == CD_SNOOP) {
- err = fread(&shdr, sizeof(snoop_frame_hdr), 1, cf->fh);
- fdata = (frame_data *) g_malloc(sizeof(frame_data));
- if (!err) { return err; }
- pkt_len = ntohl(shdr.inc_len);
- cap_len = ntohl(shdr.pr_len) - 24;
- secs = ntohl(shdr.secs);
- usecs = ntohl(shdr.usecs);
- shdr.drops = ntohl(shdr.drops);
- if (!ssec && !susec) { ssec = secs; susec = usecs; }
- cf->drops = shdr.drops;
- cf->esec = secs - ssec;
- if (susec < shdr.usecs) {
- cf->eusec = usecs - susec;
+static void
+clear_tree_and_hex_views(void)
+{
+ GList *selection;
+ GtkWidget *tmp_item;
+
+ /* Clear the hex dump. */
+ gtk_text_freeze(GTK_TEXT(byte_view));
+ gtk_text_set_point(GTK_TEXT(byte_view), 0);
+ gtk_text_forward_delete(GTK_TEXT(byte_view),
+ gtk_text_get_length(GTK_TEXT(byte_view)));
+ gtk_text_thaw(GTK_TEXT(byte_view));
+
+ /* Deselect any selected tree item. gtktree.c should
+ * do this when we clear_items, but it doesn't. I copied
+ * this while() loop from gtktree.c, gtk_real_tree_select_child()
+ */
+ if (GTK_TREE(tree_view)->root_tree) {
+ selection = GTK_TREE(tree_view)->root_tree->selection;
+ while (selection) {
+ tmp_item = selection->data;
+ gtk_tree_item_deselect(GTK_TREE_ITEM(tmp_item));
+ gtk_widget_unref(tmp_item);
+ selection = selection->next;
+ }
+ g_list_free(GTK_TREE(tree_view)->root_tree->selection);
+ GTK_TREE(tree_view)->root_tree->selection = NULL;
+ }
+
+ /* Clear the protocol tree view. The length arg of -1
+ * means to clear all items up to the end. */
+ gtk_tree_clear_items(GTK_TREE(tree_view), 0, -1);
+}
+
+
+/* Select the packet on a given row. */
+void
+select_packet(capture_file *cf, int row)
+{
+ frame_data *fd;
+ int i;
+
+ /* Clear out whatever's currently in the hex dump. */
+ gtk_text_freeze(GTK_TEXT(byte_view));
+ gtk_text_set_point(GTK_TEXT(byte_view), 0);
+ gtk_text_forward_delete(GTK_TEXT(byte_view),
+ gtk_text_get_length(GTK_TEXT(byte_view)));
+
+ /* Search through the list of frames to see which one is in
+ this row. */
+ for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
+ if (fd->row == row)
+ break;
+ }
+
+ g_assert(fd != NULL);
+
+ cf->fd = fd;
+
+ /* Remember the ordinal number of that frame. */
+ cf->selected_packet = i;
+
+ /* Get the data in that frame. */
+ wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+
+ /* Create the logical protocol tree. */
+ if (cf->protocol_tree)
+ proto_tree_free(cf->protocol_tree);
+ cf->protocol_tree = proto_tree_create_root();
+ proto_tree_is_visible = TRUE;
+ dissect_packet(cf->pd, cf->fd, cf->protocol_tree);
+
+ /* Display the GUI protocol tree and hex dump. */
+ clear_tree_and_hex_views();
+ proto_tree_draw(cf->protocol_tree, tree_view);
+ packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->fd->cap_len, -1, -1);
+ gtk_text_thaw(GTK_TEXT(byte_view));
+
+ /* A packet is selected, so "File/Print Packet" has something to print. */
+ set_menu_sensitivity("/File/Print Packet", TRUE);
+ set_menu_sensitivity("/Display/Collapse All", TRUE);
+ set_menu_sensitivity("/Display/Expand All", TRUE);
+}
+
+/* Unselect the selected packet, if any. */
+void
+unselect_packet(capture_file *cf)
+{
+ cf->selected_packet = -1; /* nothing there to be selected */
+ cf->selected_row = -1;
+
+ /* Destroy the protocol tree for that packet. */
+ if (cf->protocol_tree != NULL) {
+ proto_tree_free(cf->protocol_tree);
+ cf->protocol_tree = NULL;
+ }
+
+ /* Clear out the display of that packet. */
+ clear_tree_and_hex_views();
+
+ /* No packet is selected, so "File/Print Packet" has nothing to print. */
+ set_menu_sensitivity("/File/Print Packet", FALSE);
+ set_menu_sensitivity("/Display/Collapse All", FALSE);
+ set_menu_sensitivity("/Display/Expand All", FALSE);
+}
+
+static void
+freeze_clist(capture_file *cf)
+{
+ int i;
+
+ /* Make the column sizes static, so they don't adjust while
+ we're reading the capture file (freezing the clist doesn't
+ seem to suffice). */
+ for (i = 0; i < cf->cinfo.num_cols; i++)
+ gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
+ gtk_clist_freeze(GTK_CLIST(packet_list));
+}
+
+static void
+thaw_clist(capture_file *cf)
+{
+ int i;
+
+ for (i = 0; i < cf->cinfo.num_cols; i++) {
+ if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
+ /* Set this column's width to the appropriate value. */
+ gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
+ cf->cinfo.col_width[i]);
} else {
- cf->eusec = susec - usecs;
- cf->esec--;
+ /* Make this column's size dynamic, so that it adjusts to the
+ appropriate size. */
+ gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
}
}
- cf->cur = fdata;
- fdata->pkt_len = pkt_len;
- fdata->cap_len = cap_len;
- fdata->secs = secs;
- fdata->usecs = usecs;
- g_list_append(cf->plist, (gpointer) fdata);
- if (!ssec && !susec) {
- ssec = secs;
- susec = usecs;
- }
- cf->esec = secs - ssec;
- if (susec < usecs) {
- cf->eusec = usecs - susec;
- } else {
- cf->eusec = susec - usecs;
- cf->esec--;
+ gtk_clist_thaw(GTK_CLIST(packet_list));
+
+ /* Hopefully, the columns have now gotten their appropriate sizes;
+ make them resizeable - a column that auto-resizes cannot be
+ resized by the user, and *vice versa*. */
+ for (i = 0; i < cf->cinfo.num_cols; i++)
+ gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
+}
+
+/* Tries to mv a file. If unsuccessful, tries to cp the file.
+ * Returns 0 on failure to do either, 1 on success of either
+ */
+int
+file_mv(char *from, char *to)
+{
+
+#define COPY_BUFFER_SIZE 8192
+
+ int retval;
+
+#ifndef WIN32
+ /* try a hard link */
+ retval = link(from, to);
+
+ /* or try a copy */
+ if (retval < 0) {
+#endif
+ retval = file_cp(from, to);
+ if (!retval) {
+ return 0;
+ }
+#ifndef WIN32
+ }
+#endif
+
+ unlink(from);
+ return 1;
+}
+
+/* Copies a file.
+ * Returns 0 on failure to do either, 1 on success of either
+ */
+int
+file_cp(char *from, char *to)
+{
+
+#define COPY_BUFFER_SIZE 8192
+
+ int from_fd, to_fd, nread, nwritten;
+ char *buffer;
+
+ buffer = g_malloc(COPY_BUFFER_SIZE);
+
+ from_fd = open(from, O_RDONLY);
+ if (from_fd < 0) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_open_error_message(errno, TRUE), from);
+ return 0;
+ }
+
+ to_fd = creat(to, 0644);
+ if (to_fd < 0) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_open_error_message(errno, TRUE), to);
+ close(from_fd);
+ return 0;
+ }
+
+ while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
+ nwritten = write(to_fd, buffer, nread);
+ if (nwritten < nread) {
+ if (nwritten < 0) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_write_error_message(errno), to);
+ } else {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+"The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
+ to, nread, nwritten);
+ }
+ close(from_fd);
+ close(to_fd);
+ return 0;
+ }
+ }
+ if (nread < 0) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_read_error_message(errno), from);
+ close(from_fd);
+ close(to_fd);
+ return 0;
+ }
+ close(from_fd);
+ close(to_fd);
+
+ return 1;
+}
+
+char *
+file_open_error_message(int err, int for_writing)
+{
+ char *errmsg;
+ static char errmsg_errno[1024+1];
+
+ switch (err) {
+
+ case WTAP_ERR_NOT_REGULAR_FILE:
+ errmsg = "The file \"%s\" is invalid.";
+ break;
+
+ case WTAP_ERR_FILE_UNKNOWN_FORMAT:
+ case WTAP_ERR_UNSUPPORTED:
+ errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
+ break;
+
+ case WTAP_ERR_BAD_RECORD:
+ errmsg = "The file \"%s\" appears to be damaged or corrupt.";
+ break;
+
+ case WTAP_ERR_CANT_OPEN:
+ if (for_writing)
+ errmsg = "The file \"%s\" could not be created for some unknown reason.";
+ else
+ errmsg = "The file \"%s\" could not be opened for some unknown reason.";
+ break;
+
+ case WTAP_ERR_SHORT_READ:
+ errmsg = "The file \"%s\" appears to have been cut short"
+ " in the middle of a packet.";
+ break;
+
+ case ENOENT:
+ if (for_writing)
+ errmsg = "The path to the file \"%s\" does not exist.";
+ else
+ errmsg = "The file \"%s\" does not exist.";
+ break;
+
+ case EACCES:
+ if (for_writing)
+ errmsg = "You do not have permission to create or write to the file \"%s\".";
+ else
+ errmsg = "You do not have permission to read the file \"%s\".";
+ break;
+
+ default:
+ sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
+ wtap_strerror(err));
+ errmsg = errmsg_errno;
+ break;
}
- return err;
+ return errmsg;
+}
+
+char *
+file_read_error_message(int err)
+{
+ static char errmsg_errno[1024+1];
+
+ sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
+ wtap_strerror(err));
+ return errmsg_errno;
+}
+
+char *
+file_write_error_message(int err)
+{
+ char *errmsg;
+ static char errmsg_errno[1024+1];
+
+ switch (err) {
+
+ case ENOSPC:
+ errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
+ break;
+
+#ifdef EDQUOT
+ case EDQUOT:
+ errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
+ break;
+#endif
+
+ default:
+ sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
+ wtap_strerror(err));
+ errmsg = errmsg_errno;
+ break;
+ }
+ return errmsg;
}
-*/