4 * $Id: file.c,v 1.150 2000/01/08 23:49:25 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 #ifdef NEED_SNPRINTF_H
57 # include "snprintf.h"
60 #ifdef NEED_STRERROR_H
64 #ifdef HAVE_SYS_TYPES_H
65 # include <sys/types.h>
68 #ifdef HAVE_NETINET_IN_H
69 # include <netinet/in.h>
79 #include "simple_dialog.h"
81 #include "gtk/proto_draw.h"
83 #include "conversation.h"
90 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
91 extern guint file_ctx;
93 gboolean auto_scroll_live = FALSE;
95 static guint32 firstsec, firstusec;
96 static guint32 prevsec, prevusec;
98 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
101 static void freeze_clist(capture_file *cf);
102 static void thaw_clist(capture_file *cf);
104 static char *file_rename_error_message(int err);
105 static char *file_close_error_message(int err);
107 /* Update the progress bar this many times when reading a file. */
108 #define N_PROGBAR_UPDATES 100
111 open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
119 wth = wtap_open_offline(fname, &err);
123 /* Find the size of the file. */
126 if (fstat(fd, &cf_stat) < 0) {
132 /* The open succeeded. Close whatever capture file we had open,
133 and fill in the information for this file. */
134 close_cap_file(cf, info_bar);
136 /* Initialize the table of conversations. */
139 /* Initialize protocol-specific variables */
140 init_all_protocols();
145 cf->f_len = cf_stat.st_size;
147 /* Set the file name because we need it to set the follow stream filter.
148 XXX - is that still true? We need it for other reasons, though,
150 cf->filename = g_strdup(fname);
152 /* Indicate whether it's a permanent or temporary file. */
153 cf->is_tempfile = is_tempfile;
155 /* If it's a temporary capture buffer file, mark it as not saved. */
156 cf->user_saved = !is_tempfile;
158 cf->cd_t = wtap_file_type(cf->wth);
163 cf->snap = wtap_snapshot_length(cf->wth);
164 cf->update_progbar = FALSE;
165 cf->progbar_quantum = 0;
166 cf->progbar_nextstep = 0;
167 firstsec = 0, firstusec = 0;
168 prevsec = 0, prevusec = 0;
173 simple_dialog(ESD_TYPE_WARN, NULL,
174 file_open_error_message(err, FALSE), fname);
178 /* Reset everything to a pristine state */
180 close_cap_file(capture_file *cf, void *w)
182 frame_data *fd, *fd_next;
192 /* We have no file open... */
193 if (cf->filename != NULL) {
194 /* If it's a temporary file, remove it. */
196 unlink(cf->filename);
197 g_free(cf->filename);
200 /* ...which means we have nothing to save. */
201 cf->user_saved = FALSE;
203 for (fd = cf->plist; fd != NULL; fd = fd_next) {
207 if (cf->rfcode != NULL) {
208 dfilter_destroy(cf->rfcode);
212 cf->plist_end = NULL;
213 unselect_packet(cf); /* nothing to select */
215 /* Clear the packet list. */
216 gtk_clist_freeze(GTK_CLIST(packet_list));
217 gtk_clist_clear(GTK_CLIST(packet_list));
218 gtk_clist_thaw(GTK_CLIST(packet_list));
220 /* Clear any file-related status bar messages.
221 XXX - should be "clear *ALL* file-related status bar messages;
222 will there ever be more than one on the stack? */
223 gtk_statusbar_pop(GTK_STATUSBAR(w), file_ctx);
225 /* Restore the standard title bar message. */
226 set_main_window_name("The Ethereal Network Analyzer");
228 /* Disable all menu items that make sense only if you have a capture. */
229 set_menus_for_capture_file(FALSE);
230 set_menus_for_unsaved_capture_file(FALSE);
231 set_menus_for_captured_packets(FALSE);
232 set_menus_for_selected_packet(FALSE);
235 /* Set the file name in the status line, in the name for the main window,
236 and in the name for the main window's icon. */
238 set_display_filename(capture_file *cf)
242 gchar *done_fmt = " File: %s Drops: %u";
244 gchar *win_name_fmt = "%s - Ethereal";
247 if (!cf->is_tempfile) {
248 /* Get the last component of the file name, and put that in the
250 if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
251 name_ptr = cf->filename;
255 /* The file we read is a temporary file from a live capture;
256 we don't mention its name in the status bar. */
257 name_ptr = "<capture>";
260 msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
261 done_msg = g_malloc(msg_len);
262 snprintf(done_msg, msg_len, done_fmt, name_ptr, cf->drops);
263 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
266 msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
267 win_name = g_malloc(msg_len);
268 snprintf(win_name, msg_len, win_name_fmt, name_ptr);
269 set_main_window_name(win_name);
274 read_cap_file(capture_file *cf)
276 gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
281 char errmsg_errno[1024+1];
282 gchar err_str[2048+1];
284 if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
285 name_ptr = cf->filename;
289 msg_len = strlen(name_ptr) + strlen(load_fmt) + 2;
290 load_msg = g_malloc(msg_len);
291 snprintf(load_msg, msg_len, load_fmt, name_ptr);
292 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
295 cf->update_progbar = TRUE;
296 /* Update the progress bar when it gets to this value. */
297 cf->progbar_nextstep = 0;
298 /* When we reach the value that triggers a progress bar update,
299 bump that value by this amount. */
300 cf->progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
303 proto_tree_is_visible = FALSE;
304 success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
305 /* Set the file encapsulation type now; we don't know what it is until
306 we've looked at all the packets, as we don't know until then whether
307 there's more than one type (and thus whether it's
308 WTAP_ENCAP_PER_PACKET). */
309 cf->lnk_t = wtap_file_encap(cf->wth);
312 cf->filed = open(cf->filename, O_RDONLY);
313 cf->fh = filed_open(cf->filed, "r");
314 cf->current_frame = cf->first_displayed;
315 /* Make the first row the selected row. */
316 gtk_clist_select_row(GTK_CLIST(packet_list), 0, -1);
319 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
320 gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
322 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
323 set_display_filename(cf);
325 /* Enable menu items that make sense if you have a capture file you've
327 set_menus_for_capture_file(TRUE);
328 set_menus_for_unsaved_capture_file(!cf->user_saved);
330 /* Enable menu items that make sense if you have some captured packets. */
331 set_menus_for_captured_packets(TRUE);
334 /* Put up a message box noting that the read failed somewhere along
335 the line. Don't throw out the stuff we managed to read, though,
339 case WTAP_ERR_CANT_READ:
340 errmsg = "An attempt to read from the file failed for"
341 " some unknown reason.";
344 case WTAP_ERR_SHORT_READ:
345 errmsg = "The capture file appears to have been cut short"
346 " in the middle of a packet.";
349 case WTAP_ERR_BAD_RECORD:
350 errmsg = "The capture file appears to be damaged or corrupt.";
354 sprintf(errmsg_errno, "An error occurred while reading the"
355 " capture file: %s.", wtap_strerror(err));
356 errmsg = errmsg_errno;
359 snprintf(err_str, sizeof err_str, errmsg);
360 simple_dialog(ESD_TYPE_WARN, NULL, err_str);
368 start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
373 err = open_cap_file(fname, is_tempfile, cf);
375 /* Disable menu items that make no sense if you're currently running
377 set_menus_for_capture_in_progress(TRUE);
379 /* Enable menu items that make sense if you have some captured
380 packets (yes, I know, we don't have any *yet*). */
381 set_menus_for_captured_packets(TRUE);
383 for (i = 0; i < cf->cinfo.num_cols; i++) {
384 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
385 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
387 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
388 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
389 cf->cinfo.col_width[i]);
390 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
394 /* Yes, "open_cap_file()" set this - but it set it to a file handle
395 from Wiretap, which will be closed when we close the file; we
396 want it to remain open even after that, so that we can read
397 packet data from it. */
398 cf->fh = file_open(fname, "r");
400 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx,
401 " <live capture in progress>");
407 continue_tail_cap_file(capture_file *cf, int to_read)
411 gtk_clist_freeze(GTK_CLIST(packet_list));
413 wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
415 gtk_clist_thaw(GTK_CLIST(packet_list));
416 if (auto_scroll_live && cf->plist_end != NULL)
417 gtk_clist_moveto(GTK_CLIST(packet_list),
418 cf->plist_end->row, -1, 1.0, 1.0);
423 finish_tail_cap_file(capture_file *cf)
427 gtk_clist_freeze(GTK_CLIST(packet_list));
429 wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
432 if (auto_scroll_live && cf->plist_end != NULL)
433 gtk_clist_moveto(GTK_CLIST(packet_list),
434 cf->plist_end->row, -1, 1.0, 1.0);
436 /* Set the file encapsulation type now; we don't know what it is until
437 we've looked at all the packets, as we don't know until then whether
438 there's more than one type (and thus whether it's
439 WTAP_ENCAP_PER_PACKET). */
440 cf->lnk_t = wtap_file_encap(cf->wth);
442 /* There's nothing more to read from the capture file - close it. */
446 /* Pop the "<live capture in progress>" message off the status bar. */
447 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
449 set_display_filename(cf);
451 /* Enable menu items that make sense if you're not currently running
453 set_menus_for_capture_in_progress(FALSE);
455 /* Enable menu items that make sense if you have a capture file
456 you've finished reading. */
457 set_menus_for_capture_file(TRUE);
458 set_menus_for_unsaved_capture_file(!cf->user_saved);
462 #endif /* HAVE_LIBPCAP */
465 color_filter_t *colorf;
466 proto_tree *protocol_tree;
468 } apply_color_filter_args;
471 * If no color filter has been applied, apply this one.
472 * (The "if no color filter has been applied" is to handle the case where
473 * more than one color filter matches the packet.)
476 apply_color_filter(gpointer filter_arg, gpointer argp)
478 color_filter_t *colorf = filter_arg;
479 apply_color_filter_args *args = argp;
481 if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
482 if (dfilter_apply(colorf->c_colorfilter, args->protocol_tree, args->pd))
483 args->colorf = colorf;
488 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
490 apply_color_filter_args args;
492 proto_tree *protocol_tree = NULL;
494 /* We don't yet have a color filter to apply. */
497 fdata->num = cf->count;
499 /* If we don't have the time stamp of the first packet in the
500 capture, it's because this is the first packet. Save the time
501 stamp of this packet as the time stamp of the first packet. */
502 if (!firstsec && !firstusec) {
503 firstsec = fdata->abs_secs;
504 firstusec = fdata->abs_usecs;
507 /* Get the time elapsed between the first packet and this packet. */
508 cf->esec = fdata->abs_secs - firstsec;
509 if (firstusec <= fdata->abs_usecs) {
510 cf->eusec = fdata->abs_usecs - firstusec;
512 cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
516 fdata->cinfo = &cf->cinfo;
517 for (i = 0; i < fdata->cinfo->num_cols; i++) {
518 fdata->cinfo->col_data[i][0] = '\0';
521 /* Apply the filters */
522 if (cf->dfcode != NULL || filter_list != NULL) {
523 protocol_tree = proto_tree_create_root();
524 dissect_packet(buf, fdata, protocol_tree);
525 if (cf->dfcode != NULL)
526 fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
528 fdata->passed_dfilter = TRUE;
530 /* Apply color filters, if we have any. */
531 if (filter_list != NULL) {
532 args.protocol_tree = protocol_tree;
534 g_slist_foreach(filter_list, apply_color_filter, &args);
536 proto_tree_free(protocol_tree);
541 protocol_tree = proto_tree_create_root();
543 dissect_packet(buf, fdata, protocol_tree);
544 fdata->passed_dfilter = TRUE;
547 proto_tree_free(protocol_tree);
551 if (fdata->passed_dfilter) {
552 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
553 the first entry is added to it by "real_insert_row()", that row
554 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
555 our version and the vanilla GTK+ version).
557 This means that a "select-row" signal is emitted; this causes
558 "packet_list_select_cb()" to be called, which causes "select_packet()"
561 "select_packet()" searches the list of frames for a frame with the
562 row number passed into it; however, as "gtk_clist_append()", which
563 called "real_insert_row()", hasn't yet returned, we don't know what
564 the row number is, so we can't correctly set "fd->row" for that frame
567 This means that we won't find the frame for that row.
569 We can't assume that there's only one frame in the frame list,
570 either, as we may be filtering the display.
572 Therefore, we set "fdata->row" to 0, under the assumption that
573 the row number passed to "select_packet()" will be 0 (as we're
574 adding the first row to the list; it gets set to the proper
578 /* If we don't have the time stamp of the previous displayed packet,
579 it's because this is the first displayed packet. Save the time
580 stamp of this packet as the time stamp of the previous displayed
582 if (!prevsec && !prevusec) {
583 prevsec = fdata->abs_secs;
584 prevusec = fdata->abs_usecs;
587 /* Get the time elapsed between the first packet and this packet. */
588 fdata->rel_secs = cf->esec;
589 fdata->rel_usecs = cf->eusec;
591 /* Get the time elapsed between the previous displayed packet and
593 fdata->del_secs = fdata->abs_secs - prevsec;
594 if (prevusec <= fdata->abs_usecs) {
595 fdata->del_usecs = fdata->abs_usecs - prevusec;
597 fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
600 prevsec = fdata->abs_secs;
601 prevusec = fdata->abs_usecs;
603 fill_in_columns(fdata);
605 row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
608 if (filter_list != NULL && (args.colorf != NULL)) {
609 gtk_clist_set_background(GTK_CLIST(packet_list), row,
610 &args.colorf->bg_color);
611 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
612 &args.colorf->fg_color);
614 gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
615 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
618 /* If we haven't yet seen the first frame, this is it. */
619 if (cf->first_displayed == NULL)
620 cf->first_displayed = fdata;
622 /* This is the last frame we've seen so far. */
623 cf->last_displayed = fdata;
625 /* If this was the current frame, remember the row it's in, so
626 we can arrange that it's on the screen when we're done. */
627 if (cf->current_frame == fdata)
628 cf->current_row = row;
630 fdata->row = -1; /* not in the display */
635 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
638 capture_file *cf = (capture_file *) user;
640 proto_tree *protocol_tree;
641 frame_data *plist_end;
645 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
646 when we update it, we have to run the GTK+ main loop to get it
647 to repaint what's pending, and doing so may involve an "ioctl()"
648 to see if there's any pending input from an X server, and doing
649 that for every packet can be costly, especially on a big file.
651 Do so only if we were told to do so; when reading a capture file
652 being updated by a live capture, we don't do so (as we're not
653 "done" until the capture stops, so we don't know how close to
656 if (cf->update_progbar && offset >= cf->progbar_nextstep) {
657 file_pos = lseek(cf->filed, 0, SEEK_CUR);
658 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
659 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), prog_val);
660 cf->progbar_nextstep += cf->progbar_quantum;
661 while (gtk_events_pending())
662 gtk_main_iteration();
665 /* Allocate the next list entry, and add it to the list. */
666 fdata = (frame_data *) g_malloc(sizeof(frame_data));
670 fdata->pkt_len = phdr->len;
671 fdata->cap_len = phdr->caplen;
672 fdata->file_off = offset;
673 fdata->lnk_t = phdr->pkt_encap;
674 fdata->abs_secs = phdr->ts.tv_sec;
675 fdata->abs_usecs = phdr->ts.tv_usec;
676 fdata->encoding = CHAR_ASCII;
677 fdata->pseudo_header = phdr->pseudo_header;
682 protocol_tree = proto_tree_create_root();
683 dissect_packet(buf, fdata, protocol_tree);
684 passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
685 proto_tree_free(protocol_tree);
688 plist_end = cf->plist_end;
689 fdata->prev = plist_end;
690 if (plist_end != NULL)
691 plist_end->next = fdata;
694 cf->plist_end = fdata;
697 add_packet_to_packet_list(fdata, cf, buf);
703 filter_packets(capture_file *cf, gchar *dftext)
707 if (dftext == NULL) {
708 /* The new filter is an empty filter (i.e., display all packets). */
712 * We have a filter; try to compile it.
714 if (dfilter_compile(dftext, &dfcode) != 0) {
715 /* The attempt failed; report an error. */
716 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
721 if (dfcode == NULL) {
722 /* Yes - free the filter text, and set it to null. */
728 /* We have a valid filter. Replace the current filter. */
729 if (cf->dfilter != NULL)
731 cf->dfilter = dftext;
732 if (cf->dfcode != NULL)
733 dfilter_destroy(cf->dfcode);
736 /* Now go through the list of packets we've read from the capture file,
737 applying the current display filter, and, if the packet passes the
738 display filter, add it to the summary display, appropriately
739 colored. (That's how we colorize the display - it's like filtering
740 the display, only we don't install a new filter.) */
741 colorize_packets(cf);
746 colorize_packets(capture_file *cf)
749 guint32 progbar_quantum;
750 guint32 progbar_nextstep;
753 /* We need to re-initialize all the state information that protocols
754 keep, because we're making a fresh pass through all the packets. */
756 /* Initialize the table of conversations. */
759 /* Initialize protocol-specific variables */
760 init_all_protocols();
762 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
764 /* Freeze the packet list while we redo it, so we don't get any
765 screen updates while it happens. */
766 gtk_clist_freeze(GTK_CLIST(packet_list));
769 gtk_clist_clear(GTK_CLIST(packet_list));
771 /* We don't yet know which will be the first and last frames displayed. */
772 cf->first_displayed = NULL;
773 cf->last_displayed = NULL;
775 /* If a packet was selected, we don't know yet what row, if any, it'll
777 cf->current_row = -1;
779 /* Iterate through the list of packets, calling a routine
780 to run the filter on the packet, see if it matches, and
781 put it in the display list if so. */
787 proto_tree_is_visible = FALSE;
789 /* Update the progress bar when it gets to this value. */
790 progbar_nextstep = 0;
791 /* When we reach the value that triggers a progress bar update,
792 bump that value by this amount. */
793 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
794 /* Count of packets at which we've looked. */
797 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
799 for (fd = cf->plist; fd != NULL; fd = fd->next) {
800 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
801 when we update it, we have to run the GTK+ main loop to get it
802 to repaint what's pending, and doing so may involve an "ioctl()"
803 to see if there's any pending input from an X server, and doing
804 that for every packet can be costly, especially on a big file. */
805 if (count >= progbar_nextstep) {
806 /* let's not divide by zero. I should never be started
807 * with count == 0, so let's assert that
809 g_assert(cf->count > 0);
811 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
812 (gfloat) count / cf->count);
814 progbar_nextstep += progbar_quantum;
815 while (gtk_events_pending())
816 gtk_main_iteration();
821 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
823 add_packet_to_packet_list(fd, cf, cf->pd);
826 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
828 if (cf->current_row != -1) {
829 /* The current frame passed the filter; make sure it's visible. */
830 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), cf->current_row))
831 gtk_clist_moveto(GTK_CLIST(packet_list), cf->current_row, -1, 0.0, 0.0);
832 if (cf->current_frame_is_selected) {
833 /* It was selected, so re-select it. */
834 gtk_clist_select_row(GTK_CLIST(packet_list), cf->current_row, -1);
836 finfo_selected = NULL;
838 /* The current frame didn't pass the filter; make the first frame
839 the current frame, and leave it unselected. */
841 cf->current_frame = cf->first_displayed;
844 /* Unfreeze the packet list. */
845 gtk_clist_thaw(GTK_CLIST(packet_list));
848 #define MAX_LINE_LENGTH 256
851 print_packets(capture_file *cf, print_args_t *print_args)
855 guint32 progbar_quantum;
856 guint32 progbar_nextstep;
858 proto_tree *protocol_tree;
859 gint *col_widths = NULL;
861 gboolean print_separator;
862 char line_buf[MAX_LINE_LENGTH+1]; /* static-sized buffer! */
866 cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
867 if (cf->print_fh == NULL)
868 return FALSE; /* attempt to open destination failed */
870 print_preamble(cf->print_fh, print_args->format);
872 if (print_args->print_summary) {
873 /* We're printing packet summaries.
875 Find the widths for each of the columns - maximum of the
876 width of the title and the width of the data - and print
877 the column titles. */
878 col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
880 for (i = 0; i < cf->cinfo.num_cols; i++) {
881 /* Don't pad the last column. */
882 if (i == cf->cinfo.num_cols - 1)
885 col_widths[i] = strlen(cf->cinfo.col_title[i]);
886 data_width = get_column_char_width(get_column_format(i));
887 if (data_width > col_widths[i])
888 col_widths[i] = data_width;
891 /* Right-justify the packet number column. */
892 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
893 sprintf_len = sprintf(cp, "%*s", col_widths[i], cf->cinfo.col_title[i]);
895 sprintf_len = sprintf(cp, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
897 if (i == cf->cinfo.num_cols - 1)
903 print_line(cf->print_fh, print_args->format, line_buf);
906 print_separator = FALSE;
907 proto_tree_is_visible = TRUE;
909 /* Update the progress bar when it gets to this value. */
910 progbar_nextstep = 0;
911 /* When we reach the value that triggers a progress bar update,
912 bump that value by this amount. */
913 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
914 /* Count of packets at which we've looked. */
917 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
919 /* Iterate through the list of packets, printing the packets that
920 were selected by the current display filter. */
921 for (fd = cf->plist; fd != NULL; fd = fd->next) {
922 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
923 when we update it, we have to run the GTK+ main loop to get it
924 to repaint what's pending, and doing so may involve an "ioctl()"
925 to see if there's any pending input from an X server, and doing
926 that for every packet can be costly, especially on a big file. */
927 if (count >= progbar_nextstep) {
928 /* let's not divide by zero. I should never be started
929 * with count == 0, so let's assert that
931 g_assert(cf->count > 0);
933 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
934 (gfloat) count / cf->count);
935 progbar_nextstep += progbar_quantum;
936 while (gtk_events_pending())
937 gtk_main_iteration();
941 if (fd->passed_dfilter) {
942 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
943 if (print_args->print_summary) {
944 /* Fill in the column information, but don't bother creating
945 the logical protocol tree. */
946 fd->cinfo = &cf->cinfo;
947 for (i = 0; i < fd->cinfo->num_cols; i++) {
948 fd->cinfo->col_data[i][0] = '\0';
950 dissect_packet(cf->pd, fd, NULL);
953 for (i = 0; i < cf->cinfo.num_cols; i++) {
954 /* Right-justify the packet number column. */
955 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
956 sprintf_len = sprintf(cp, "%*s", col_widths[i], cf->cinfo.col_data[i]);
958 sprintf_len = sprintf(cp, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
960 if (i == cf->cinfo.num_cols - 1)
966 print_line(cf->print_fh, print_args->format, line_buf);
969 print_line(cf->print_fh, print_args->format, "\n");
971 /* Create the logical protocol tree. */
972 protocol_tree = proto_tree_create_root();
973 dissect_packet(cf->pd, fd, protocol_tree);
975 /* Print the information in that tree. */
976 proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
977 cf->pd, fd, cf->print_fh);
979 proto_tree_free(protocol_tree);
981 if (print_args->print_hex) {
982 /* Print the full packet data as hex. */
983 print_hex_data(cf->print_fh, print_args->format, cf->pd,
984 fd->cap_len, fd->encoding);
987 /* Print a blank line if we print anything after this. */
988 print_separator = TRUE;
993 if (col_widths != NULL)
996 print_finale(cf->print_fh, print_args->format);
998 close_print_dest(print_args->to_file, cf->print_fh);
1000 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
1002 cf->print_fh = NULL;
1006 /* Scan through the packet list and change all columns that use the
1007 "command-line-specified" time stamp format to use the current
1008 value of that format. */
1010 change_time_formats(capture_file *cf)
1016 /* Freeze the packet list while we redo it, so we don't get any
1017 screen updates while it happens. */
1020 /* Iterate through the list of packets, checking whether the packet
1021 is in a row of the summary list and, if so, whether there are
1022 any columns that show the time in the "command-line-specified"
1023 format and, if so, update that row. */
1024 for (fd = cf->plist; fd != NULL; fd = fd->next) {
1025 if (fd->row != -1) {
1026 /* This packet is in the summary list, on row "fd->row". */
1028 /* XXX - there really should be a way of checking "cf->cinfo" for this;
1029 the answer isn't going to change from packet to packet, so we should
1030 simply skip all the "change_time_formats()" work if we're not
1031 changing anything. */
1032 fd->cinfo = &cf->cinfo;
1033 if (check_col(fd, COL_CLS_TIME)) {
1034 /* There are columns that show the time in the "command-line-specified"
1035 format; update them. */
1036 for (i = 0; i < cf->cinfo.num_cols; i++) {
1037 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
1038 /* This is one of the columns that shows the time in
1039 "command-line-specified" format; update it. */
1040 cf->cinfo.col_data[i][0] = '\0';
1041 col_set_cls_time(fd, i);
1042 gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
1043 cf->cinfo.col_data[i]);
1050 /* Set the column widths of those columns that show the time in
1051 "command-line-specified" format. */
1052 pl_style = gtk_widget_get_style(packet_list);
1053 for (i = 0; i < cf->cinfo.num_cols; i++) {
1054 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
1055 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1056 get_column_width(COL_CLS_TIME, pl_style->font));
1060 /* Unfreeze the packet list. */
1065 clear_tree_and_hex_views(void)
1067 /* Clear the hex dump. */
1068 gtk_text_freeze(GTK_TEXT(byte_view));
1069 gtk_text_set_point(GTK_TEXT(byte_view), 0);
1070 gtk_text_forward_delete(GTK_TEXT(byte_view),
1071 gtk_text_get_length(GTK_TEXT(byte_view)));
1072 gtk_text_thaw(GTK_TEXT(byte_view));
1074 /* Remove all nodes in ctree. This is how it's done in testgtk.c in GTK+ */
1075 gtk_clist_clear ( GTK_CLIST(tree_view) );
1080 find_packet(capture_file *cf, dfilter *sfcode)
1082 frame_data *start_fd;
1084 frame_data *new_fd = NULL;
1085 guint32 progbar_quantum;
1086 guint32 progbar_nextstep;
1088 proto_tree *protocol_tree;
1090 start_fd = cf->current_frame;
1091 if (start_fd != NULL) {
1092 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
1094 /* Iterate through the list of packets, starting at the packet we've
1095 picked, calling a routine to run the filter on the packet, see if
1096 it matches, and stop if so. */
1100 proto_tree_is_visible = FALSE;
1102 /* Update the progress bar when it gets to this value. */
1103 progbar_nextstep = 0;
1104 /* When we reach the value that triggers a progress bar update,
1105 bump that value by this amount. */
1106 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1107 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
1111 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1112 when we update it, we have to run the GTK+ main loop to get it
1113 to repaint what's pending, and doing so may involve an "ioctl()"
1114 to see if there's any pending input from an X server, and doing
1115 that for every packet can be costly, especially on a big file. */
1116 if (count >= progbar_nextstep) {
1117 /* let's not divide by zero. I should never be started
1118 * with count == 0, so let's assert that
1120 g_assert(cf->count > 0);
1122 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
1123 (gfloat) count / cf->count);
1125 progbar_nextstep += progbar_quantum;
1126 while (gtk_events_pending())
1127 gtk_main_iteration();
1130 /* Go past the current frame. */
1131 if (cf->sbackward) {
1132 /* Go on to the previous frame. */
1135 fd = cf->plist_end; /* wrap around */
1137 /* Go on to the next frame. */
1140 fd = cf->plist; /* wrap around */
1143 if (fd == start_fd) {
1144 /* We're back to the frame we were on originally. The search
1151 /* Is this packet in the display? */
1152 if (fd->passed_dfilter) {
1153 /* Yes. Does it match the search filter? */
1154 protocol_tree = proto_tree_create_root();
1155 wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1156 dissect_packet(cf->pd, fd, protocol_tree);
1157 if (dfilter_apply(sfcode, protocol_tree, cf->pd)) {
1159 break; /* found it! */
1164 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
1167 if (new_fd != NULL) {
1168 /* We found a frame. Make it visible, and select it. */
1169 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), new_fd->row))
1170 gtk_clist_moveto(GTK_CLIST(packet_list), new_fd->row, -1, 0.0, 0.0);
1172 /* XXX - why is there no "gtk_clist_set_focus_row()", so that we
1173 can make the row for the frame we found the focus row?
1177 http://www.gnome.org/mailing-lists/archives/gtk-list/2000-January/0038.shtml
1180 GTK_CLIST(packet_list)->focus_row = new_fd->row;
1181 gtk_clist_select_row(GTK_CLIST(packet_list), new_fd->row, -1);
1182 return TRUE; /* success */
1184 return FALSE; /* failure */
1188 goto_frame(capture_file *cf, guint fnumber)
1192 for (fd = cf->plist; fd != NULL && fd->num < fnumber; fd = fd->next)
1196 return NO_SUCH_FRAME; /* we didn't find that frame */
1197 if (!fd->passed_dfilter)
1198 return FRAME_NOT_DISPLAYED; /* the frame with that number isn't displayed */
1200 /* We found that frame, and it's currently being displayed.
1201 Make it visible, and select it. */
1202 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), fd->row))
1203 gtk_clist_moveto(GTK_CLIST(packet_list), fd->row, -1, 0.0, 0.0);
1205 /* See above complaint about the lack of "gtk_clist_set_focus_row()". */
1206 GTK_CLIST(packet_list)->focus_row = fd->row;
1207 gtk_clist_select_row(GTK_CLIST(packet_list), fd->row, -1);
1211 /* Select the packet on a given row. */
1213 select_packet(capture_file *cf, int row)
1218 /* Search through the list of frames to see which one is in
1220 for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
1225 g_assert(fd != NULL);
1227 /* Record that this frame is the current frame, and that it's selected. */
1228 cf->current_frame = fd;
1229 cf->current_frame_is_selected = TRUE;
1231 /* Get the data in that frame. */
1232 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1234 /* Create the logical protocol tree. */
1235 if (cf->protocol_tree)
1236 proto_tree_free(cf->protocol_tree);
1237 cf->protocol_tree = proto_tree_create_root();
1238 proto_tree_is_visible = TRUE;
1239 dissect_packet(cf->pd, cf->current_frame, cf->protocol_tree);
1241 /* Display the GUI protocol tree and hex dump. */
1242 clear_tree_and_hex_views();
1243 proto_tree_draw(cf->protocol_tree, tree_view);
1244 packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->current_frame->cap_len,
1245 -1, -1, cf->current_frame->encoding);
1247 /* A packet is selected. */
1248 set_menus_for_selected_packet(TRUE);
1251 /* Unselect the selected packet, if any. */
1253 unselect_packet(capture_file *cf)
1255 cf->current_frame_is_selected = FALSE;
1257 /* Destroy the protocol tree for that packet. */
1258 if (cf->protocol_tree != NULL) {
1259 proto_tree_free(cf->protocol_tree);
1260 cf->protocol_tree = NULL;
1263 finfo_selected = NULL;
1265 /* Clear out the display of that packet. */
1266 clear_tree_and_hex_views();
1268 /* No packet is selected. */
1269 set_menus_for_selected_packet(FALSE);
1273 freeze_clist(capture_file *cf)
1277 /* Make the column sizes static, so they don't adjust while
1278 we're reading the capture file (freezing the clist doesn't
1279 seem to suffice). */
1280 for (i = 0; i < cf->cinfo.num_cols; i++)
1281 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
1282 gtk_clist_freeze(GTK_CLIST(packet_list));
1286 thaw_clist(capture_file *cf)
1290 for (i = 0; i < cf->cinfo.num_cols; i++) {
1291 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
1292 /* Set this column's width to the appropriate value. */
1293 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1294 cf->cinfo.col_width[i]);
1296 /* Make this column's size dynamic, so that it adjusts to the
1297 appropriate size. */
1298 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1301 gtk_clist_thaw(GTK_CLIST(packet_list));
1303 /* Hopefully, the columns have now gotten their appropriate sizes;
1304 make them resizeable - a column that auto-resizes cannot be
1305 resized by the user, and *vice versa*. */
1306 for (i = 0; i < cf->cinfo.num_cols; i++)
1307 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
1311 save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
1314 gchar *from_filename;
1315 gchar *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
1319 int from_fd, to_fd, nread, nwritten;
1322 struct wtap_pkthdr hdr;
1325 if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
1329 msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
1330 save_msg = g_malloc(msg_len);
1331 snprintf(save_msg, msg_len, save_fmt, name_ptr);
1332 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
1335 if (!save_filtered && save_format == cf->cd_t) {
1336 /* We're not filtering packets, and we're saving it in the format
1337 it's already in, so we can just move or copy the raw data. */
1339 /* In this branch, we set "err" only if we get an error, so we
1340 must first clear it. */
1342 if (cf->is_tempfile) {
1343 /* The file being saved is a temporary file from a live
1344 capture, so it doesn't need to stay around under that name;
1345 first, try renaming the capture buffer file to the new name. */
1346 if (rename(cf->filename, fname) == 0) {
1347 /* That succeeded - there's no need to copy the source file. */
1348 from_filename = NULL;
1351 if (errno == EXDEV) {
1352 /* They're on different file systems, so we have to copy the
1355 from_filename = cf->filename;
1357 /* The rename failed, but not because they're on different
1358 file systems - put up an error message. (Or should we
1359 just punt and try to copy? The only reason why I'd
1360 expect the rename to fail and the copy to succeed would
1361 be if we didn't have permission to remove the file from
1362 the temporary directory, and that might be fixable - but
1363 is it worth requiring the user to go off and fix it?) */
1365 simple_dialog(ESD_TYPE_WARN, NULL,
1366 file_rename_error_message(err), fname);
1371 /* It's a permanent file, so we should copy it, and not remove the
1374 from_filename = cf->filename;
1377 /* Copy the file, if we haven't moved it. */
1379 /* Copy the raw bytes of the file. */
1380 from_fd = open(from_filename, O_RDONLY);
1383 simple_dialog(ESD_TYPE_WARN, NULL,
1384 file_open_error_message(err, TRUE), from_filename);
1388 to_fd = creat(fname, 0644);
1391 simple_dialog(ESD_TYPE_WARN, NULL,
1392 file_open_error_message(err, TRUE), fname);
1397 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
1398 nwritten = write(to_fd, pd, nread);
1399 if (nwritten < nread) {
1403 err = WTAP_ERR_SHORT_WRITE;
1404 simple_dialog(ESD_TYPE_WARN, NULL,
1405 file_write_error_message(err), fname);
1413 simple_dialog(ESD_TYPE_WARN, NULL,
1414 file_read_error_message(err), from_filename);
1420 if (close(to_fd) < 0) {
1422 simple_dialog(ESD_TYPE_WARN, NULL,
1423 file_close_error_message(err), fname);
1428 /* Either we're filtering packets, or we're saving in a different
1429 format; we can't do that by copying or moving the capture file,
1430 we have to do it by writing the packets out in Wiretap. */
1431 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
1433 simple_dialog(ESD_TYPE_WARN, NULL,
1434 file_open_error_message(err, TRUE), fname);
1438 /* XXX - have a way to save only the packets currently selected by
1441 If we do that, should we make that file the current file? If so,
1442 it means we can no longer get at the other packets. What does
1444 for (fd = cf->plist; fd != NULL; fd = fd->next) {
1445 /* XXX - do a progress bar */
1446 if (!save_filtered || fd->passed_dfilter) {
1447 /* Either we're saving all frames, or we're saving filtered frames
1448 and this one passed the display filter - save it. */
1449 hdr.ts.tv_sec = fd->abs_secs;
1450 hdr.ts.tv_usec = fd->abs_usecs;
1451 hdr.caplen = fd->cap_len;
1452 hdr.len = fd->pkt_len;
1453 hdr.pkt_encap = fd->lnk_t;
1454 hdr.pseudo_header = fd->pseudo_header;
1455 wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, pd, fd->cap_len);
1457 if (!wtap_dump(pdh, &hdr, pd, &err)) {
1458 simple_dialog(ESD_TYPE_WARN, NULL,
1459 file_write_error_message(err), fname);
1460 wtap_dump_close(pdh, &err);
1466 if (!wtap_dump_close(pdh, &err)) {
1467 simple_dialog(ESD_TYPE_WARN, NULL,
1468 file_close_error_message(err), fname);
1475 /* Pop the "Saving:" message off the status bar. */
1476 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1478 if (!save_filtered) {
1479 /* We saved the entire capture, not just some packets from it.
1480 Open and read the file we saved it to.
1482 XXX - this is somewhat of a waste; we already have the
1483 packets, all this gets us is updated file type information
1484 (which we could just stuff into "cf"), and having the new
1485 file be the one we have opened and from which we're reading
1486 the data, and it means we have to spend time opening and
1487 reading the file, which could be a significant amount of
1488 time if the file is large. */
1489 cf->user_saved = TRUE;
1491 if ((err = open_cap_file(fname, FALSE, cf)) == 0) {
1492 /* XXX - report errors if this fails? */
1493 err = read_cap_file(cf);
1494 set_menus_for_unsaved_capture_file(FALSE);
1502 file_open_error_message(int err, int for_writing)
1505 static char errmsg_errno[1024+1];
1509 case WTAP_ERR_NOT_REGULAR_FILE:
1510 errmsg = "The file \"%s\" is invalid.";
1513 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
1514 case WTAP_ERR_UNSUPPORTED:
1515 /* Seen only when opening a capture file for reading. */
1516 errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
1519 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
1520 /* Seen only when opening a capture file for writing. */
1521 errmsg = "Ethereal does not support writing capture files in that format.";
1524 case WTAP_ERR_UNSUPPORTED_ENCAP:
1525 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
1526 /* Seen only when opening a capture file for writing. */
1527 errmsg = "Ethereal cannot save this capture in that format.";
1530 case WTAP_ERR_BAD_RECORD:
1531 errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1534 case WTAP_ERR_CANT_OPEN:
1536 errmsg = "The file \"%s\" could not be created for some unknown reason.";
1538 errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1541 case WTAP_ERR_SHORT_READ:
1542 errmsg = "The file \"%s\" appears to have been cut short"
1543 " in the middle of a packet.";
1546 case WTAP_ERR_SHORT_WRITE:
1547 errmsg = "A full header couldn't be written to the file \"%s\".";
1552 errmsg = "The path to the file \"%s\" does not exist.";
1554 errmsg = "The file \"%s\" does not exist.";
1559 errmsg = "You do not have permission to create or write to the file \"%s\".";
1561 errmsg = "You do not have permission to read the file \"%s\".";
1565 sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1566 wtap_strerror(err));
1567 errmsg = errmsg_errno;
1574 file_rename_error_message(int err)
1577 static char errmsg_errno[1024+1];
1582 errmsg = "The path to the file \"%s\" does not exist.";
1586 errmsg = "You do not have permission to move the capture file to \"%s\".";
1590 sprintf(errmsg_errno, "The file \"%%s\" could not be moved: %s.",
1591 wtap_strerror(err));
1592 errmsg = errmsg_errno;
1599 file_read_error_message(int err)
1601 static char errmsg_errno[1024+1];
1603 sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
1604 wtap_strerror(err));
1605 return errmsg_errno;
1609 file_write_error_message(int err)
1612 static char errmsg_errno[1024+1];
1617 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1622 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1627 sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
1628 wtap_strerror(err));
1629 errmsg = errmsg_errno;
1635 /* Check for write errors - if the file is being written to an NFS server,
1636 a write error may not show up until the file is closed, as NFS clients
1637 might not send writes to the server until the "write()" call finishes,
1638 so that the write may fail on the server but the "write()" may succeed. */
1640 file_close_error_message(int err)
1643 static char errmsg_errno[1024+1];
1647 case WTAP_ERR_CANT_CLOSE:
1648 errmsg = "The file \"%s\" couldn't be closed for some unknown reason.";
1651 case WTAP_ERR_SHORT_WRITE:
1652 errmsg = "Not all the data could be written to the file \"%s\".";
1656 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1661 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1666 sprintf(errmsg_errno, "An error occurred while closing the file \"%%s\": %s.",
1667 wtap_strerror(err));
1668 errmsg = errmsg_errno;