4 * $Id: file.c,v 1.88 1999/09/11 04:50:34 gerald 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.
50 #ifdef NEED_SNPRINTF_H
56 # include "snprintf.h"
59 #ifdef NEED_STRERROR_H
63 #ifdef HAVE_SYS_TYPES_H
64 # include <sys/types.h>
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
78 #include "gtk/proto_draw.h"
80 #include "timestamp.h"
82 #include "packet-ncp.h"
84 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
85 extern guint file_ctx;
87 extern int sync_pipe[];
91 static guint32 firstsec, firstusec;
92 static guint32 prevsec, prevusec;
94 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
97 static void freeze_clist(capture_file *cf);
98 static void thaw_clist(capture_file *cf);
100 /* Update the progress bar this many times when reading a file. */
101 #define N_PROGBAR_UPDATES 100
104 open_cap_file(char *fname, capture_file *cf) {
110 wth = wtap_open_offline(fname, &err);
114 /* Find the size of the file. */
116 if (fstat(fileno(fh), &cf_stat) < 0) {
122 /* The open succeeded. Close whatever capture file we had open,
123 and fill in the information for this file. */
124 close_cap_file(cf, info_bar, file_ctx);
126 /* Initialize protocol-specific variables */
131 cf->f_len = cf_stat.st_size;
133 /* set the file name because we need it to set the follow stream filter */
134 cf->filename = g_strdup(fname);
136 cf->cd_t = wtap_file_type(cf->wth);
137 cf->cd_t_desc = wtap_file_type_string(cf->wth);
142 cf->snap = wtap_snapshot_length(cf->wth);
143 cf->update_progbar = FALSE;
144 cf->progbar_quantum = 0;
145 cf->progbar_nextstep = 0;
146 firstsec = 0, firstusec = 0;
147 prevsec = 0, prevusec = 0;
152 simple_dialog(ESD_TYPE_WARN, NULL,
153 file_open_error_message(err, FALSE), fname);
157 /* Reset everything to a pristine state */
159 close_cap_file(capture_file *cf, void *w, guint context) {
160 frame_data *fd, *fd_next;
170 for (fd = cf->plist; fd != NULL; fd = fd_next) {
174 if (cf->rfcode != NULL) {
175 dfilter_destroy(cf->rfcode);
179 cf->plist_end = NULL;
180 unselect_packet(cf); /* nothing to select */
182 gtk_clist_freeze(GTK_CLIST(packet_list));
183 gtk_clist_clear(GTK_CLIST(packet_list));
184 gtk_clist_thaw(GTK_CLIST(packet_list));
185 gtk_statusbar_pop(GTK_STATUSBAR(w), context);
187 /* Disable all menu items that make sense only if you have a capture. */
188 set_menu_sensitivity("/File/Save", FALSE);
189 set_menu_sensitivity("/File/Save As...", FALSE);
190 set_menu_sensitivity("/File/Close", FALSE);
191 set_menu_sensitivity("/File/Reload", FALSE);
192 set_menu_sensitivity("/File/Print...", FALSE);
193 set_menu_sensitivity("/Display/Options...", FALSE);
194 set_menu_sensitivity("/Tools/Summary", FALSE);
198 read_cap_file(capture_file *cf) {
199 gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
200 gchar *done_fmt = " File: %s Drops: %d";
205 char errmsg_errno[1024+1];
206 gchar err_str[2048+1];
208 if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
209 name_ptr = cf->filename;
213 load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
214 sprintf(load_msg, load_fmt, name_ptr);
215 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
217 cf->update_progbar = TRUE;
218 /* Update the progress bar when it gets to this value. */
219 cf->progbar_nextstep = 0;
220 /* When we reach the value that triggers a progress bar update,
221 bump that value by this amount. */
222 cf->progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
225 proto_tree_is_visible = FALSE;
226 success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
229 cf->fh = fopen(cf->filename, "r");
232 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
234 gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
236 msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
237 load_msg = g_realloc(load_msg, msg_len);
239 if (cf->user_saved || !cf->save_file)
240 snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
242 snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
244 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
247 /* Enable menu items that make sense if you have a capture. */
248 set_menu_sensitivity("/File/Close", TRUE);
249 set_menu_sensitivity("/File/Reload", TRUE);
250 set_menu_sensitivity("/File/Print...", TRUE);
251 set_menu_sensitivity("/Display/Options...", TRUE);
252 set_menu_sensitivity("/Tools/Summary", TRUE);
255 /* Put up a message box noting that the read failed somewhere along
256 the line. Don't throw out the stuff we managed to read, though,
260 case WTAP_ERR_CANT_READ:
261 errmsg = "An attempt to read from the file failed for"
262 " some unknown reason.";
265 case WTAP_ERR_SHORT_READ:
266 errmsg = "The capture file appears to have been cut short"
267 " in the middle of a packet.";
270 case WTAP_ERR_BAD_RECORD:
271 errmsg = "The capture file appears to be damaged or corrupt.";
275 sprintf(errmsg_errno, "An error occurred while reading the"
276 " capture file: %s.", wtap_strerror(err));
277 errmsg = errmsg_errno;
280 snprintf(err_str, sizeof err_str, errmsg);
281 simple_dialog(ESD_TYPE_WARN, NULL, err_str);
289 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
291 capture_file *cf = (capture_file *)data;
292 char buffer[256], *p = buffer, *q = buffer;
295 gboolean exit_loop = FALSE;
298 /* avoid reentrancy problems and stack overflow */
299 gtk_input_remove(cap_input_id);
301 if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
303 /* The child has closed the sync pipe, meaning it's not going to be
304 capturing any more packets. Read what remains of the capture file,
305 and stop capture (restore menu items) */
306 gtk_clist_freeze(GTK_CLIST(packet_list));
308 /* XXX - do something if this fails? */
309 wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
315 set_menu_sensitivity("/File/Open...", TRUE);
316 set_menu_sensitivity("/File/Close", TRUE);
317 set_menu_sensitivity("/File/Save As...", TRUE);
318 set_menu_sensitivity("/File/Print...", TRUE);
319 set_menu_sensitivity("/File/Reload", TRUE);
321 set_menu_sensitivity("/Capture/Start...", TRUE);
323 set_menu_sensitivity("/Tools/Summary", TRUE);
324 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
328 buffer[nread] = '\0';
331 /* look for (possibly multiple) '*' */
339 /* XXX should handle the case of a pipe full (i.e. no star found) */
348 gtk_clist_freeze(GTK_CLIST(packet_list));
349 /* XXX - do something if this fails? */
350 wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
351 gtk_clist_thaw(GTK_CLIST(packet_list));
353 /* restore pipe handler */
354 cap_input_id = gtk_input_add_full (sync_pipe[0],
363 tail_cap_file(char *fname, capture_file *cf) {
367 err = open_cap_file(fname, cf);
368 if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
370 set_menu_sensitivity("/File/Open...", FALSE);
371 set_menu_sensitivity("/Display/Options...", TRUE);
373 set_menu_sensitivity("/Capture/Start...", FALSE);
376 for (i = 0; i < cf->cinfo.num_cols; i++) {
377 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
378 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
380 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
381 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
382 cf->cinfo.col_width[i]);
383 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
387 cf->fh = fopen(fname, "r");
389 cap_input_id = gtk_input_add_full (sync_pipe[0],
395 gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx,
396 " <live capture in progress>");
405 /* To do: Add check_col checks to the col_add* routines */
408 col_add_abs_time(frame_data *fd, gint el)
414 tmp = localtime(&then);
415 col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
419 (long)fd->abs_usecs/100);
423 col_add_rel_time(frame_data *fd, gint el)
425 col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
429 col_add_delta_time(frame_data *fd, gint el)
431 col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
434 /* Add "command-line-specified" time. */
436 col_add_cls_time(frame_data *fd)
438 switch (timestamp_type) {
440 col_add_abs_time(fd, COL_CLS_TIME);
444 col_add_rel_time(fd, COL_CLS_TIME);
448 col_add_delta_time(fd, COL_CLS_TIME);
454 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
459 proto_tree *protocol_tree;
461 /* If we don't have the time stamp of the first packet in the
462 capture, it's because this is the first packet. Save the time
463 stamp of this packet as the time stamp of the first packet. */
464 if (!firstsec && !firstusec) {
465 firstsec = fdata->abs_secs;
466 firstusec = fdata->abs_usecs;
469 /* Get the time elapsed between the first packet and this packet. */
470 cf->esec = fdata->abs_secs - firstsec;
471 if (firstusec <= fdata->abs_usecs) {
472 cf->eusec = fdata->abs_usecs - firstusec;
474 cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
478 fdata->cinfo = &cf->cinfo;
479 for (i = 0; i < fdata->cinfo->num_cols; i++) {
480 fdata->cinfo->col_data[i][0] = '\0';
483 /* Apply the filters */
484 if (DFILTER_CONTAINS_FILTER(cf->dfcode) ||
485 CFILTERS_CONTAINS_FILTER(cf)) {
486 protocol_tree = proto_tree_create_root();
487 dissect_packet(buf, fdata, protocol_tree);
488 if( DFILTER_CONTAINS_FILTER(cf->dfcode) )
489 fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
491 fdata->passed_dfilter = TRUE;
492 /* Apply color filters. */
494 for(crow = 0; cf->colors->num_of_filters &&
495 crow < cf->colors->num_of_filters; crow++) {
496 if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
503 proto_tree_free(protocol_tree);
506 dissect_packet(buf, fdata, NULL);
507 fdata->passed_dfilter = TRUE;
510 if (fdata->passed_dfilter) {
511 if (check_col(fdata, COL_NUMBER))
512 col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
514 /* If we don't have the time stamp of the previous displayed packet,
515 it's because this is the first displayed packet. Save the time
516 stamp of this packet as the time stamp of the previous displayed
518 if (!prevsec && !prevusec) {
519 prevsec = fdata->abs_secs;
520 prevusec = fdata->abs_usecs;
523 /* Get the time elapsed between the first packet and this packet. */
524 fdata->rel_secs = cf->esec;
525 fdata->rel_usecs = cf->eusec;
527 /* Get the time elapsed between the previous displayed packet and
529 fdata->del_secs = fdata->abs_secs - prevsec;
530 if (prevusec <= fdata->abs_usecs) {
531 fdata->del_usecs = fdata->abs_usecs - prevusec;
533 fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
536 prevsec = fdata->abs_secs;
537 prevusec = fdata->abs_usecs;
539 /* Set any time stamp columns. */
540 if (check_col(fdata, COL_CLS_TIME))
541 col_add_cls_time(fdata);
542 if (check_col(fdata, COL_ABS_TIME))
543 col_add_abs_time(fdata, COL_ABS_TIME);
544 if (check_col(fdata, COL_REL_TIME))
545 col_add_rel_time(fdata, COL_REL_TIME);
546 if (check_col(fdata, COL_DELTA_TIME))
547 col_add_delta_time(fdata, COL_DELTA_TIME);
549 if (check_col(fdata, COL_PACKET_LENGTH))
550 col_add_fstr(fdata, COL_PACKET_LENGTH, "%d", fdata->pkt_len);
552 row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
555 if (cf->colors->color_filters && (color != -1)){
556 gtk_clist_set_background(GTK_CLIST(packet_list), row,
557 &(color_filter(cf,color)->bg_color));
558 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
559 &(color_filter(cf,color)->fg_color));
561 gtk_clist_set_background(GTK_CLIST(packet_list), row,
563 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
568 /* If this was the selected packet, remember the row it's in, so
569 we can re-select it. ("selected_packet" is 0-origin, as it's
570 a GList index; "count", however, is 1-origin.) */
571 if (cf->selected_packet == cf->count - 1)
572 cf->selected_row = row;
574 fdata->row = -1; /* not in the display */
579 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
582 capture_file *cf = (capture_file *) user;
584 proto_tree *protocol_tree;
585 frame_data *plist_end;
587 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
588 when we update it, we have to run the GTK+ main loop to get it
589 to repaint what's pending, and doing so may involve an "ioctl()"
590 to see if there's any pending input from an X server, and doing
591 that for every packet can be costly, especially on a big file.
593 Do so only if we were told to do so; when reading a capture file
594 being updated by a live capture, we don't do so (as we're not
595 "done" until the capture stops, so we don't know how close to
597 if (cf->update_progbar && offset >= cf->progbar_nextstep) {
598 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
599 (gfloat) ftell(cf->fh) / (gfloat) cf->f_len);
600 cf->progbar_nextstep += cf->progbar_quantum;
601 while (gtk_events_pending())
602 gtk_main_iteration();
605 /* Allocate the next list entry, and add it to the list. */
606 fdata = (frame_data *) g_malloc(sizeof(frame_data));
609 fdata->pkt_len = phdr->len;
610 fdata->cap_len = phdr->caplen;
611 fdata->file_off = offset;
612 fdata->lnk_t = phdr->pkt_encap;
613 fdata->abs_secs = phdr->ts.tv_sec;
614 fdata->abs_usecs = phdr->ts.tv_usec;
615 fdata->pseudo_header = phdr->pseudo_header;
620 if (DFILTER_CONTAINS_FILTER(cf->rfcode)) {
621 protocol_tree = proto_tree_create_root();
622 dissect_packet(buf, fdata, protocol_tree);
623 passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
624 proto_tree_free(protocol_tree);
628 plist_end = cf->plist_end;
629 if (plist_end != NULL)
630 plist_end->next = fdata;
633 cf->plist_end = fdata;
636 add_packet_to_packet_list(fdata, cf, buf);
642 filter_packets(capture_file *cf)
645 guint32 progbar_quantum;
646 guint32 progbar_nextstep;
648 if (cf->dfilter == NULL) {
649 dfilter_clear_filter(cf->dfcode);
653 * Compile the filter.
655 if (dfilter_compile(cf->dfcode, cf->dfilter) != 0) {
656 simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
661 /* Freeze the packet list while we redo it, so we don't get any
662 screen updates while it happens. */
663 gtk_clist_freeze(GTK_CLIST(packet_list));
666 gtk_clist_clear(GTK_CLIST(packet_list));
668 /* If a packet was selected, we don't know yet what row, if any, it'll
670 cf->selected_row = -1;
672 /* Iterate through the list of packets, calling a routine
673 to run the filter on the packet, see if it matches, and
674 put it in the display list if so. */
679 cf->unfiltered_count = cf->count;
682 proto_tree_is_visible = FALSE;
684 /* Update the progress bar when it gets to this value. */
685 progbar_nextstep = 0;
686 /* When we reach the value that triggers a progress bar update,
687 bump that value by this amount. */
688 progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
690 for (fd = cf->plist; fd != NULL; fd = fd->next) {
691 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
692 when we update it, we have to run the GTK+ main loop to get it
693 to repaint what's pending, and doing so may involve an "ioctl()"
694 to see if there's any pending input from an X server, and doing
695 that for every packet can be costly, especially on a big file. */
696 if (cf->count >= progbar_nextstep) {
697 /* let's not divide by zero. I should never be started
698 * with unfiltered_count == 0, so let's assert that
700 g_assert(cf->unfiltered_count > 0);
702 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
703 (gfloat) cf->count / cf->unfiltered_count);
704 progbar_nextstep += progbar_quantum;
705 while (gtk_events_pending())
706 gtk_main_iteration();
711 wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
713 add_packet_to_packet_list(fd, cf, cf->pd);
716 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
718 if (cf->selected_row != -1) {
719 /* We had a selected packet and it passed the filter. */
720 gtk_clist_select_row(GTK_CLIST(packet_list), cf->selected_row, -1);
722 /* If we had one, it didn't pass the filter. */
726 /* Unfreeze the packet list. */
727 gtk_clist_thaw(GTK_CLIST(packet_list));
731 print_packets(capture_file *cf, int to_file, const char *dest)
734 proto_tree *protocol_tree;
736 cf->print_fh = open_print_dest(to_file, dest);
737 if (cf->print_fh == NULL)
738 return FALSE; /* attempt to open destination failed */
740 /* XXX - printing multiple frames in PostScript looks as if it's
741 tricky - you have to deal with page boundaries, I think -
742 and I'll have to spend some time learning enough about
743 PostScript to figure it out, so, for now, we only print
744 multiple frames as text. */
746 print_preamble(cf->print_fh);
749 proto_tree_is_visible = TRUE;
751 /* Iterate through the list of packets, printing each of them. */
753 for (fd = cf->plist; fd != NULL; fd = fd->next) {
756 wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
758 /* create the logical protocol tree */
759 protocol_tree = proto_tree_create_root();
760 dissect_packet(cf->pd, fd, protocol_tree);
762 /* Print the packet */
763 proto_tree_print(cf->count, (GNode *)protocol_tree, cf->pd, fd, cf->print_fh);
765 proto_tree_free(protocol_tree);
769 print_finale(cf->print_fh);
772 close_print_dest(to_file, cf->print_fh);
777 /* Scan through the packet list and change all columns that use the
778 "command-line-specified" time stamp format to use the current
779 value of that format. */
781 change_time_formats(capture_file *cf)
787 /* Freeze the packet list while we redo it, so we don't get any
788 screen updates while it happens. */
791 /* Iterate through the list of packets, checking whether the packet
792 is in a row of the summary list and, if so, whether there are
793 any columns that show the time in the "command-line-specified"
794 format and, if so, update that row. */
795 for (fd = cf->plist; fd != NULL; fd = fd->next) {
797 /* This packet is in the summary list, on row "fd->row". */
799 /* XXX - there really should be a way of checking "cf->cinfo" for this;
800 the answer isn't going to change from packet to packet, so we should
801 simply skip all the "change_time_formats()" work if we're not
802 changing anything. */
803 fd->cinfo = &cf->cinfo;
804 if (check_col(fd, COL_CLS_TIME)) {
805 /* There are columns that show the time in the "command-line-specified"
806 format; update them. */
807 for (i = 0; i < cf->cinfo.num_cols; i++) {
808 cf->cinfo.col_data[i][0] = '\0';
810 col_add_cls_time(fd);
811 for (i = 0; i < cf->cinfo.num_cols; i++) {
812 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
813 /* This is one of the columns that shows the time in
814 "command-line-specified" format; update it. */
815 gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
816 cf->cinfo.col_data[i]);
823 /* Set the column widths of those columns that show the time in
824 "command-line-specified" format. */
825 pl_style = gtk_widget_get_style(packet_list);
826 for (i = 0; i < cf->cinfo.num_cols; i++) {
827 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
828 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
829 get_column_width(COL_CLS_TIME, pl_style->font));
833 /* Unfreeze the packet list. */
838 clear_tree_and_hex_views(void)
843 /* Clear the hex dump. */
844 gtk_text_freeze(GTK_TEXT(byte_view));
845 gtk_text_set_point(GTK_TEXT(byte_view), 0);
846 gtk_text_forward_delete(GTK_TEXT(byte_view),
847 gtk_text_get_length(GTK_TEXT(byte_view)));
848 gtk_text_thaw(GTK_TEXT(byte_view));
850 /* Deselect any selected tree item. gtktree.c should
851 * do this when we clear_items, but it doesn't. I copied
852 * this while() loop from gtktree.c, gtk_real_tree_select_child()
854 if (GTK_TREE(tree_view)->root_tree) {
855 selection = GTK_TREE(tree_view)->root_tree->selection;
857 tmp_item = selection->data;
858 gtk_tree_item_deselect(GTK_TREE_ITEM(tmp_item));
859 gtk_widget_unref(tmp_item);
860 selection = selection->next;
862 g_list_free(GTK_TREE(tree_view)->root_tree->selection);
863 GTK_TREE(tree_view)->root_tree->selection = NULL;
866 /* Clear the protocol tree view. The length arg of -1
867 * means to clear all items up to the end. */
868 gtk_tree_clear_items(GTK_TREE(tree_view), 0, -1);
872 /* Select the packet on a given row. */
874 select_packet(capture_file *cf, int row)
879 /* Clear out whatever's currently in the hex dump. */
880 gtk_text_freeze(GTK_TEXT(byte_view));
881 gtk_text_set_point(GTK_TEXT(byte_view), 0);
882 gtk_text_forward_delete(GTK_TEXT(byte_view),
883 gtk_text_get_length(GTK_TEXT(byte_view)));
885 /* Search through the list of frames to see which one is in
887 for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
893 /* Remember the ordinal number of that frame. */
894 cf->selected_packet = i;
896 /* Get the data in that frame. */
897 wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
899 /* Create the logical protocol tree. */
900 if (cf->protocol_tree)
901 proto_tree_free(cf->protocol_tree);
902 cf->protocol_tree = proto_tree_create_root();
903 proto_tree_is_visible = TRUE;
904 dissect_packet(cf->pd, cf->fd, cf->protocol_tree);
906 /* Display the GUI protocol tree and hex dump. */
907 clear_tree_and_hex_views();
908 proto_tree_draw(cf->protocol_tree, tree_view);
909 packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->fd->cap_len, -1, -1);
910 gtk_text_thaw(GTK_TEXT(byte_view));
912 /* A packet is selected, so "File/Print Packet" has something to print. */
913 set_menu_sensitivity("/File/Print Packet", TRUE);
916 /* Unselect the selected packet, if any. */
918 unselect_packet(capture_file *cf)
920 cf->selected_packet = -1; /* nothing there to be selected */
921 cf->selected_row = -1;
923 /* Destroy the protocol tree for that packet. */
924 if (cf->protocol_tree != NULL) {
925 proto_tree_free(cf->protocol_tree);
926 cf->protocol_tree = NULL;
929 /* Clear out the display of that packet. */
930 clear_tree_and_hex_views();
932 /* No packet is selected, so "File/Print Packet" has nothing to print. */
933 set_menu_sensitivity("/File/Print Packet", FALSE);
937 freeze_clist(capture_file *cf)
941 /* Make the column sizes static, so they don't adjust while
942 we're reading the capture file (freezing the clist doesn't
944 for (i = 0; i < cf->cinfo.num_cols; i++)
945 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
946 gtk_clist_freeze(GTK_CLIST(packet_list));
950 thaw_clist(capture_file *cf)
954 for (i = 0; i < cf->cinfo.num_cols; i++) {
955 if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
956 /* Set this column's width to the appropriate value. */
957 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
958 cf->cinfo.col_width[i]);
960 /* Make this column's size dynamic, so that it adjusts to the
962 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
965 gtk_clist_thaw(GTK_CLIST(packet_list));
967 /* Hopefully, the columns have now gotten their appropriate sizes;
968 make them resizeable - a column that auto-resizes cannot be
969 resized by the user, and *vice versa*. */
970 for (i = 0; i < cf->cinfo.num_cols; i++)
971 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
974 /* Tries to mv a file. If unsuccessful, tries to cp the file.
975 * Returns 0 on failure to do either, 1 on success of either
978 file_mv(char *from, char *to)
981 #define COPY_BUFFER_SIZE 8192
986 /* try a hard link */
987 retval = link(from, to);
992 retval = file_cp(from, to);
1005 * Returns 0 on failure to do either, 1 on success of either
1008 file_cp(char *from, char *to)
1011 #define COPY_BUFFER_SIZE 8192
1013 int from_fd, to_fd, nread, nwritten;
1016 buffer = g_malloc(COPY_BUFFER_SIZE);
1018 from_fd = open(from, O_RDONLY);
1020 simple_dialog(ESD_TYPE_WARN, NULL,
1021 file_open_error_message(errno, TRUE), from);
1025 to_fd = creat(to, 0644);
1027 simple_dialog(ESD_TYPE_WARN, NULL,
1028 file_open_error_message(errno, TRUE), to);
1033 while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
1034 nwritten = write(to_fd, buffer, nread);
1035 if (nwritten < nread) {
1037 simple_dialog(ESD_TYPE_WARN, NULL,
1038 file_write_error_message(errno), to);
1040 simple_dialog(ESD_TYPE_WARN, NULL,
1041 "The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
1042 to, nread, nwritten);
1050 simple_dialog(ESD_TYPE_WARN, NULL,
1051 file_read_error_message(errno), from);
1063 file_open_error_message(int err, int for_writing)
1066 static char errmsg_errno[1024+1];
1070 case WTAP_ERR_NOT_REGULAR_FILE:
1071 errmsg = "The file \"%s\" is invalid.";
1074 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
1075 case WTAP_ERR_UNSUPPORTED:
1076 errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
1079 case WTAP_ERR_BAD_RECORD:
1080 errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1083 case WTAP_ERR_CANT_OPEN:
1085 errmsg = "The file \"%s\" could not be created for some unknown reason.";
1087 errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1090 case WTAP_ERR_SHORT_READ:
1091 errmsg = "The file \"%s\" appears to have been cut short"
1092 " in the middle of a packet.";
1097 errmsg = "The path to the file \"%s\" does not exist.";
1099 errmsg = "The file \"%s\" does not exist.";
1104 errmsg = "You do not have permission to create or write to the file \"%s\".";
1106 errmsg = "You do not have permission to read the file \"%s\".";
1110 sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1111 wtap_strerror(err));
1112 errmsg = errmsg_errno;
1119 file_read_error_message(int err)
1121 static char errmsg_errno[1024+1];
1123 sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
1124 wtap_strerror(err));
1125 return errmsg_errno;
1129 file_write_error_message(int err)
1132 static char errmsg_errno[1024+1];
1137 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1142 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1147 sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
1148 wtap_strerror(err));
1149 errmsg = errmsg_errno;