X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=file.c;h=d8e920c183eeee1648e01b4852cfde7c896304dd;hb=1a7be4638f77a2b91cedab8e2b88fc8733e22a55;hp=6bc52bdf50561d7d21b3b6462badbd4b001518a8;hpb=dfa9f0cb3680a9ca3493d1dd41ad1fe5ab90d460;p=obnox%2Fwireshark%2Fwip.git diff --git a/file.c b/file.c index 6bc52bdf50..d8e920c183 100644 --- a/file.c +++ b/file.c @@ -1,7 +1,7 @@ /* file.c * File I/O routines * - * $Id: file.c,v 1.57 1999/08/07 01:25:04 guy Exp $ + * $Id: file.c,v 1.112 1999/10/22 08:30:02 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -35,6 +35,8 @@ #include #endif +#include + #ifdef HAVE_IO_H #include #endif @@ -44,6 +46,7 @@ #include #include #include +#include #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H @@ -66,27 +69,41 @@ # include #endif -#include "ethereal.h" +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#include "gtk/main.h" #include "column.h" -#include "menu.h" +#include "gtk/menu.h" #include "packet.h" #include "print.h" #include "file.h" #include "util.h" -#include "gtkpacket.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_mode; extern int sync_pipe[]; guint cap_input_id; +gboolean auto_scroll_live = FALSE; static guint32 firstsec, firstusec; -static guint32 lastsec, lastusec; +static guint32 prevsec, prevusec; static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int, const u_char *); @@ -94,81 +111,94 @@ static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int, static void freeze_clist(capture_file *cf); static void thaw_clist(capture_file *cf); -static gint dfilter_progress_cb(gpointer p); +/* 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) { + 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)) - return (errno); -#ifndef WIN32 - if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode)) - return (OPEN_CAP_FILE_NOT_REGULAR); -#endif + 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; + } + + /* 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); + + /* Initialize the table of conversations. */ + conversation_init(); + + /* Initialize protocol-specific variables */ + afs_init_protocol(); + ncp_init_protocol(); + smb_init_protocol(); + + cf->wth = wth; + cf->fh = fh; + cf->filed = fd; + cf->f_len = cf_stat.st_size; - /* Next, try to open the file */ - cf->fh = fopen(fname, "r"); - if (cf->fh == NULL) - return (errno); - - fseek(cf->fh, 0L, SEEK_END); - cf->f_len = ftell(cf->fh); - 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 */ - cf->cd_t = WTAP_FILE_UNKNOWN; - cf->cd_t_desc = "unknown"; + /* 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 = 0; + cf->snap = wtap_snapshot_length(cf->wth); + cf->update_progbar = FALSE; + cf->progbar_quantum = 0; + cf->progbar_nextstep = 0; firstsec = 0, firstusec = 0; - lastsec = 0, lastusec = 0; + prevsec = 0, prevusec = 0; - cf->wth = wtap_open_offline(fname); - if (cf->wth == NULL) { - - /* XXX - we assume that, because we were able to open it above, - this must have failed because it's not a capture file in - a format we can read. */ - return (OPEN_CAP_FILE_UNKNOWN_FORMAT); - } - - cf->fh = wtap_file(cf->wth); - cf->cd_t = wtap_file_type(cf->wth); - cf->cd_t_desc = wtap_file_type_string(cf->wth); - cf->snap = wtap_snapshot_length(cf->wth); return (0); -} -static void -free_packets_cb(gpointer data, gpointer user_data) -{ - g_free(data); +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, void *w, guint context) { + frame_data *fd, *fd_next; + if (cf->fh) { - fclose(cf->fh); + file_close(cf->fh); cf->fh = NULL; } if (cf->wth) { wtap_close(cf->wth); cf->wth = NULL; } - if (cf->plist) { - g_list_foreach(cf->plist, free_packets_cb, NULL); - g_list_free(cf->plist); - cf->plist = NULL; + 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)); @@ -187,72 +217,96 @@ close_cap_file(capture_file *cf, void *w, guint context) { } 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); - - /* Initialize protocol-specific variables */ - ncp_init_protocol(); - - 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); - - timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) cf); - err = open_cap_file(fname, cf); - if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) { - freeze_clist(cf); - wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf); - wtap_close(cf->wth); - cf->wth = NULL; - cf->fh = fopen(fname, "r"); - thaw_clist(cf); - } - - gtk_timeout_remove(timeout); - gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0); + 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); - if (err == 0) { - msg_len = strlen(name_ptr) + strlen(done_fmt) + 64; - load_msg = g_realloc(load_msg, msg_len); + 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, "", cf->drops); + 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, "", 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; - gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg); - g_free(load_msg); + case WTAP_ERR_SHORT_READ: + errmsg = "The capture file appears to have been cut short" + " in the middle of a packet."; + break; -/* name_ptr[-1] = '\0'; Why is this here? It causes problems with capture files */ + case WTAP_ERR_BAD_RECORD: + errmsg = "The capture file appears to be damaged or corrupt."; + break; - /* 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); - } 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); - } - return err; + 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 @@ -260,10 +314,17 @@ void cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) { capture_file *cf = (capture_file *)data; - char buffer[256], *p = buffer, *q = buffer; + 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); @@ -271,13 +332,117 @@ cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) { 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. Read what remains of the capture file, - and stop capture (restore menu items) */ + 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 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)); - 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; @@ -286,9 +451,7 @@ cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) { set_menu_sensitivity("/File/Save As...", TRUE); set_menu_sensitivity("/File/Print...", TRUE); set_menu_sensitivity("/File/Reload", TRUE); -#ifdef HAVE_LIBPCAP set_menu_sensitivity("/Capture/Start...", TRUE); -#endif set_menu_sensitivity("/Tools/Summary", TRUE); gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: "); return; @@ -315,8 +478,11 @@ cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) { } gtk_clist_freeze(GTK_CLIST(packet_list)); - wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf); + /* 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], @@ -332,18 +498,12 @@ tail_cap_file(char *fname, capture_file *cf) { int err; int i; - close_cap_file(cf, info_bar, file_ctx); - - /* Initialize protocol-specific variables */ - ncp_init_protocol(); - err = open_cap_file(fname, cf); if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) { set_menu_sensitivity("/File/Open...", FALSE); -#ifdef HAVE_LIBPCAP + set_menu_sensitivity("/Display/Options...", TRUE); set_menu_sensitivity("/Capture/Start...", FALSE); -#endif for (i = 0; i < cf->cinfo.num_cols; i++) { if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE) @@ -356,7 +516,7 @@ tail_cap_file(char *fname, capture_file *cf) { } } - cf->fh = fopen(fname, "r"); + cf->fh = file_open(fname, "r"); cap_input_id = gtk_input_add_full (sync_pipe[0], GDK_INPUT_READ, @@ -372,83 +532,377 @@ tail_cap_file(char *fname, capture_file *cf) { } return err; } -#endif +#endif /* HAVE_LIBPCAP */ + +/* To do: Add check_col checks to the col_add* routines */ static void -compute_time_stamps(frame_data *fdata, capture_file *cf) +col_set_abs_time(frame_data *fd, int col) { - /* 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 (!firstsec && !firstusec) { - firstsec = fdata->abs_secs; - firstusec = fdata->abs_usecs; + 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; - /* Do the same for the time stamp of the previous packet. */ - if (!lastsec && !lastusec) { - lastsec = fdata->abs_secs; - lastusec = fdata->abs_usecs; + default: + break; } + fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0'; +} - /* 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 { - cf->eusec = (fdata->abs_usecs + 1000000) - firstusec; - cf->esec--; +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; } - fdata->rel_secs = cf->esec; - fdata->rel_usecs = cf->eusec; - - /* Do the same for the previous packet */ - fdata->del_secs = fdata->abs_secs - lastsec; - if (lastusec <= fdata->abs_usecs) { - fdata->del_usecs = fdata->abs_usecs - lastusec; - } else { - fdata->del_usecs = (fdata->abs_usecs + 1000000) - lastusec; - fdata->del_secs--; + 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; + } } - lastsec = fdata->abs_secs; - lastusec = fdata->abs_usecs; } 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; - compute_time_stamps(fdata, cf); + 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 { + cf->eusec = (fdata->abs_usecs + 1000000) - firstusec; + cf->esec--; + } fdata->cinfo = &cf->cinfo; for (i = 0; i < fdata->cinfo->num_cols; i++) { fdata->cinfo->col_data[i][0] = '\0'; } - if (check_col(fdata, COL_NUMBER)) - col_add_fstr(fdata, COL_NUMBER, "%d", cf->count); - /* Apply the display filter */ - if (cf->dfcode) { + + /* Apply the filters */ + if (cf->dfcode != NULL || + CFILTERS_CONTAINS_FILTER(cf)) { protocol_tree = proto_tree_create_root(); dissect_packet(buf, fdata, protocol_tree); - fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd); + 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) { - row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data); - gtk_clist_set_row_data(GTK_CLIST(packet_list), row, fdata); + /* 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; + } - /* 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; "count", however, is 1-origin.) */ - if (cf->selected_packet == cf->count - 1) - cf->selected_row = row; - } + /* 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; } @@ -457,62 +911,117 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset, const u_char *buf) { frame_data *fdata; capture_file *cf = (capture_file *) user; - - 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. */ + + 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)); - cf->plist = g_list_append(cf->plist, (gpointer) fdata); - - cf->count++; + fdata->next = NULL; fdata->pkt_len = phdr->len; fdata->cap_len = phdr->caplen; fdata->file_off = offset; fdata->lnk_t = phdr->pkt_encap; fdata->abs_secs = phdr->ts.tv_sec; fdata->abs_usecs = phdr->ts.tv_usec; - fdata->flags = phdr->flags; + fdata->pseudo_header = phdr->pseudo_header; fdata->cinfo = NULL; - add_packet_to_packet_list(fdata, cf, buf); -} - -static void -filter_packets_cb(gpointer data, gpointer user_data) -{ - frame_data *fd = data; - capture_file *cf = user_data; - - cf->count++; - - fseek(cf->fh, fd->file_off, SEEK_SET); - fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh); - - add_packet_to_packet_list(fd, cf, cf->pd); + 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; - if (cf->count % 20 == 0) { - dfilter_progress_cb(cf); - } + cf->count++; + add_packet_to_packet_list(fdata, cf, buf); + } else + g_free(fdata); } void -filter_packets(capture_file *cf) +filter_packets(capture_file *cf, gchar *dftext) { -/* gint timeout;*/ + dfilter *dfcode; - if (cf->dfilter != NULL) { + if (dftext == NULL) { + /* The new filter is an empty filter (i.e., display all packets). */ + dfcode = NULL; + } else { /* - * Compile the filter. + * We have a filter; try to compile it. */ - if (dfilter_compile(cf->dfilter, &cf->dfcode) != 0) { - simple_dialog(ESD_TYPE_WARN, NULL, - "Unable to parse filter string \"%s\".", cf->dfilter); + if (dfilter_compile(dftext, &dfcode) != 0) { + /* The attempt failed; report an error. */ + simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg); return; } + + /* Was it empty? */ + if (dfcode == NULL) { + /* Yes - free the filter text, and set it to null. */ + g_free(dftext); + dftext = NULL; + } } + /* 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)); @@ -524,21 +1033,51 @@ filter_packets(capture_file *cf) 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. - */ + /* 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; - lastsec = 0; - lastusec = 0; + prevsec = 0; + prevusec = 0; cf->unfiltered_count = cf->count; cf->count = 0; -/* timeout = gtk_timeout_add(250, dfilter_progress_cb, cf);*/ - g_list_foreach(cf->plist, filter_packets_cb, cf); -/* gtk_timeout_remove(timeout);*/ + 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); @@ -554,53 +1093,20 @@ filter_packets(capture_file *cf) gtk_clist_thaw(GTK_CLIST(packet_list)); } -/* Update the progress bar */ -static gint -dfilter_progress_cb(gpointer p) { - capture_file *cf = (capture_file*)p; - - /* 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); - - /* Have GTK+ repaint what is pending */ - while (gtk_events_pending ()) { - gtk_main_iteration(); - } - return TRUE; -} - - -static void -print_packets_cb(gpointer data, gpointer user_data) +int +print_packets(capture_file *cf, print_args_t *print_args) { - frame_data *fd = data; - capture_file *cf = user_data; + 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->count++; - - fseek(cf->fh, fd->file_off, SEEK_SET); - fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh); - - /* create the logical protocol tree */ - protocol_tree = proto_tree_create_root(); - dissect_packet(cf->pd, fd, protocol_tree); - - /* Print the packet */ - proto_tree_print(cf->count, (GNode *)protocol_tree, cf->pd, fd, cf->print_fh); - - proto_tree_free(protocol_tree); -} - -int -print_packets(capture_file *cf, int to_file, const char *dest) -{ - cf->print_fh = open_print_dest(to_file, dest); + 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 */ @@ -613,56 +1119,129 @@ print_packets(capture_file *cf, int to_file, const char *dest) print_preamble(cf->print_fh); #endif - /* - * Iterate through the list of packets, printing each of them. - */ - cf->count = 0; - g_list_foreach(cf->plist, print_packets_cb, cf); + if (print_args->print_summary) { + /* We're printing packet summaries. -#if 0 - print_finale(cf->print_fh); -#endif - - close_print_dest(to_file, cf->print_fh); - cf->print_fh = NULL; - return TRUE; -} + 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; + } -static void -change_time_formats_cb(gpointer data, gpointer user_data) -{ - frame_data *fd = data; - capture_file *cf = user_data; - gint i; - - cf->count++; - - /* 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 no columns that show the time in the "command-line-specified" - format, so there's nothing we need to do. */ - return; + /* 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); + } } - compute_time_stamps(fd, cf); + 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 { + 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); + } - for (i = 0; i < fd->cinfo->num_cols; i++) { - fd->cinfo->col_data[i][0] = '\0'; - } - col_add_cls_time(fd); - for (i = 0; i < fd->cinfo->num_cols; i++) { - if (fd->cinfo->fmt_matx[i][COL_CLS_TIME]) { - /* This is one of the columns that shows the time in - "command-line-specified" format; update it. */ - gtk_clist_set_text(GTK_CLIST(packet_list), cf->count - 1, i, - fd->cinfo->col_data[i]); + /* Print a blank line if we print anything after this. */ + print_separator = TRUE; + } } } - fd->cinfo = NULL; + + 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 @@ -671,6 +1250,7 @@ change_time_formats_cb(gpointer data, gpointer user_data) void change_time_formats(capture_file *cf) { + frame_data *fd; int i; GtkStyle *pl_style; @@ -678,17 +1258,35 @@ change_time_formats(capture_file *cf) screen updates while it happens. */ freeze_clist(cf); - /* - * 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; - lastsec = 0; - lastusec = 0; - cf->count = 0; - g_list_foreach(cf->plist, change_time_formats_cb, 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]); + } + } + } + } + } /* Set the column widths of those columns that show the time in "command-line-specified" format. */ @@ -707,6 +1305,9 @@ change_time_formats(capture_file *cf) 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); @@ -714,35 +1315,63 @@ clear_tree_and_hex_views(void) gtk_text_get_length(GTK_TEXT(byte_view))); gtk_text_thaw(GTK_TEXT(byte_view)); - /* Clear the protocol tree view. */ - gtk_tree_clear_items(GTK_TREE(tree_view), 0, - g_list_length(GTK_TREE(tree_view)->children)); + /* 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))); - /* Get the frame data struct pointer for this frame. */ - cf->fd = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), row); + /* 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; + } - /* Get the data in that frame. */ - fseek(cf->fh, cf->fd->file_off, SEEK_SET); - fread(cf->pd, sizeof(guint8), cf->fd->cap_len, cf->fh); + g_assert(fd != NULL); + + cf->fd = fd; - /* Mark that frame as the selected frame. */ - cf->selected_packet = g_list_index(cf->plist, (gpointer)cf->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. */ @@ -753,6 +1382,8 @@ select_packet(capture_file *cf, int row) /* 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. */ @@ -773,6 +1404,8 @@ unselect_packet(capture_file *cf) /* 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 @@ -909,14 +1542,31 @@ file_open_error_message(int err, int for_writing) switch (err) { - case OPEN_CAP_FILE_NOT_REGULAR: + case WTAP_ERR_NOT_REGULAR_FILE: errmsg = "The file \"%s\" is invalid."; break; - case OPEN_CAP_FILE_UNKNOWN_FORMAT: + 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."; @@ -928,11 +1578,12 @@ file_open_error_message(int err, int for_writing) 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 open the file \"%s\"."; + errmsg = "You do not have permission to read the file \"%s\"."; break; default: - sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.", strerror(err)); + sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.", + wtap_strerror(err)); errmsg = errmsg_errno; break; } @@ -944,7 +1595,8 @@ 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.", strerror(err)); + sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.", + wtap_strerror(err)); return errmsg_errno; } @@ -967,7 +1619,8 @@ file_write_error_message(int err) #endif default: - sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.", strerror(err)); + sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.", + wtap_strerror(err)); errmsg = errmsg_errno; break; }