4 * $Id: file.c,v 1.154 2000/01/18 08:37:55 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"
88 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
89 extern guint file_ctx;
91 gboolean auto_scroll_live = FALSE;
93 static guint32 firstsec, firstusec;
94 static guint32 prevsec, prevusec;
96 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
99 static void freeze_clist(capture_file *cf);
100 static void thaw_clist(capture_file *cf);
102 static char *file_rename_error_message(int err);
103 static char *file_close_error_message(int err);
105 /* Update the progress bar this many times when reading a file. */
106 #define N_PROGBAR_UPDATES 100
109 open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
117 wth = wtap_open_offline(fname, &err);
121 /* Find the size of the file. */
124 if (fstat(fd, &cf_stat) < 0) {
130 /* The open succeeded. Close whatever capture file we had open,
131 and fill in the information for this file. */
132 close_cap_file(cf, info_bar);
134 /* Initialize the table of conversations. */
137 /* Initialize protocol-specific variables */
138 init_all_protocols();
143 cf->f_len = cf_stat.st_size;
145 /* Set the file name because we need it to set the follow stream filter.
146 XXX - is that still true? We need it for other reasons, though,
148 cf->filename = g_strdup(fname);
150 /* Indicate whether it's a permanent or temporary file. */
151 cf->is_tempfile = is_tempfile;
153 /* If it's a temporary capture buffer file, mark it as not saved. */
154 cf->user_saved = !is_tempfile;
156 cf->cd_t = wtap_file_type(cf->wth);
161 cf->snap = wtap_snapshot_length(cf->wth);
162 cf->update_progbar = FALSE;
163 cf->progbar_quantum = 0;
164 cf->progbar_nextstep = 0;
165 firstsec = 0, firstusec = 0;
166 prevsec = 0, prevusec = 0;
171 simple_dialog(ESD_TYPE_WARN, NULL,
172 file_open_error_message(err, FALSE), fname);
176 /* Reset everything to a pristine state */
178 close_cap_file(capture_file *cf, void *w)
180 frame_data *fd, *fd_next;
190 /* We have no file open... */
191 if (cf->filename != NULL) {
192 /* If it's a temporary file, remove it. */
194 unlink(cf->filename);
195 g_free(cf->filename);
198 /* ...which means we have nothing to save. */
199 cf->user_saved = FALSE;
201 for (fd = cf->plist; fd != NULL; fd = fd_next) {
205 if (cf->rfcode != NULL) {
206 dfilter_destroy(cf->rfcode);
210 cf->plist_end = NULL;
211 unselect_packet(cf); /* nothing to select */
213 /* Clear the packet list. */
214 gtk_clist_freeze(GTK_CLIST(packet_list));
215 gtk_clist_clear(GTK_CLIST(packet_list));
216 gtk_clist_thaw(GTK_CLIST(packet_list));
218 /* Clear any file-related status bar messages.
219 XXX - should be "clear *ALL* file-related status bar messages;
220 will there ever be more than one on the stack? */
221 gtk_statusbar_pop(GTK_STATUSBAR(w), file_ctx);
223 /* Restore the standard title bar message. */
224 set_main_window_name("The Ethereal Network Analyzer");
226 /* Disable all menu items that make sense only if you have a capture. */
227 set_menus_for_capture_file(FALSE);
228 set_menus_for_unsaved_capture_file(FALSE);
229 set_menus_for_captured_packets(FALSE);
230 set_menus_for_selected_packet(FALSE);
233 /* Set the file name in the status line, in the name for the main window,
234 and in the name for the main window's icon. */
236 set_display_filename(capture_file *cf)
240 gchar *done_fmt = " File: %s Drops: %u";
242 gchar *win_name_fmt = "%s - Ethereal";
245 if (!cf->is_tempfile) {
246 /* Get the last component of the file name, and put that in the
248 if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
249 name_ptr = cf->filename;
253 /* The file we read is a temporary file from a live capture;
254 we don't mention its name in the status bar. */
255 name_ptr = "<capture>";
258 msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
259 done_msg = g_malloc(msg_len);
260 snprintf(done_msg, msg_len, done_fmt, name_ptr, cf->drops);
261 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
264 msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
265 win_name = g_malloc(msg_len);
266 snprintf(win_name, msg_len, win_name_fmt, name_ptr);
267 set_main_window_name(win_name);
272 read_cap_file(capture_file *cf)
274 gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
279 char errmsg_errno[1024+1];
280 gchar err_str[2048+1];
282 if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
283 name_ptr = cf->filename;
287 msg_len = strlen(name_ptr) + strlen(load_fmt) + 2;
288 load_msg = g_malloc(msg_len);
289 snprintf(load_msg, msg_len, load_fmt, name_ptr);
290 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
293 cf->update_progbar = TRUE;
294 /* Update the progress bar when it gets to this value. */
295 cf->progbar_nextstep = 0;
296 /* When we reach the value that triggers a progress bar update,
297 bump that value by this amount. */
298 cf->progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
301 proto_tree_is_visible = FALSE;
302 success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
303 /* Set the file encapsulation type now; we don't know what it is until
304 we've looked at all the packets, as we don't know until then whether
305 there's more than one type (and thus whether it's
306 WTAP_ENCAP_PER_PACKET). */
307 cf->lnk_t = wtap_file_encap(cf->wth);
310 cf->filed = open(cf->filename, O_RDONLY);
311 cf->fh = filed_open(cf->filed, "r");
312 cf->current_frame = cf->first_displayed;
315 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
316 gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
318 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
319 set_display_filename(cf);
321 /* Enable menu items that make sense if you have a capture file you've
323 set_menus_for_capture_file(TRUE);
324 set_menus_for_unsaved_capture_file(!cf->user_saved);
326 /* Enable menu items that make sense if you have some captured packets. */
327 set_menus_for_captured_packets(TRUE);
329 /* Make the first row the selected row. */
330 gtk_signal_emit_by_name(GTK_OBJECT(packet_list), "select_row", 0);
333 /* Put up a message box noting that the read failed somewhere along
334 the line. Don't throw out the stuff we managed to read, though,
338 case WTAP_ERR_CANT_READ:
339 errmsg = "An attempt to read from the file failed for"
340 " some unknown reason.";
343 case WTAP_ERR_SHORT_READ:
344 errmsg = "The capture file appears to have been cut short"
345 " in the middle of a packet.";
348 case WTAP_ERR_BAD_RECORD:
349 errmsg = "The capture file appears to be damaged or corrupt.";
353 sprintf(errmsg_errno, "An error occurred while reading the"
354 " capture file: %s.", wtap_strerror(err));
355 errmsg = errmsg_errno;
358 snprintf(err_str, sizeof err_str, errmsg);
359 simple_dialog(ESD_TYPE_WARN, NULL, err_str);
367 start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
372 err = open_cap_file(fname, is_tempfile, cf);
374 /* Disable menu items that make no sense if you're currently running
376 set_menus_for_capture_in_progress(TRUE);
378 /* Enable menu items that make sense if you have some captured
379 packets (yes, I know, we don't have any *yet*). */
380 set_menus_for_captured_packets(TRUE);
382 for (i = 0; i < cf->cinfo.num_cols; i++) {
383 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
384 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
386 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
387 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
388 cf->cinfo.col_width[i]);
389 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
393 /* Yes, "open_cap_file()" set this - but it set it to a file handle
394 from Wiretap, which will be closed when we close the file; we
395 want it to remain open even after that, so that we can read
396 packet data from it. */
397 cf->fh = file_open(fname, "r");
399 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx,
400 " <live capture in progress>");
406 continue_tail_cap_file(capture_file *cf, int to_read)
410 gtk_clist_freeze(GTK_CLIST(packet_list));
412 wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
414 gtk_clist_thaw(GTK_CLIST(packet_list));
415 if (auto_scroll_live && cf->plist_end != NULL)
416 gtk_clist_moveto(GTK_CLIST(packet_list),
417 cf->plist_end->row, -1, 1.0, 1.0);
422 finish_tail_cap_file(capture_file *cf)
426 gtk_clist_freeze(GTK_CLIST(packet_list));
428 wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
431 if (auto_scroll_live && cf->plist_end != NULL)
432 gtk_clist_moveto(GTK_CLIST(packet_list),
433 cf->plist_end->row, -1, 1.0, 1.0);
435 /* Set the file encapsulation type now; we don't know what it is until
436 we've looked at all the packets, as we don't know until then whether
437 there's more than one type (and thus whether it's
438 WTAP_ENCAP_PER_PACKET). */
439 cf->lnk_t = wtap_file_encap(cf->wth);
441 /* There's nothing more to read from the capture file - close it. */
445 /* Pop the "<live capture in progress>" message off the status bar. */
446 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
448 set_display_filename(cf);
450 /* Enable menu items that make sense if you're not currently running
452 set_menus_for_capture_in_progress(FALSE);
454 /* Enable menu items that make sense if you have a capture file
455 you've finished reading. */
456 set_menus_for_capture_file(TRUE);
457 set_menus_for_unsaved_capture_file(!cf->user_saved);
461 #endif /* HAVE_LIBPCAP */
464 color_filter_t *colorf;
465 proto_tree *protocol_tree;
467 } apply_color_filter_args;
470 * If no color filter has been applied, apply this one.
471 * (The "if no color filter has been applied" is to handle the case where
472 * more than one color filter matches the packet.)
475 apply_color_filter(gpointer filter_arg, gpointer argp)
477 color_filter_t *colorf = filter_arg;
478 apply_color_filter_args *args = argp;
480 if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
481 if (dfilter_apply(colorf->c_colorfilter, args->protocol_tree, args->pd))
482 args->colorf = colorf;
487 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
489 apply_color_filter_args args;
491 proto_tree *protocol_tree = NULL;
493 /* We don't yet have a color filter to apply. */
496 /* If we don't have the time stamp of the first packet in the
497 capture, it's because this is the first packet. Save the time
498 stamp of this packet as the time stamp of the first packet. */
499 if (!firstsec && !firstusec) {
500 firstsec = fdata->abs_secs;
501 firstusec = fdata->abs_usecs;
504 /* Get the time elapsed between the first packet and this packet. */
505 cf->esec = fdata->abs_secs - firstsec;
506 if (firstusec <= fdata->abs_usecs) {
507 cf->eusec = fdata->abs_usecs - firstusec;
509 cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
513 fdata->cinfo = &cf->cinfo;
514 for (i = 0; i < fdata->cinfo->num_cols; i++) {
515 fdata->cinfo->col_data[i][0] = '\0';
518 /* Apply the filters */
519 if (cf->dfcode != NULL || filter_list != NULL) {
520 protocol_tree = proto_tree_create_root();
521 dissect_packet(buf, fdata, protocol_tree);
522 if (cf->dfcode != NULL)
523 fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
525 fdata->passed_dfilter = TRUE;
527 /* Apply color filters, if we have any. */
528 if (filter_list != NULL) {
529 args.protocol_tree = protocol_tree;
531 g_slist_foreach(filter_list, apply_color_filter, &args);
533 proto_tree_free(protocol_tree);
538 protocol_tree = proto_tree_create_root();
540 dissect_packet(buf, fdata, protocol_tree);
541 fdata->passed_dfilter = TRUE;
544 proto_tree_free(protocol_tree);
548 if (fdata->passed_dfilter) {
549 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
550 the first entry is added to it by "real_insert_row()", that row
551 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
552 our version and the vanilla GTK+ version).
554 This means that a "select-row" signal is emitted; this causes
555 "packet_list_select_cb()" to be called, which causes "select_packet()"
558 "select_packet()" searches the list of frames for a frame with the
559 row number passed into it; however, as "gtk_clist_append()", which
560 called "real_insert_row()", hasn't yet returned, we don't know what
561 the row number is, so we can't correctly set "fd->row" for that frame
564 This means that we won't find the frame for that row.
566 We can't assume that there's only one frame in the frame list,
567 either, as we may be filtering the display.
569 Therefore, we set "fdata->row" to 0, under the assumption that
570 the row number passed to "select_packet()" will be 0 (as we're
571 adding the first row to the list; it gets set to the proper
575 /* If we don't have the time stamp of the previous displayed packet,
576 it's because this is the first displayed packet. Save the time
577 stamp of this packet as the time stamp of the previous displayed
579 if (!prevsec && !prevusec) {
580 prevsec = fdata->abs_secs;
581 prevusec = fdata->abs_usecs;
584 /* Get the time elapsed between the first packet and this packet. */
585 fdata->rel_secs = cf->esec;
586 fdata->rel_usecs = cf->eusec;
588 /* Get the time elapsed between the previous displayed packet and
590 fdata->del_secs = fdata->abs_secs - prevsec;
591 if (prevusec <= fdata->abs_usecs) {
592 fdata->del_usecs = fdata->abs_usecs - prevusec;
594 fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
597 prevsec = fdata->abs_secs;
598 prevusec = fdata->abs_usecs;
600 fill_in_columns(fdata);
602 row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
605 if (filter_list != NULL && (args.colorf != NULL)) {
606 gtk_clist_set_background(GTK_CLIST(packet_list), row,
607 &args.colorf->bg_color);
608 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
609 &args.colorf->fg_color);
611 gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
612 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
615 /* If we haven't yet seen the first frame, this is it. */
616 if (cf->first_displayed == NULL)
617 cf->first_displayed = fdata;
619 /* This is the last frame we've seen so far. */
620 cf->last_displayed = fdata;
622 /* If this was the current frame, remember the row it's in, so
623 we can arrange that it's on the screen when we're done. */
624 if (cf->current_frame == fdata)
625 cf->current_row = row;
627 fdata->row = -1; /* not in the display */
632 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
635 capture_file *cf = (capture_file *) user;
637 proto_tree *protocol_tree;
638 frame_data *plist_end;
642 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
643 when we update it, we have to run the GTK+ main loop to get it
644 to repaint what's pending, and doing so may involve an "ioctl()"
645 to see if there's any pending input from an X server, and doing
646 that for every packet can be costly, especially on a big file.
648 Do so only if we were told to do so; when reading a capture file
649 being updated by a live capture, we don't do so (as we're not
650 "done" until the capture stops, so we don't know how close to
653 if (cf->update_progbar && offset >= cf->progbar_nextstep) {
654 file_pos = lseek(cf->filed, 0, SEEK_CUR);
655 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
656 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), prog_val);
657 cf->progbar_nextstep += cf->progbar_quantum;
658 while (gtk_events_pending())
659 gtk_main_iteration();
662 /* Allocate the next list entry, and add it to the list. */
663 fdata = (frame_data *) g_malloc(sizeof(frame_data));
667 fdata->pkt_len = phdr->len;
668 fdata->cap_len = phdr->caplen;
669 fdata->file_off = offset;
670 fdata->lnk_t = phdr->pkt_encap;
671 fdata->abs_secs = phdr->ts.tv_sec;
672 fdata->abs_usecs = phdr->ts.tv_usec;
673 fdata->encoding = CHAR_ASCII;
674 fdata->pseudo_header = phdr->pseudo_header;
679 protocol_tree = proto_tree_create_root();
680 dissect_packet(buf, fdata, protocol_tree);
681 passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
682 proto_tree_free(protocol_tree);
685 plist_end = cf->plist_end;
686 fdata->prev = plist_end;
687 if (plist_end != NULL)
688 plist_end->next = fdata;
691 cf->plist_end = fdata;
694 fdata->num = cf->count;
695 add_packet_to_packet_list(fdata, cf, buf);
701 filter_packets(capture_file *cf, gchar *dftext)
705 if (dftext == NULL) {
706 /* The new filter is an empty filter (i.e., display all packets). */
710 * We have a filter; try to compile it.
712 if (dfilter_compile(dftext, &dfcode) != 0) {
713 /* The attempt failed; report an error. */
714 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
719 if (dfcode == NULL) {
720 /* Yes - free the filter text, and set it to null. */
726 /* We have a valid filter. Replace the current filter. */
727 if (cf->dfilter != NULL)
729 cf->dfilter = dftext;
730 if (cf->dfcode != NULL)
731 dfilter_destroy(cf->dfcode);
734 /* Now go through the list of packets we've read from the capture file,
735 applying the current display filter, and, if the packet passes the
736 display filter, add it to the summary display, appropriately
737 colored. (That's how we colorize the display - it's like filtering
738 the display, only we don't install a new filter.) */
739 colorize_packets(cf);
744 colorize_packets(capture_file *cf)
747 guint32 progbar_quantum;
748 guint32 progbar_nextstep;
751 /* We need to re-initialize all the state information that protocols
752 keep, because we're making a fresh pass through all the packets. */
754 /* Initialize the table of conversations. */
757 /* Initialize protocol-specific variables */
758 init_all_protocols();
760 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
762 /* Freeze the packet list while we redo it, so we don't get any
763 screen updates while it happens. */
764 gtk_clist_freeze(GTK_CLIST(packet_list));
767 gtk_clist_clear(GTK_CLIST(packet_list));
769 /* We don't yet know which will be the first and last frames displayed. */
770 cf->first_displayed = NULL;
771 cf->last_displayed = NULL;
773 /* If a packet was selected, we don't know yet what row, if any, it'll
775 cf->current_row = -1;
777 /* Iterate through the list of packets, calling a routine
778 to run the filter on the packet, see if it matches, and
779 put it in the display list if so. */
785 proto_tree_is_visible = FALSE;
787 /* Update the progress bar when it gets to this value. */
788 progbar_nextstep = 0;
789 /* When we reach the value that triggers a progress bar update,
790 bump that value by this amount. */
791 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
792 /* Count of packets at which we've looked. */
795 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
797 for (fd = cf->plist; fd != NULL; fd = fd->next) {
798 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
799 when we update it, we have to run the GTK+ main loop to get it
800 to repaint what's pending, and doing so may involve an "ioctl()"
801 to see if there's any pending input from an X server, and doing
802 that for every packet can be costly, especially on a big file. */
803 if (count >= progbar_nextstep) {
804 /* let's not divide by zero. I should never be started
805 * with count == 0, so let's assert that
807 g_assert(cf->count > 0);
809 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
810 (gfloat) count / cf->count);
812 progbar_nextstep += progbar_quantum;
813 while (gtk_events_pending())
814 gtk_main_iteration();
819 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
821 add_packet_to_packet_list(fd, cf, cf->pd);
824 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
826 if (cf->current_row != -1) {
827 /* The current frame passed the filter; make sure it's visible. */
828 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), cf->current_row))
829 gtk_clist_moveto(GTK_CLIST(packet_list), cf->current_row, -1, 0.0, 0.0);
830 if (cf->current_frame_is_selected) {
831 /* It was selected, so re-select it. */
832 gtk_clist_select_row(GTK_CLIST(packet_list), cf->current_row, -1);
834 finfo_selected = NULL;
836 /* The current frame didn't pass the filter; make the first frame
837 the current frame, and leave it unselected. */
839 cf->current_frame = cf->first_displayed;
842 /* Unfreeze the packet list. */
843 gtk_clist_thaw(GTK_CLIST(packet_list));
846 #define MAX_LINE_LENGTH 256
849 print_packets(capture_file *cf, print_args_t *print_args)
853 guint32 progbar_quantum;
854 guint32 progbar_nextstep;
856 proto_tree *protocol_tree;
857 gint *col_widths = NULL;
859 gboolean print_separator;
860 char line_buf[MAX_LINE_LENGTH+1]; /* static-sized buffer! */
864 cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
865 if (cf->print_fh == NULL)
866 return FALSE; /* attempt to open destination failed */
868 print_preamble(cf->print_fh, print_args->format);
870 if (print_args->print_summary) {
871 /* We're printing packet summaries.
873 Find the widths for each of the columns - maximum of the
874 width of the title and the width of the data - and print
875 the column titles. */
876 col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
878 for (i = 0; i < cf->cinfo.num_cols; i++) {
879 /* Don't pad the last column. */
880 if (i == cf->cinfo.num_cols - 1)
883 col_widths[i] = strlen(cf->cinfo.col_title[i]);
884 data_width = get_column_char_width(get_column_format(i));
885 if (data_width > col_widths[i])
886 col_widths[i] = data_width;
889 /* Right-justify the packet number column. */
890 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
891 sprintf_len = sprintf(cp, "%*s", col_widths[i], cf->cinfo.col_title[i]);
893 sprintf_len = sprintf(cp, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
895 if (i == cf->cinfo.num_cols - 1)
901 print_line(cf->print_fh, print_args->format, line_buf);
904 print_separator = FALSE;
905 proto_tree_is_visible = TRUE;
907 /* Update the progress bar when it gets to this value. */
908 progbar_nextstep = 0;
909 /* When we reach the value that triggers a progress bar update,
910 bump that value by this amount. */
911 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
912 /* Count of packets at which we've looked. */
915 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
917 /* Iterate through the list of packets, printing the packets that
918 were selected by the current display filter. */
919 for (fd = cf->plist; fd != NULL; fd = fd->next) {
920 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
921 when we update it, we have to run the GTK+ main loop to get it
922 to repaint what's pending, and doing so may involve an "ioctl()"
923 to see if there's any pending input from an X server, and doing
924 that for every packet can be costly, especially on a big file. */
925 if (count >= progbar_nextstep) {
926 /* let's not divide by zero. I should never be started
927 * with count == 0, so let's assert that
929 g_assert(cf->count > 0);
931 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
932 (gfloat) count / cf->count);
933 progbar_nextstep += progbar_quantum;
934 while (gtk_events_pending())
935 gtk_main_iteration();
939 if (fd->passed_dfilter) {
940 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
941 if (print_args->print_summary) {
942 /* Fill in the column information, but don't bother creating
943 the logical protocol tree. */
944 fd->cinfo = &cf->cinfo;
945 for (i = 0; i < fd->cinfo->num_cols; i++) {
946 fd->cinfo->col_data[i][0] = '\0';
948 dissect_packet(cf->pd, fd, NULL);
951 for (i = 0; i < cf->cinfo.num_cols; i++) {
952 /* Right-justify the packet number column. */
953 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
954 sprintf_len = sprintf(cp, "%*s", col_widths[i], cf->cinfo.col_data[i]);
956 sprintf_len = sprintf(cp, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
958 if (i == cf->cinfo.num_cols - 1)
964 print_line(cf->print_fh, print_args->format, line_buf);
967 print_line(cf->print_fh, print_args->format, "\n");
969 /* Create the logical protocol tree. */
970 protocol_tree = proto_tree_create_root();
971 dissect_packet(cf->pd, fd, protocol_tree);
973 /* Print the information in that tree. */
974 proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
975 cf->pd, fd, cf->print_fh);
977 proto_tree_free(protocol_tree);
979 if (print_args->print_hex) {
980 /* Print the full packet data as hex. */
981 print_hex_data(cf->print_fh, print_args->format, cf->pd,
982 fd->cap_len, fd->encoding);
985 /* Print a blank line if we print anything after this. */
986 print_separator = TRUE;
991 if (col_widths != NULL)
994 print_finale(cf->print_fh, print_args->format);
996 close_print_dest(print_args->to_file, cf->print_fh);
998 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
1000 cf->print_fh = NULL;
1004 /* Scan through the packet list and change all columns that use the
1005 "command-line-specified" time stamp format to use the current
1006 value of that format. */
1008 change_time_formats(capture_file *cf)
1014 /* Freeze the packet list while we redo it, so we don't get any
1015 screen updates while it happens. */
1018 /* Iterate through the list of packets, checking whether the packet
1019 is in a row of the summary list and, if so, whether there are
1020 any columns that show the time in the "command-line-specified"
1021 format and, if so, update that row. */
1022 for (fd = cf->plist; fd != NULL; fd = fd->next) {
1023 if (fd->row != -1) {
1024 /* This packet is in the summary list, on row "fd->row". */
1026 /* XXX - there really should be a way of checking "cf->cinfo" for this;
1027 the answer isn't going to change from packet to packet, so we should
1028 simply skip all the "change_time_formats()" work if we're not
1029 changing anything. */
1030 fd->cinfo = &cf->cinfo;
1031 if (check_col(fd, COL_CLS_TIME)) {
1032 /* There are columns that show the time in the "command-line-specified"
1033 format; update them. */
1034 for (i = 0; i < cf->cinfo.num_cols; i++) {
1035 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
1036 /* This is one of the columns that shows the time in
1037 "command-line-specified" format; update it. */
1038 cf->cinfo.col_data[i][0] = '\0';
1039 col_set_cls_time(fd, i);
1040 gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
1041 cf->cinfo.col_data[i]);
1048 /* Set the column widths of those columns that show the time in
1049 "command-line-specified" format. */
1050 pl_style = gtk_widget_get_style(packet_list);
1051 for (i = 0; i < cf->cinfo.num_cols; i++) {
1052 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
1053 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1054 gdk_string_width(pl_style->font, get_column_longest_string(COL_CLS_TIME)));
1058 /* Unfreeze the packet list. */
1063 clear_tree_and_hex_views(void)
1065 /* Clear the hex dump. */
1066 gtk_text_freeze(GTK_TEXT(byte_view));
1067 gtk_text_set_point(GTK_TEXT(byte_view), 0);
1068 gtk_text_forward_delete(GTK_TEXT(byte_view),
1069 gtk_text_get_length(GTK_TEXT(byte_view)));
1070 gtk_text_thaw(GTK_TEXT(byte_view));
1072 /* Remove all nodes in ctree. This is how it's done in testgtk.c in GTK+ */
1073 gtk_clist_clear ( GTK_CLIST(tree_view) );
1078 find_packet(capture_file *cf, dfilter *sfcode)
1080 frame_data *start_fd;
1082 frame_data *new_fd = NULL;
1083 guint32 progbar_quantum;
1084 guint32 progbar_nextstep;
1086 proto_tree *protocol_tree;
1088 start_fd = cf->current_frame;
1089 if (start_fd != NULL) {
1090 gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
1092 /* Iterate through the list of packets, starting at the packet we've
1093 picked, calling a routine to run the filter on the packet, see if
1094 it matches, and stop if so. */
1098 proto_tree_is_visible = FALSE;
1100 /* Update the progress bar when it gets to this value. */
1101 progbar_nextstep = 0;
1102 /* When we reach the value that triggers a progress bar update,
1103 bump that value by this amount. */
1104 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1105 gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
1109 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1110 when we update it, we have to run the GTK+ main loop to get it
1111 to repaint what's pending, and doing so may involve an "ioctl()"
1112 to see if there's any pending input from an X server, and doing
1113 that for every packet can be costly, especially on a big file. */
1114 if (count >= progbar_nextstep) {
1115 /* let's not divide by zero. I should never be started
1116 * with count == 0, so let's assert that
1118 g_assert(cf->count > 0);
1120 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
1121 (gfloat) count / cf->count);
1123 progbar_nextstep += progbar_quantum;
1124 while (gtk_events_pending())
1125 gtk_main_iteration();
1128 /* Go past the current frame. */
1129 if (cf->sbackward) {
1130 /* Go on to the previous frame. */
1133 fd = cf->plist_end; /* wrap around */
1135 /* Go on to the next frame. */
1138 fd = cf->plist; /* wrap around */
1141 if (fd == start_fd) {
1142 /* We're back to the frame we were on originally. The search
1149 /* Is this packet in the display? */
1150 if (fd->passed_dfilter) {
1151 /* Yes. Does it match the search filter? */
1152 protocol_tree = proto_tree_create_root();
1153 wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1154 dissect_packet(cf->pd, fd, protocol_tree);
1155 if (dfilter_apply(sfcode, protocol_tree, cf->pd)) {
1157 break; /* found it! */
1162 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
1165 if (new_fd != NULL) {
1166 /* We found a frame. Make it visible, and select it. */
1167 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), new_fd->row))
1168 gtk_clist_moveto(GTK_CLIST(packet_list), new_fd->row, -1, 0.0, 0.0);
1170 /* XXX - why is there no "gtk_clist_set_focus_row()", so that we
1171 can make the row for the frame we found the focus row?
1175 http://www.gnome.org/mailing-lists/archives/gtk-list/2000-January/0038.shtml
1178 GTK_CLIST(packet_list)->focus_row = new_fd->row;
1179 gtk_clist_select_row(GTK_CLIST(packet_list), new_fd->row, -1);
1180 return TRUE; /* success */
1182 return FALSE; /* failure */
1186 goto_frame(capture_file *cf, guint fnumber)
1190 for (fd = cf->plist; fd != NULL && fd->num < fnumber; fd = fd->next)
1194 return NO_SUCH_FRAME; /* we didn't find that frame */
1195 if (!fd->passed_dfilter)
1196 return FRAME_NOT_DISPLAYED; /* the frame with that number isn't displayed */
1198 /* We found that frame, and it's currently being displayed.
1199 Make it visible, and select it. */
1200 if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), fd->row))
1201 gtk_clist_moveto(GTK_CLIST(packet_list), fd->row, -1, 0.0, 0.0);
1203 /* See above complaint about the lack of "gtk_clist_set_focus_row()". */
1204 GTK_CLIST(packet_list)->focus_row = fd->row;
1205 gtk_clist_select_row(GTK_CLIST(packet_list), fd->row, -1);
1209 /* Select the packet on a given row. */
1211 select_packet(capture_file *cf, int row)
1216 /* Search through the list of frames to see which one is in
1218 for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
1223 g_assert(fd != NULL);
1225 /* Record that this frame is the current frame, and that it's selected. */
1226 cf->current_frame = fd;
1227 cf->current_frame_is_selected = TRUE;
1229 /* Get the data in that frame. */
1230 wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1232 /* Create the logical protocol tree. */
1233 if (cf->protocol_tree)
1234 proto_tree_free(cf->protocol_tree);
1235 cf->protocol_tree = proto_tree_create_root();
1236 proto_tree_is_visible = TRUE;
1237 dissect_packet(cf->pd, cf->current_frame, cf->protocol_tree);
1239 /* Display the GUI protocol tree and hex dump. */
1240 clear_tree_and_hex_views();
1241 proto_tree_draw(cf->protocol_tree, tree_view);
1242 packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->current_frame->cap_len,
1243 -1, -1, cf->current_frame->encoding);
1245 /* A packet is selected. */
1246 set_menus_for_selected_packet(TRUE);
1249 /* Unselect the selected packet, if any. */
1251 unselect_packet(capture_file *cf)
1253 cf->current_frame_is_selected = FALSE;
1255 /* Destroy the protocol tree for that packet. */
1256 if (cf->protocol_tree != NULL) {
1257 proto_tree_free(cf->protocol_tree);
1258 cf->protocol_tree = NULL;
1261 finfo_selected = NULL;
1263 /* Clear out the display of that packet. */
1264 clear_tree_and_hex_views();
1266 /* No packet is selected. */
1267 set_menus_for_selected_packet(FALSE);
1271 freeze_clist(capture_file *cf)
1275 /* Make the column sizes static, so they don't adjust while
1276 we're reading the capture file (freezing the clist doesn't
1277 seem to suffice). */
1278 for (i = 0; i < cf->cinfo.num_cols; i++)
1279 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
1280 gtk_clist_freeze(GTK_CLIST(packet_list));
1284 thaw_clist(capture_file *cf)
1288 for (i = 0; i < cf->cinfo.num_cols; i++) {
1289 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
1290 /* Set this column's width to the appropriate value. */
1291 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1292 cf->cinfo.col_width[i]);
1294 /* Make this column's size dynamic, so that it adjusts to the
1295 appropriate size. */
1296 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1299 gtk_clist_thaw(GTK_CLIST(packet_list));
1301 /* Hopefully, the columns have now gotten their appropriate sizes;
1302 make them resizeable - a column that auto-resizes cannot be
1303 resized by the user, and *vice versa*. */
1304 for (i = 0; i < cf->cinfo.num_cols; i++)
1305 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
1309 save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
1312 gchar *from_filename;
1313 gchar *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
1317 int from_fd, to_fd, nread, nwritten;
1320 struct wtap_pkthdr hdr;
1323 if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
1327 msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
1328 save_msg = g_malloc(msg_len);
1329 snprintf(save_msg, msg_len, save_fmt, name_ptr);
1330 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
1333 if (!save_filtered && save_format == cf->cd_t) {
1334 /* We're not filtering packets, and we're saving it in the format
1335 it's already in, so we can just move or copy the raw data. */
1337 /* In this branch, we set "err" only if we get an error, so we
1338 must first clear it. */
1340 if (cf->is_tempfile) {
1341 /* The file being saved is a temporary file from a live
1342 capture, so it doesn't need to stay around under that name;
1343 first, try renaming the capture buffer file to the new name. */
1344 if (rename(cf->filename, fname) == 0) {
1345 /* That succeeded - there's no need to copy the source file. */
1346 from_filename = NULL;
1349 if (errno == EXDEV) {
1350 /* They're on different file systems, so we have to copy the
1353 from_filename = cf->filename;
1355 /* The rename failed, but not because they're on different
1356 file systems - put up an error message. (Or should we
1357 just punt and try to copy? The only reason why I'd
1358 expect the rename to fail and the copy to succeed would
1359 be if we didn't have permission to remove the file from
1360 the temporary directory, and that might be fixable - but
1361 is it worth requiring the user to go off and fix it?) */
1363 simple_dialog(ESD_TYPE_WARN, NULL,
1364 file_rename_error_message(err), fname);
1369 /* It's a permanent file, so we should copy it, and not remove the
1372 from_filename = cf->filename;
1375 /* Copy the file, if we haven't moved it. */
1377 /* Copy the raw bytes of the file. */
1378 from_fd = open(from_filename, O_RDONLY);
1381 simple_dialog(ESD_TYPE_WARN, NULL,
1382 file_open_error_message(err, TRUE), from_filename);
1386 to_fd = creat(fname, 0644);
1389 simple_dialog(ESD_TYPE_WARN, NULL,
1390 file_open_error_message(err, TRUE), fname);
1395 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
1396 nwritten = write(to_fd, pd, nread);
1397 if (nwritten < nread) {
1401 err = WTAP_ERR_SHORT_WRITE;
1402 simple_dialog(ESD_TYPE_WARN, NULL,
1403 file_write_error_message(err), fname);
1411 simple_dialog(ESD_TYPE_WARN, NULL,
1412 file_read_error_message(err), from_filename);
1418 if (close(to_fd) < 0) {
1420 simple_dialog(ESD_TYPE_WARN, NULL,
1421 file_close_error_message(err), fname);
1426 /* Either we're filtering packets, or we're saving in a different
1427 format; we can't do that by copying or moving the capture file,
1428 we have to do it by writing the packets out in Wiretap. */
1429 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
1431 simple_dialog(ESD_TYPE_WARN, NULL,
1432 file_open_error_message(err, TRUE), fname);
1436 /* XXX - have a way to save only the packets currently selected by
1439 If we do that, should we make that file the current file? If so,
1440 it means we can no longer get at the other packets. What does
1442 for (fd = cf->plist; fd != NULL; fd = fd->next) {
1443 /* XXX - do a progress bar */
1444 if (!save_filtered || fd->passed_dfilter) {
1445 /* Either we're saving all frames, or we're saving filtered frames
1446 and this one passed the display filter - save it. */
1447 hdr.ts.tv_sec = fd->abs_secs;
1448 hdr.ts.tv_usec = fd->abs_usecs;
1449 hdr.caplen = fd->cap_len;
1450 hdr.len = fd->pkt_len;
1451 hdr.pkt_encap = fd->lnk_t;
1452 hdr.pseudo_header = fd->pseudo_header;
1453 wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, pd, fd->cap_len);
1455 if (!wtap_dump(pdh, &hdr, pd, &err)) {
1456 simple_dialog(ESD_TYPE_WARN, NULL,
1457 file_write_error_message(err), fname);
1458 wtap_dump_close(pdh, &err);
1464 if (!wtap_dump_close(pdh, &err)) {
1465 simple_dialog(ESD_TYPE_WARN, NULL,
1466 file_close_error_message(err), fname);
1473 /* Pop the "Saving:" message off the status bar. */
1474 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1476 if (!save_filtered) {
1477 /* We saved the entire capture, not just some packets from it.
1478 Open and read the file we saved it to.
1480 XXX - this is somewhat of a waste; we already have the
1481 packets, all this gets us is updated file type information
1482 (which we could just stuff into "cf"), and having the new
1483 file be the one we have opened and from which we're reading
1484 the data, and it means we have to spend time opening and
1485 reading the file, which could be a significant amount of
1486 time if the file is large. */
1487 cf->user_saved = TRUE;
1489 if ((err = open_cap_file(fname, FALSE, cf)) == 0) {
1490 /* XXX - report errors if this fails? */
1491 err = read_cap_file(cf);
1492 set_menus_for_unsaved_capture_file(FALSE);
1500 file_open_error_message(int err, int for_writing)
1503 static char errmsg_errno[1024+1];
1507 case WTAP_ERR_NOT_REGULAR_FILE:
1508 errmsg = "The file \"%s\" is invalid.";
1511 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
1512 case WTAP_ERR_UNSUPPORTED:
1513 /* Seen only when opening a capture file for reading. */
1514 errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
1517 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
1518 /* Seen only when opening a capture file for writing. */
1519 errmsg = "Ethereal does not support writing capture files in that format.";
1522 case WTAP_ERR_UNSUPPORTED_ENCAP:
1523 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
1524 /* Seen only when opening a capture file for writing. */
1525 errmsg = "Ethereal cannot save this capture in that format.";
1528 case WTAP_ERR_BAD_RECORD:
1529 errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1532 case WTAP_ERR_CANT_OPEN:
1534 errmsg = "The file \"%s\" could not be created for some unknown reason.";
1536 errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1539 case WTAP_ERR_SHORT_READ:
1540 errmsg = "The file \"%s\" appears to have been cut short"
1541 " in the middle of a packet.";
1544 case WTAP_ERR_SHORT_WRITE:
1545 errmsg = "A full header couldn't be written to the file \"%s\".";
1550 errmsg = "The path to the file \"%s\" does not exist.";
1552 errmsg = "The file \"%s\" does not exist.";
1557 errmsg = "You do not have permission to create or write to the file \"%s\".";
1559 errmsg = "You do not have permission to read the file \"%s\".";
1563 sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1564 wtap_strerror(err));
1565 errmsg = errmsg_errno;
1572 file_rename_error_message(int err)
1575 static char errmsg_errno[1024+1];
1580 errmsg = "The path to the file \"%s\" does not exist.";
1584 errmsg = "You do not have permission to move the capture file to \"%s\".";
1588 sprintf(errmsg_errno, "The file \"%%s\" could not be moved: %s.",
1589 wtap_strerror(err));
1590 errmsg = errmsg_errno;
1597 file_read_error_message(int err)
1599 static char errmsg_errno[1024+1];
1601 sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
1602 wtap_strerror(err));
1603 return errmsg_errno;
1607 file_write_error_message(int err)
1610 static char errmsg_errno[1024+1];
1615 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1620 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1625 sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
1626 wtap_strerror(err));
1627 errmsg = errmsg_errno;
1633 /* Check for write errors - if the file is being written to an NFS server,
1634 a write error may not show up until the file is closed, as NFS clients
1635 might not send writes to the server until the "write()" call finishes,
1636 so that the write may fail on the server but the "write()" may succeed. */
1638 file_close_error_message(int err)
1641 static char errmsg_errno[1024+1];
1645 case WTAP_ERR_CANT_CLOSE:
1646 errmsg = "The file \"%s\" couldn't be closed for some unknown reason.";
1649 case WTAP_ERR_SHORT_WRITE:
1650 errmsg = "Not all the data could be written to the file \"%s\".";
1654 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1659 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1664 sprintf(errmsg_errno, "An error occurred while closing the file \"%%s\": %s.",
1665 wtap_strerror(err));
1666 errmsg = errmsg_errno;