4 * $Id: file.c,v 1.146 2000/01/03 06:59:08 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->unfiltered_count = cf->count;
315 cf->current_frame = cf->first_displayed;
316 /* Make the first row the selected row. */
317 gtk_clist_select_row(GTK_CLIST(packet_list), 0, -1);
320 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
321 gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
323 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
324 set_display_filename(cf);
326 /* Enable menu items that make sense if you have a capture file you've
328 set_menus_for_capture_file(TRUE);
329 set_menus_for_unsaved_capture_file(!cf->user_saved);
331 /* Enable menu items that make sense if you have some captured packets. */
332 set_menus_for_captured_packets(TRUE);
335 /* Put up a message box noting that the read failed somewhere along
336 the line. Don't throw out the stuff we managed to read, though,
340 case WTAP_ERR_CANT_READ:
341 errmsg = "An attempt to read from the file failed for"
342 " some unknown reason.";
345 case WTAP_ERR_SHORT_READ:
346 errmsg = "The capture file appears to have been cut short"
347 " in the middle of a packet.";
350 case WTAP_ERR_BAD_RECORD:
351 errmsg = "The capture file appears to be damaged or corrupt.";
355 sprintf(errmsg_errno, "An error occurred while reading the"
356 " capture file: %s.", wtap_strerror(err));
357 errmsg = errmsg_errno;
360 snprintf(err_str, sizeof err_str, errmsg);
361 simple_dialog(ESD_TYPE_WARN, NULL, err_str);
369 start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
374 err = open_cap_file(fname, is_tempfile, cf);
376 /* Disable menu items that make no sense if you're currently running
378 set_menus_for_capture_in_progress(TRUE);
380 /* Enable menu items that make sense if you have some captured
381 packets (yes, I know, we don't have any *yet*). */
382 set_menus_for_captured_packets(TRUE);
384 for (i = 0; i < cf->cinfo.num_cols; i++) {
385 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
386 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
388 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
389 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
390 cf->cinfo.col_width[i]);
391 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
395 /* Yes, "open_cap_file()" set this - but it set it to a file handle
396 from Wiretap, which will be closed when we close the file; we
397 want it to remain open even after that, so that we can read
398 packet data from it. */
399 cf->fh = file_open(fname, "r");
401 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx,
402 " <live capture in progress>");
408 continue_tail_cap_file(capture_file *cf, int to_read)
412 gtk_clist_freeze(GTK_CLIST(packet_list));
414 wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
416 gtk_clist_thaw(GTK_CLIST(packet_list));
417 if (auto_scroll_live && cf->plist_end != NULL)
418 gtk_clist_moveto(GTK_CLIST(packet_list),
419 cf->plist_end->row, -1, 1.0, 1.0);
424 finish_tail_cap_file(capture_file *cf)
428 gtk_clist_freeze(GTK_CLIST(packet_list));
430 wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
433 if (auto_scroll_live && cf->plist_end != NULL)
434 gtk_clist_moveto(GTK_CLIST(packet_list),
435 cf->plist_end->row, -1, 1.0, 1.0);
437 /* Set the file encapsulation type now; we don't know what it is until
438 we've looked at all the packets, as we don't know until then whether
439 there's more than one type (and thus whether it's
440 WTAP_ENCAP_PER_PACKET). */
441 cf->lnk_t = wtap_file_encap(cf->wth);
443 /* There's nothing more to read from the capture file - close it. */
447 /* Pop the "<live capture in progress>" message off the status bar. */
448 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
450 set_display_filename(cf);
452 /* Enable menu items that make sense if you're not currently running
454 set_menus_for_capture_in_progress(FALSE);
456 /* Enable menu items that make sense if you have a capture file
457 you've finished reading. */
458 set_menus_for_capture_file(TRUE);
459 set_menus_for_unsaved_capture_file(!cf->user_saved);
463 #endif /* HAVE_LIBPCAP */
466 color_filter_t *colorf;
467 proto_tree *protocol_tree;
469 } apply_color_filter_args;
472 * If no color filter has been applied, apply this one.
473 * (The "if no color filter has been applied" is to handle the case where
474 * more than one color filter matches the packet.)
477 apply_color_filter(gpointer filter_arg, gpointer argp)
479 color_filter_t *colorf = filter_arg;
480 apply_color_filter_args *args = argp;
482 if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
483 if (dfilter_apply(colorf->c_colorfilter, args->protocol_tree, args->pd))
484 args->colorf = colorf;
489 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
491 apply_color_filter_args args;
493 proto_tree *protocol_tree = NULL;
495 /* We don't yet have a color filter to apply. */
498 fdata->num = cf->count;
500 /* If we don't have the time stamp of the first packet in the
501 capture, it's because this is the first packet. Save the time
502 stamp of this packet as the time stamp of the first packet. */
503 if (!firstsec && !firstusec) {
504 firstsec = fdata->abs_secs;
505 firstusec = fdata->abs_usecs;
508 /* Get the time elapsed between the first packet and this packet. */
509 cf->esec = fdata->abs_secs - firstsec;
510 if (firstusec <= fdata->abs_usecs) {
511 cf->eusec = fdata->abs_usecs - firstusec;
513 cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
517 fdata->cinfo = &cf->cinfo;
518 for (i = 0; i < fdata->cinfo->num_cols; i++) {
519 fdata->cinfo->col_data[i][0] = '\0';
522 /* Apply the filters */
523 if (cf->dfcode != NULL || filter_list != NULL) {
524 protocol_tree = proto_tree_create_root();
525 dissect_packet(buf, fdata, protocol_tree);
526 if (cf->dfcode != NULL)
527 fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
529 fdata->passed_dfilter = TRUE;
531 /* Apply color filters, if we have any. */
532 if (filter_list != NULL) {
533 args.protocol_tree = protocol_tree;
535 g_slist_foreach(filter_list, apply_color_filter, &args);
537 proto_tree_free(protocol_tree);
542 protocol_tree = proto_tree_create_root();
544 dissect_packet(buf, fdata, protocol_tree);
545 fdata->passed_dfilter = TRUE;
548 proto_tree_free(protocol_tree);
551 if (fdata->passed_dfilter) {
552 /* If we don't have the time stamp of the previous displayed packet,
553 it's because this is the first displayed packet. Save the time
554 stamp of this packet as the time stamp of the previous displayed
556 if (!prevsec && !prevusec) {
557 prevsec = fdata->abs_secs;
558 prevusec = fdata->abs_usecs;
561 /* Get the time elapsed between the first packet and this packet. */
562 fdata->rel_secs = cf->esec;
563 fdata->rel_usecs = cf->eusec;
565 /* Get the time elapsed between the previous displayed packet and
567 fdata->del_secs = fdata->abs_secs - prevsec;
568 if (prevusec <= fdata->abs_usecs) {
569 fdata->del_usecs = fdata->abs_usecs - prevusec;
571 fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
574 prevsec = fdata->abs_secs;
575 prevusec = fdata->abs_usecs;
577 fill_in_columns(fdata);
579 row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
582 if (filter_list != NULL && (args.colorf != NULL)) {
583 gtk_clist_set_background(GTK_CLIST(packet_list), row,
584 &args.colorf->bg_color);
585 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
586 &args.colorf->fg_color);
588 gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
589 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
592 /* If we haven't yet seen the first frame, this is it. */
593 if (cf->first_displayed == NULL)
594 cf->first_displayed = fdata;
596 /* This is the last frame we've seen so far. */
597 cf->last_displayed = fdata;
599 /* If this was the current frame, remember the row it's in, so
600 we can arrange that it's on the screen when we're done. */
601 if (cf->current_frame == fdata)
602 cf->current_row = row;
604 fdata->row = -1; /* not in the display */
609 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
612 capture_file *cf = (capture_file *) user;
614 proto_tree *protocol_tree;
615 frame_data *plist_end;
619 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
620 when we update it, we have to run the GTK+ main loop to get it
621 to repaint what's pending, and doing so may involve an "ioctl()"
622 to see if there's any pending input from an X server, and doing
623 that for every packet can be costly, especially on a big file.
625 Do so only if we were told to do so; when reading a capture file
626 being updated by a live capture, we don't do so (as we're not
627 "done" until the capture stops, so we don't know how close to
630 if (cf->update_progbar && offset >= cf->progbar_nextstep) {
631 file_pos = lseek(cf->filed, 0, SEEK_CUR);
632 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
633 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), prog_val);
634 cf->progbar_nextstep += cf->progbar_quantum;
635 while (gtk_events_pending())
636 gtk_main_iteration();
639 /* Allocate the next list entry, and add it to the list. */
640 fdata = (frame_data *) g_malloc(sizeof(frame_data));
644 fdata->pkt_len = phdr->len;
645 fdata->cap_len = phdr->caplen;
646 fdata->file_off = offset;
647 fdata->lnk_t = phdr->pkt_encap;
648 fdata->abs_secs = phdr->ts.tv_sec;
649 fdata->abs_usecs = phdr->ts.tv_usec;
650 fdata->encoding = CHAR_ASCII;
651 fdata->pseudo_header = phdr->pseudo_header;
656 protocol_tree = proto_tree_create_root();
657 dissect_packet(buf, fdata, protocol_tree);
658 passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
659 proto_tree_free(protocol_tree);
662 plist_end = cf->plist_end;
663 fdata->prev = plist_end;
664 if (plist_end != NULL)
665 plist_end->next = fdata;
668 cf->plist_end = fdata;
671 add_packet_to_packet_list(fdata, cf, buf);
677 filter_packets(capture_file *cf, gchar *dftext)
681 if (dftext == NULL) {
682 /* The new filter is an empty filter (i.e., display all packets). */
686 * We have a filter; try to compile it.
688 if (dfilter_compile(dftext, &dfcode) != 0) {
689 /* The attempt failed; report an error. */
690 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
695 if (dfcode == NULL) {
696 /* Yes - free the filter text, and set it to null. */
702 /* We have a valid filter. Replace the current filter. */
703 if (cf->dfilter != NULL)
705 cf->dfilter = dftext;
706 if (cf->dfcode != NULL)
707 dfilter_destroy(cf->dfcode);
710 /* Now go through the list of packets we've read from the capture file,
711 applying the current display filter, and, if the packet passes the
712 display filter, add it to the summary display, appropriately
713 colored. (That's how we colorize the display - it's like filtering
714 the display, only we don't install a new filter.) */
715 colorize_packets(cf);
720 colorize_packets(capture_file *cf)
723 guint32 progbar_quantum;
724 guint32 progbar_nextstep;
726 /* We need to re-initialize all the state information that protocols
727 keep, because we're making a fresh pass through all the packets. */
729 /* Initialize the table of conversations. */
732 /* Initialize protocol-specific variables */
733 init_all_protocols();
735 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
737 /* Freeze the packet list while we redo it, so we don't get any
738 screen updates while it happens. */
739 gtk_clist_freeze(GTK_CLIST(packet_list));
742 gtk_clist_clear(GTK_CLIST(packet_list));
744 /* We don't yet know which will be the first and last frames displayed. */
745 cf->first_displayed = NULL;
746 cf->last_displayed = NULL;
748 /* If a packet was selected, we don't know yet what row, if any, it'll
750 cf->current_row = -1;
752 /* Iterate through the list of packets, calling a routine
753 to run the filter on the packet, see if it matches, and
754 put it in the display list if so. */
759 cf->unfiltered_count = cf->count;
762 proto_tree_is_visible = FALSE;
764 /* Update the progress bar when it gets to this value. */
765 progbar_nextstep = 0;
766 /* When we reach the value that triggers a progress bar update,
767 bump that value by this amount. */
768 progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
769 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
771 for (fd = cf->plist; fd != NULL; fd = fd->next) {
772 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
773 when we update it, we have to run the GTK+ main loop to get it
774 to repaint what's pending, and doing so may involve an "ioctl()"
775 to see if there's any pending input from an X server, and doing
776 that for every packet can be costly, especially on a big file. */
777 if (cf->count >= progbar_nextstep) {
778 /* let's not divide by zero. I should never be started
779 * with unfiltered_count == 0, so let's assert that
781 g_assert(cf->unfiltered_count > 0);
783 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
784 (gfloat) cf->count / cf->unfiltered_count);
786 progbar_nextstep += progbar_quantum;
787 while (gtk_events_pending())
788 gtk_main_iteration();
793 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
795 add_packet_to_packet_list(fd, cf, cf->pd);
798 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
800 if (cf->current_row != -1) {
801 /* The current frame passed the filter; make sure it's visible. */
802 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), cf->current_row))
803 gtk_clist_moveto(GTK_CLIST(packet_list), cf->current_row, -1, 0.0, 0.0);
804 if (cf->current_frame_is_selected) {
805 /* It was selected, so re-select it. */
806 gtk_clist_select_row(GTK_CLIST(packet_list), cf->current_row, -1);
808 finfo_selected = NULL;
810 /* The current frame didn't pass the filter; make the first frame
811 the current frame, and leave it unselected. */
813 cf->current_frame = cf->first_displayed;
816 /* Unfreeze the packet list. */
817 gtk_clist_thaw(GTK_CLIST(packet_list));
821 print_packets(capture_file *cf, print_args_t *print_args)
825 guint32 progbar_quantum;
826 guint32 progbar_nextstep;
828 proto_tree *protocol_tree;
829 gint *col_widths = NULL;
831 gboolean print_separator;
833 cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
834 if (cf->print_fh == NULL)
835 return FALSE; /* attempt to open destination failed */
837 /* XXX - printing multiple frames in PostScript looks as if it's
838 tricky - you have to deal with page boundaries, I think -
839 and I'll have to spend some time learning enough about
840 PostScript to figure it out, so, for now, we only print
841 multiple frames as text. */
843 print_preamble(cf->print_fh);
846 if (print_args->print_summary) {
847 /* We're printing packet summaries.
849 Find the widths for each of the columns - maximum of the
850 width of the title and the width of the data - and print
851 the column titles. */
852 col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
853 for (i = 0; i < cf->cinfo.num_cols; i++) {
854 /* Don't pad the last column. */
855 if (i == cf->cinfo.num_cols - 1)
858 col_widths[i] = strlen(cf->cinfo.col_title[i]);
859 data_width = get_column_char_width(get_column_format(i));
860 if (data_width > col_widths[i])
861 col_widths[i] = data_width;
864 /* Right-justify the packet number column. */
865 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
866 fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_title[i]);
868 fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
869 if (i == cf->cinfo.num_cols - 1)
870 fputc('\n', cf->print_fh);
872 fputc(' ', cf->print_fh);
876 print_separator = FALSE;
877 proto_tree_is_visible = TRUE;
879 /* Update the progress bar when it gets to this value. */
880 progbar_nextstep = 0;
881 /* When we reach the value that triggers a progress bar update,
882 bump that value by this amount. */
883 progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
884 /* Count of packets we've looked at. */
887 /* Iterate through the list of packets, printing the packets that
888 were selected by the current display filter. */
889 for (fd = cf->plist; fd != NULL; fd = fd->next) {
890 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
891 when we update it, we have to run the GTK+ main loop to get it
892 to repaint what's pending, and doing so may involve an "ioctl()"
893 to see if there's any pending input from an X server, and doing
894 that for every packet can be costly, especially on a big file. */
895 if (count >= progbar_nextstep) {
896 /* let's not divide by zero. I should never be started
897 * with unfiltered_count == 0, so let's assert that
899 g_assert(cf->unfiltered_count > 0);
901 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
902 (gfloat) count / cf->unfiltered_count);
903 progbar_nextstep += progbar_quantum;
904 while (gtk_events_pending())
905 gtk_main_iteration();
909 if (fd->passed_dfilter) {
910 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
911 if (print_args->print_summary) {
912 /* Fill in the column information, but don't bother creating
913 the logical protocol tree. */
914 fd->cinfo = &cf->cinfo;
915 for (i = 0; i < fd->cinfo->num_cols; i++) {
916 fd->cinfo->col_data[i][0] = '\0';
918 dissect_packet(cf->pd, fd, NULL);
920 for (i = 0; i < cf->cinfo.num_cols; i++) {
921 /* Right-justify the packet number column. */
922 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
923 fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_data[i]);
925 fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
926 if (i == cf->cinfo.num_cols - 1)
927 fputc('\n', cf->print_fh);
929 fputc(' ', cf->print_fh);
933 fputc('\n', cf->print_fh);
935 /* Create the logical protocol tree. */
936 protocol_tree = proto_tree_create_root();
937 dissect_packet(cf->pd, fd, protocol_tree);
939 /* Print the information in that tree. */
940 proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
941 cf->pd, fd, cf->print_fh);
943 proto_tree_free(protocol_tree);
945 if (print_args->print_hex) {
946 /* Print the full packet data as hex. */
947 print_hex_data(cf->print_fh, cf->pd, fd->cap_len, fd->encoding);
950 /* Print a blank line if we print anything after this. */
951 print_separator = TRUE;
956 if (col_widths != NULL)
960 print_finale(cf->print_fh);
963 close_print_dest(print_args->to_file, cf->print_fh);
965 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
971 /* Scan through the packet list and change all columns that use the
972 "command-line-specified" time stamp format to use the current
973 value of that format. */
975 change_time_formats(capture_file *cf)
981 /* Freeze the packet list while we redo it, so we don't get any
982 screen updates while it happens. */
985 /* Iterate through the list of packets, checking whether the packet
986 is in a row of the summary list and, if so, whether there are
987 any columns that show the time in the "command-line-specified"
988 format and, if so, update that row. */
989 for (fd = cf->plist; fd != NULL; fd = fd->next) {
991 /* This packet is in the summary list, on row "fd->row". */
993 /* XXX - there really should be a way of checking "cf->cinfo" for this;
994 the answer isn't going to change from packet to packet, so we should
995 simply skip all the "change_time_formats()" work if we're not
996 changing anything. */
997 fd->cinfo = &cf->cinfo;
998 if (check_col(fd, COL_CLS_TIME)) {
999 /* There are columns that show the time in the "command-line-specified"
1000 format; update them. */
1001 for (i = 0; i < cf->cinfo.num_cols; i++) {
1002 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
1003 /* This is one of the columns that shows the time in
1004 "command-line-specified" format; update it. */
1005 cf->cinfo.col_data[i][0] = '\0';
1006 col_set_cls_time(fd, i);
1007 gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
1008 cf->cinfo.col_data[i]);
1015 /* Set the column widths of those columns that show the time in
1016 "command-line-specified" format. */
1017 pl_style = gtk_widget_get_style(packet_list);
1018 for (i = 0; i < cf->cinfo.num_cols; i++) {
1019 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
1020 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1021 get_column_width(COL_CLS_TIME, pl_style->font));
1025 /* Unfreeze the packet list. */
1030 clear_tree_and_hex_views(void)
1032 /* Clear the hex dump. */
1033 gtk_text_freeze(GTK_TEXT(byte_view));
1034 gtk_text_set_point(GTK_TEXT(byte_view), 0);
1035 gtk_text_forward_delete(GTK_TEXT(byte_view),
1036 gtk_text_get_length(GTK_TEXT(byte_view)));
1037 gtk_text_thaw(GTK_TEXT(byte_view));
1039 /* Remove all nodes in ctree. This is how it's done in testgtk.c in GTK+ */
1040 gtk_clist_clear ( GTK_CLIST(tree_view) );
1045 find_packet(capture_file *cf, dfilter *sfcode)
1047 frame_data *start_fd;
1049 frame_data *new_fd = NULL;
1050 guint32 progbar_quantum;
1051 guint32 progbar_nextstep;
1053 proto_tree *protocol_tree;
1055 start_fd = cf->current_frame;
1056 if (start_fd != NULL) {
1057 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
1059 /* Iterate through the list of packets, starting at the packet we've
1060 picked, calling a routine to run the filter on the packet, see if
1061 it matches, and stop if so. */
1065 proto_tree_is_visible = FALSE;
1067 /* Update the progress bar when it gets to this value. */
1068 progbar_nextstep = 0;
1069 /* When we reach the value that triggers a progress bar update,
1070 bump that value by this amount.
1072 We base the progress bar on the extent to which we've gone through
1073 the displayed packets, as those are the only ones for which we
1074 have to do a significant amount of work. */
1075 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1076 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
1080 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1081 when we update it, we have to run the GTK+ main loop to get it
1082 to repaint what's pending, and doing so may involve an "ioctl()"
1083 to see if there's any pending input from an X server, and doing
1084 that for every packet can be costly, especially on a big file. */
1085 if (count >= progbar_nextstep) {
1086 /* let's not divide by zero. I should never be started
1087 * with count == 0, so let's assert that
1089 g_assert(cf->count > 0);
1091 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
1092 (gfloat) count / cf->count);
1094 progbar_nextstep += progbar_quantum;
1095 while (gtk_events_pending())
1096 gtk_main_iteration();
1099 /* Go past the current frame. */
1100 if (cf->sbackward) {
1101 /* Go on to the previous frame. */
1104 fd = cf->plist_end; /* wrap around */
1106 /* Go on to the next frame. */
1109 fd = cf->plist; /* wrap around */
1112 if (fd == start_fd) {
1113 /* We're back to the frame we were on originally. The search
1118 /* Is this packet in the display? */
1119 if (fd->passed_dfilter) {
1122 /* Yes. Does it match the search filter? */
1123 protocol_tree = proto_tree_create_root();
1124 wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1125 dissect_packet(cf->pd, fd, protocol_tree);
1126 if (dfilter_apply(sfcode, protocol_tree, cf->pd)) {
1128 break; /* found it! */
1133 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
1136 if (new_fd != NULL) {
1137 /* We found a frame. Make it visible, and select it. */
1138 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), new_fd->row))
1139 gtk_clist_moveto(GTK_CLIST(packet_list), new_fd->row, -1, 0.0, 0.0);
1140 gtk_clist_select_row(GTK_CLIST(packet_list), new_fd->row, -1);
1141 return TRUE; /* success */
1143 return FALSE; /* failure */
1147 goto_frame(capture_file *cf, guint fnumber)
1151 for (fd = cf->plist; fd != NULL && fd->num < fnumber; fd = fd->next)
1155 return NO_SUCH_FRAME; /* we didn't find that frame */
1156 if (!fd->passed_dfilter)
1157 return FRAME_NOT_DISPLAYED; /* the frame with that number isn't displayed */
1159 /* We found that frame, and it's currently being displayed.
1160 Make it visible, and select it. */
1161 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), fd->row))
1162 gtk_clist_moveto(GTK_CLIST(packet_list), fd->row, -1, 0.0, 0.0);
1163 gtk_clist_select_row(GTK_CLIST(packet_list), fd->row, -1);
1167 /* Select the packet on a given row. */
1169 select_packet(capture_file *cf, int row)
1174 /* Search through the list of frames to see which one is in
1177 XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
1178 the first entry is added to it by "real_insert_row()", that row
1179 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
1180 our version and the vanilla GTK+ version).
1182 This means that a "select-row" signal is emitted; this causes
1183 "packet_list_select_cb()" to be called, which causes "select_packet()"
1186 As "gtk_clist_append()", which called "real_insert_row()", hasn't
1187 yet returned, we don't know what the row number is, so we can't
1188 set "fd->row" for that frame yet.
1190 This means that we won't find this row in the list of frames.
1192 For now, we handle that by, if "fd" is NULL when the loop terminates
1193 (meaning we didn't find the frame), verifying that "i" is 1 (meaning
1194 there's only one frame in the list, which we take as a sign that the
1195 first and only frame *must* have been the one selected) and forcibly
1196 setting "fd" to "cf->plist" (so that it points to the first and only
1198 for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
1207 /* Record that this frame is the current frame, and that it's selected. */
1208 cf->current_frame = fd;
1209 cf->current_frame_is_selected = TRUE;
1211 /* Get the data in that frame. */
1212 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1214 /* Create the logical protocol tree. */
1215 if (cf->protocol_tree)
1216 proto_tree_free(cf->protocol_tree);
1217 cf->protocol_tree = proto_tree_create_root();
1218 proto_tree_is_visible = TRUE;
1219 dissect_packet(cf->pd, cf->current_frame, cf->protocol_tree);
1221 /* Display the GUI protocol tree and hex dump. */
1222 clear_tree_and_hex_views();
1223 proto_tree_draw(cf->protocol_tree, tree_view);
1224 packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->current_frame->cap_len,
1225 -1, -1, cf->current_frame->encoding);
1227 /* A packet is selected. */
1228 set_menus_for_selected_packet(TRUE);
1231 /* Unselect the selected packet, if any. */
1233 unselect_packet(capture_file *cf)
1235 cf->current_frame_is_selected = FALSE;
1237 /* Destroy the protocol tree for that packet. */
1238 if (cf->protocol_tree != NULL) {
1239 proto_tree_free(cf->protocol_tree);
1240 cf->protocol_tree = NULL;
1243 finfo_selected = NULL;
1245 /* Clear out the display of that packet. */
1246 clear_tree_and_hex_views();
1248 /* No packet is selected. */
1249 set_menus_for_selected_packet(FALSE);
1253 freeze_clist(capture_file *cf)
1257 /* Make the column sizes static, so they don't adjust while
1258 we're reading the capture file (freezing the clist doesn't
1259 seem to suffice). */
1260 for (i = 0; i < cf->cinfo.num_cols; i++)
1261 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
1262 gtk_clist_freeze(GTK_CLIST(packet_list));
1266 thaw_clist(capture_file *cf)
1270 for (i = 0; i < cf->cinfo.num_cols; i++) {
1271 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
1272 /* Set this column's width to the appropriate value. */
1273 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1274 cf->cinfo.col_width[i]);
1276 /* Make this column's size dynamic, so that it adjusts to the
1277 appropriate size. */
1278 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1281 gtk_clist_thaw(GTK_CLIST(packet_list));
1283 /* Hopefully, the columns have now gotten their appropriate sizes;
1284 make them resizeable - a column that auto-resizes cannot be
1285 resized by the user, and *vice versa*. */
1286 for (i = 0; i < cf->cinfo.num_cols; i++)
1287 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
1291 save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
1294 gchar *from_filename;
1295 gchar *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
1299 int from_fd, to_fd, nread, nwritten;
1302 struct wtap_pkthdr hdr;
1305 if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
1309 msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
1310 save_msg = g_malloc(msg_len);
1311 snprintf(save_msg, msg_len, save_fmt, name_ptr);
1312 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
1315 if (!save_filtered && save_format == cf->cd_t) {
1316 /* We're not filtering packets, and we're saving it in the format
1317 it's already in, so we can just move or copy the raw data. */
1319 /* In this branch, we set "err" only if we get an error, so we
1320 must first clear it. */
1322 if (cf->is_tempfile) {
1323 /* The file being saved is a temporary file from a live
1324 capture, so it doesn't need to stay around under that name;
1325 first, try renaming the capture buffer file to the new name. */
1326 if (rename(cf->filename, fname) == 0) {
1327 /* That succeeded - there's no need to copy the source file. */
1328 from_filename = NULL;
1331 if (errno == EXDEV) {
1332 /* They're on different file systems, so we have to copy the
1335 from_filename = cf->filename;
1337 /* The rename failed, but not because they're on different
1338 file systems - put up an error message. (Or should we
1339 just punt and try to copy? The only reason why I'd
1340 expect the rename to fail and the copy to succeed would
1341 be if we didn't have permission to remove the file from
1342 the temporary directory, and that might be fixable - but
1343 is it worth requiring the user to go off and fix it?) */
1345 simple_dialog(ESD_TYPE_WARN, NULL,
1346 file_rename_error_message(err), fname);
1351 /* It's a permanent file, so we should copy it, and not remove the
1354 from_filename = cf->filename;
1357 /* Copy the file, if we haven't moved it. */
1359 /* Copy the raw bytes of the file. */
1360 from_fd = open(from_filename, O_RDONLY);
1363 simple_dialog(ESD_TYPE_WARN, NULL,
1364 file_open_error_message(err, TRUE), from_filename);
1368 to_fd = creat(fname, 0644);
1371 simple_dialog(ESD_TYPE_WARN, NULL,
1372 file_open_error_message(err, TRUE), fname);
1377 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
1378 nwritten = write(to_fd, pd, nread);
1379 if (nwritten < nread) {
1383 err = WTAP_ERR_SHORT_WRITE;
1384 simple_dialog(ESD_TYPE_WARN, NULL,
1385 file_write_error_message(err), fname);
1393 simple_dialog(ESD_TYPE_WARN, NULL,
1394 file_read_error_message(err), from_filename);
1400 if (close(to_fd) < 0) {
1402 simple_dialog(ESD_TYPE_WARN, NULL,
1403 file_close_error_message(err), fname);
1408 /* Either we're filtering packets, or we're saving in a different
1409 format; we can't do that by copying or moving the capture file,
1410 we have to do it by writing the packets out in Wiretap. */
1411 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
1413 simple_dialog(ESD_TYPE_WARN, NULL,
1414 file_open_error_message(err, TRUE), fname);
1418 /* XXX - have a way to save only the packets currently selected by
1421 If we do that, should we make that file the current file? If so,
1422 it means we can no longer get at the other packets. What does
1424 for (fd = cf->plist; fd != NULL; fd = fd->next) {
1425 /* XXX - do a progress bar */
1426 if (!save_filtered || fd->passed_dfilter) {
1427 /* Either we're saving all frames, or we're saving filtered frames
1428 and this one passed the display filter - save it. */
1429 hdr.ts.tv_sec = fd->abs_secs;
1430 hdr.ts.tv_usec = fd->abs_usecs;
1431 hdr.caplen = fd->cap_len;
1432 hdr.len = fd->pkt_len;
1433 hdr.pkt_encap = fd->lnk_t;
1434 hdr.pseudo_header = fd->pseudo_header;
1435 wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, pd, fd->cap_len);
1437 if (!wtap_dump(pdh, &hdr, pd, &err)) {
1438 simple_dialog(ESD_TYPE_WARN, NULL,
1439 file_write_error_message(err), fname);
1440 wtap_dump_close(pdh, &err);
1446 if (!wtap_dump_close(pdh, &err)) {
1447 simple_dialog(ESD_TYPE_WARN, NULL,
1448 file_close_error_message(err), fname);
1455 /* Pop the "Saving:" message off the status bar. */
1456 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1458 if (!save_filtered) {
1459 /* We saved the entire capture, not just some packets from it.
1460 Open and read the file we saved it to.
1462 XXX - this is somewhat of a waste; we already have the
1463 packets, all this gets us is updated file type information
1464 (which we could just stuff into "cf"), and having the new
1465 file be the one we have opened and from which we're reading
1466 the data, and it means we have to spend time opening and
1467 reading the file, which could be a significant amount of
1468 time if the file is large. */
1469 cf->user_saved = TRUE;
1471 if ((err = open_cap_file(fname, FALSE, cf)) == 0) {
1472 /* XXX - report errors if this fails? */
1473 err = read_cap_file(cf);
1474 set_menus_for_unsaved_capture_file(FALSE);
1482 file_open_error_message(int err, int for_writing)
1485 static char errmsg_errno[1024+1];
1489 case WTAP_ERR_NOT_REGULAR_FILE:
1490 errmsg = "The file \"%s\" is invalid.";
1493 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
1494 case WTAP_ERR_UNSUPPORTED:
1495 /* Seen only when opening a capture file for reading. */
1496 errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
1499 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
1500 /* Seen only when opening a capture file for writing. */
1501 errmsg = "Ethereal does not support writing capture files in that format.";
1504 case WTAP_ERR_UNSUPPORTED_ENCAP:
1505 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
1506 /* Seen only when opening a capture file for writing. */
1507 errmsg = "Ethereal cannot save this capture in that format.";
1510 case WTAP_ERR_BAD_RECORD:
1511 errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1514 case WTAP_ERR_CANT_OPEN:
1516 errmsg = "The file \"%s\" could not be created for some unknown reason.";
1518 errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1521 case WTAP_ERR_SHORT_READ:
1522 errmsg = "The file \"%s\" appears to have been cut short"
1523 " in the middle of a packet.";
1526 case WTAP_ERR_SHORT_WRITE:
1527 errmsg = "A full header couldn't be written to the file \"%s\".";
1532 errmsg = "The path to the file \"%s\" does not exist.";
1534 errmsg = "The file \"%s\" does not exist.";
1539 errmsg = "You do not have permission to create or write to the file \"%s\".";
1541 errmsg = "You do not have permission to read the file \"%s\".";
1545 sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1546 wtap_strerror(err));
1547 errmsg = errmsg_errno;
1554 file_rename_error_message(int err)
1557 static char errmsg_errno[1024+1];
1562 errmsg = "The path to the file \"%s\" does not exist.";
1566 errmsg = "You do not have permission to move the capture file to \"%s\".";
1570 sprintf(errmsg_errno, "The file \"%%s\" could not be moved: %s.",
1571 wtap_strerror(err));
1572 errmsg = errmsg_errno;
1579 file_read_error_message(int err)
1581 static char errmsg_errno[1024+1];
1583 sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
1584 wtap_strerror(err));
1585 return errmsg_errno;
1589 file_write_error_message(int err)
1592 static char errmsg_errno[1024+1];
1597 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1602 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1607 sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
1608 wtap_strerror(err));
1609 errmsg = errmsg_errno;
1615 /* Check for write errors - if the file is being written to an NFS server,
1616 a write error may not show up until the file is closed, as NFS clients
1617 might not send writes to the server until the "write()" call finishes,
1618 so that the write may fail on the server but the "write()" may succeed. */
1620 file_close_error_message(int err)
1623 static char errmsg_errno[1024+1];
1627 case WTAP_ERR_CANT_CLOSE:
1628 errmsg = "The file \"%s\" couldn't be closed for some unknown reason.";
1631 case WTAP_ERR_SHORT_WRITE:
1632 errmsg = "Not all the data could be written to the file \"%s\".";
1636 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1641 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1646 sprintf(errmsg_errno, "An error occurred while closing the file \"%%s\": %s.",
1647 wtap_strerror(err));
1648 errmsg = errmsg_errno;