Added support for Lucent/Ascend packet traces. The MAX and Pipeline router
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id: file.c,v 1.88 1999/09/11 04:50:34 gerald Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
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.
15  * 
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.
20  * 
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.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31
32 #include <stdio.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <time.h>
39
40 #ifdef HAVE_IO_H
41 #include <io.h>
42 #endif
43
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/stat.h>
47 #include <errno.h>
48 #include <fcntl.h>
49
50 #ifdef NEED_SNPRINTF_H
51 # ifdef HAVE_STDARG_H
52 #  include <stdarg.h>
53 # else
54 #  include <varargs.h>
55 # endif
56 # include "snprintf.h"
57 #endif
58
59 #ifdef NEED_STRERROR_H
60 #include "strerror.h"
61 #endif
62
63 #ifdef HAVE_SYS_TYPES_H
64 # include <sys/types.h>
65 #endif
66
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
69 #endif
70
71 #include "gtk/main.h"
72 #include "column.h"
73 #include "gtk/menu.h"
74 #include "packet.h"
75 #include "print.h"
76 #include "file.h"
77 #include "util.h"
78 #include "gtk/proto_draw.h"
79 #include "dfilter.h"
80 #include "timestamp.h"
81
82 #include "packet-ncp.h"
83
84 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
85 extern guint      file_ctx;
86 extern int        sync_mode;
87 extern int        sync_pipe[];
88
89 guint cap_input_id;
90
91 static guint32 firstsec, firstusec;
92 static guint32 prevsec, prevusec;
93
94 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
95     const u_char *);
96
97 static void freeze_clist(capture_file *cf);
98 static void thaw_clist(capture_file *cf);
99
100 /* Update the progress bar this many times when reading a file. */
101 #define N_PROGBAR_UPDATES       100
102
103 int
104 open_cap_file(char *fname, capture_file *cf) {
105   wtap       *wth;
106   int         err;
107   FILE       *fh;
108   struct stat cf_stat;
109
110   wth = wtap_open_offline(fname, &err);
111   if (wth == NULL)
112     goto fail;
113
114   /* Find the size of the file. */
115   fh = wtap_file(wth);
116   if (fstat(fileno(fh), &cf_stat) < 0) {
117     err = errno;
118     wtap_close(wth);
119     goto fail;
120   }
121
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);
125
126   /* Initialize protocol-specific variables */
127   ncp_init_protocol();
128
129   cf->wth = wth;
130   cf->fh = fh;
131   cf->f_len = cf_stat.st_size;
132
133   /* set the file name because we need it to set the follow stream filter */
134   cf->filename = g_strdup(fname);
135
136   cf->cd_t      = wtap_file_type(cf->wth);
137   cf->cd_t_desc = wtap_file_type_string(cf->wth);
138   cf->count     = 0;
139   cf->drops     = 0;
140   cf->esec      = 0;
141   cf->eusec     = 0;
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;
148  
149   return (0);
150
151 fail:
152   simple_dialog(ESD_TYPE_WARN, NULL,
153                         file_open_error_message(err, FALSE), fname);
154   return (err);
155 }
156
157 /* Reset everything to a pristine state */
158 void
159 close_cap_file(capture_file *cf, void *w, guint context) {
160   frame_data *fd, *fd_next;
161
162   if (cf->fh) {
163     fclose(cf->fh);
164     cf->fh = NULL;
165   }
166   if (cf->wth) {
167     wtap_close(cf->wth);
168     cf->wth = NULL;
169   }
170   for (fd = cf->plist; fd != NULL; fd = fd_next) {
171     fd_next = fd->next;
172     g_free(fd);
173   }
174   if (cf->rfcode != NULL) {
175     dfilter_destroy(cf->rfcode);
176     cf->rfcode = NULL;
177   }
178   cf->plist = NULL;
179   cf->plist_end = NULL;
180   unselect_packet(cf);  /* nothing to select */
181
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);
186
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);
195 }
196
197 int
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";
201   int     success;
202   int     err;
203   size_t  msg_len;
204   char   *errmsg;
205   char    errmsg_errno[1024+1];
206   gchar   err_str[2048+1];
207
208   if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
209     name_ptr = cf->filename;
210   else
211     name_ptr++;
212
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);
216
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;
223
224   freeze_clist(cf);
225   proto_tree_is_visible = FALSE;
226   success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
227   wtap_close(cf->wth);
228   cf->wth = NULL;
229   cf->fh = fopen(cf->filename, "r");
230   thaw_clist(cf);
231   
232   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
233
234   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
235
236   msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
237   load_msg = g_realloc(load_msg, msg_len);
238
239   if (cf->user_saved || !cf->save_file)
240     snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
241   else
242     snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
243
244   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
245   g_free(load_msg);
246
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);
253
254   if (!success) {
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,
257        if any. */
258     switch (err) {
259
260     case WTAP_ERR_CANT_READ:
261       errmsg = "An attempt to read from the file failed for"
262                " some unknown reason.";
263       break;
264
265     case WTAP_ERR_SHORT_READ:
266       errmsg = "The capture file appears to have been cut short"
267                " in the middle of a packet.";
268       break;
269
270     case WTAP_ERR_BAD_RECORD:
271       errmsg = "The capture file appears to be damaged or corrupt.";
272       break;
273
274     default:
275       sprintf(errmsg_errno, "An error occurred while reading the"
276                               " capture file: %s.", wtap_strerror(err));
277       errmsg = errmsg_errno;
278       break;
279     }
280     snprintf(err_str, sizeof err_str, errmsg);
281     simple_dialog(ESD_TYPE_WARN, NULL, err_str);
282     return (err);
283   } else
284     return (0);
285 }
286
287 #ifdef HAVE_LIBPCAP
288 void 
289 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
290   
291   capture_file *cf = (capture_file *)data;
292   char buffer[256], *p = buffer, *q = buffer;
293   int  nread;
294   int  to_read = 0;
295   gboolean exit_loop = FALSE;
296   int  err;
297
298   /* avoid reentrancy problems and stack overflow */
299   gtk_input_remove(cap_input_id);
300
301   if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
302
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));
307
308     /* XXX - do something if this fails? */
309     wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
310
311     thaw_clist(cf);
312
313     wtap_close(cf->wth);
314     cf->wth = NULL;
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);
320 #ifdef HAVE_LIBPCAP
321     set_menu_sensitivity("/Capture/Start...", TRUE);
322 #endif
323     set_menu_sensitivity("/Tools/Summary", TRUE);
324     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
325     return;
326   }
327
328   buffer[nread] = '\0';
329
330   while(!exit_loop) {
331     /* look for (possibly multiple) '*' */
332     switch (*q) {
333     case '*' :
334       to_read += atoi(p);
335       p = q + 1; 
336       q++;
337       break;
338     case '\0' :
339       /* XXX should handle the case of a pipe full (i.e. no star found) */
340       exit_loop = TRUE;
341       break;
342     default :
343       q++;
344       break;
345     } 
346   }
347
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));
352
353   /* restore pipe handler */
354   cap_input_id = gtk_input_add_full (sync_pipe[0],
355                                      GDK_INPUT_READ,
356                                      cap_file_input_cb,
357                                      NULL,
358                                      (gpointer) cf,
359                                      NULL);
360 }
361
362 int
363 tail_cap_file(char *fname, capture_file *cf) {
364   int     err;
365   int     i;
366
367   err = open_cap_file(fname, cf);
368   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
369
370     set_menu_sensitivity("/File/Open...", FALSE);
371     set_menu_sensitivity("/Display/Options...", TRUE);
372 #ifdef HAVE_LIBPCAP
373     set_menu_sensitivity("/Capture/Start...", FALSE);
374 #endif
375
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);
379       else {
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);
384       }
385     }
386
387     cf->fh = fopen(fname, "r");
388
389     cap_input_id = gtk_input_add_full (sync_pipe[0],
390                                        GDK_INPUT_READ,
391                                        cap_file_input_cb,
392                                        NULL,
393                                        (gpointer) cf,
394                                        NULL);
395     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, 
396                        " <live capture in progress>");
397   }
398   else {
399     close(sync_pipe[0]);
400   }
401   return err;
402 }
403 #endif
404
405 /* To do: Add check_col checks to the col_add* routines */
406
407 static void
408 col_add_abs_time(frame_data *fd, gint el)
409 {
410   struct tm *tmp;
411   time_t then;
412
413   then = fd->abs_secs;
414   tmp = localtime(&then);
415   col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
416     tmp->tm_hour,
417     tmp->tm_min,
418     tmp->tm_sec,
419     (long)fd->abs_usecs/100);
420 }
421
422 static void
423 col_add_rel_time(frame_data *fd, gint el)
424 {
425   col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
426 }
427
428 static void
429 col_add_delta_time(frame_data *fd, gint el)
430 {
431   col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
432 }
433
434 /* Add "command-line-specified" time. */
435 static void
436 col_add_cls_time(frame_data *fd)
437 {
438   switch (timestamp_type) {
439     case ABSOLUTE:
440       col_add_abs_time(fd, COL_CLS_TIME);
441       break;
442
443     case RELATIVE:
444       col_add_rel_time(fd, COL_CLS_TIME);
445       break;
446
447     case DELTA:
448       col_add_delta_time(fd, COL_CLS_TIME);
449       break;
450   }
451 }
452
453 static void
454 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
455 {
456   gint          i, row;
457   gint          crow;
458   gint          color;
459   proto_tree   *protocol_tree;
460
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;
467   }
468
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;
473   } else {
474     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
475     cf->esec--;
476   }
477
478   fdata->cinfo = &cf->cinfo;
479   for (i = 0; i < fdata->cinfo->num_cols; i++) {
480     fdata->cinfo->col_data[i][0] = '\0';
481   }
482
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);
490         else
491                 fdata->passed_dfilter = TRUE;
492         /* Apply color filters. */
493         color = -1;
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,
497                  cf->pd)){
498                 color = crow;
499                 break;
500             }
501         }
502
503         proto_tree_free(protocol_tree);
504   }
505   else {
506         dissect_packet(buf, fdata, NULL);
507         fdata->passed_dfilter = TRUE;
508         color = -1;
509   }
510   if (fdata->passed_dfilter) {
511     if (check_col(fdata, COL_NUMBER))
512       col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
513
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
517        packet. */
518     if (!prevsec && !prevusec) {
519       prevsec  = fdata->abs_secs;
520       prevusec = fdata->abs_usecs;
521     }
522
523     /* Get the time elapsed between the first packet and this packet. */
524     fdata->rel_secs = cf->esec;
525     fdata->rel_usecs = cf->eusec;
526   
527     /* Get the time elapsed between the previous displayed packet and
528        this packet. */
529     fdata->del_secs = fdata->abs_secs - prevsec;
530     if (prevusec <= fdata->abs_usecs) {
531       fdata->del_usecs = fdata->abs_usecs - prevusec;
532     } else {
533       fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
534       fdata->del_secs--;
535     }
536     prevsec = fdata->abs_secs;
537     prevusec = fdata->abs_usecs;
538
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);
548
549     if (check_col(fdata, COL_PACKET_LENGTH))
550       col_add_fstr(fdata, COL_PACKET_LENGTH, "%d", fdata->pkt_len);
551
552     row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
553     fdata->row = row;
554
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));
560         } else {
561                 gtk_clist_set_background(GTK_CLIST(packet_list), row,
562                    &WHITE);
563                 gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
564                    &BLACK);
565
566         }
567
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;
573   } else
574     fdata->row = -1;    /* not in the display */
575   fdata->cinfo = NULL;
576 }
577
578 static void
579 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
580   const u_char *buf) {
581   frame_data   *fdata;
582   capture_file *cf = (capture_file *) user;
583   int           passed;
584   proto_tree   *protocol_tree;
585   frame_data   *plist_end;
586
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.
592      
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
596      "done" we are. */
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();
603   }
604
605   /* Allocate the next list entry, and add it to the list. */
606   fdata = (frame_data *) g_malloc(sizeof(frame_data));
607
608   fdata->next = NULL;
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;
616   fdata->cinfo = NULL;
617
618   passed = TRUE;
619   if (cf->rfcode) {
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);
625           }
626   }   
627   if (passed) {
628     plist_end = cf->plist_end;
629     if (plist_end != NULL)
630       plist_end->next = fdata;
631     else
632       cf->plist = fdata;
633     cf->plist_end = fdata;
634
635     cf->count++;
636     add_packet_to_packet_list(fdata, cf, buf);
637   } else
638     g_free(fdata);
639 }
640
641 void
642 filter_packets(capture_file *cf)
643 {
644   frame_data *fd;
645   guint32 progbar_quantum;
646   guint32 progbar_nextstep;
647
648   if (cf->dfilter == NULL) {
649         dfilter_clear_filter(cf->dfcode);
650   }
651   else {
652     /*
653      * Compile the filter.
654      */
655     if (dfilter_compile(cf->dfcode, cf->dfilter) != 0) {
656       simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
657       return;
658     }
659   }
660
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));
664
665   /* Clear it out. */
666   gtk_clist_clear(GTK_CLIST(packet_list));
667
668   /* If a packet was selected, we don't know yet what row, if any, it'll
669      get. */
670   cf->selected_row = -1;
671
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.  */
675   firstsec = 0;
676   firstusec = 0;
677   prevsec = 0;
678   prevusec = 0;
679   cf->unfiltered_count = cf->count;
680   cf->count = 0;
681
682   proto_tree_is_visible = FALSE;
683
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;
689
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
699        */
700       g_assert(cf->unfiltered_count > 0);
701
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();
707     }
708
709     cf->count++;
710
711     wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
712
713     add_packet_to_packet_list(fd, cf, cf->pd);
714   }
715  
716   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
717
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);
721   } else {
722     /* If we had one, it didn't pass the filter. */
723     unselect_packet(cf);
724   }
725
726   /* Unfreeze the packet list. */
727   gtk_clist_thaw(GTK_CLIST(packet_list));
728 }
729
730 int
731 print_packets(capture_file *cf, int to_file, const char *dest)
732 {
733   frame_data *fd;
734   proto_tree *protocol_tree;
735
736   cf->print_fh = open_print_dest(to_file, dest);
737   if (cf->print_fh == NULL)
738     return FALSE;       /* attempt to open destination failed */
739
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. */
745 #if 0
746   print_preamble(cf->print_fh);
747 #endif
748
749   proto_tree_is_visible = TRUE;
750
751   /* Iterate through the list of packets, printing each of them.  */
752   cf->count = 0;
753   for (fd = cf->plist; fd != NULL; fd = fd->next) {
754     cf->count++;
755
756     wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
757
758     /* create the logical protocol tree */
759     protocol_tree = proto_tree_create_root();
760     dissect_packet(cf->pd, fd, protocol_tree);
761
762     /* Print the packet */
763     proto_tree_print(cf->count, (GNode *)protocol_tree, cf->pd, fd, cf->print_fh);
764
765     proto_tree_free(protocol_tree);
766   }
767
768 #if 0
769   print_finale(cf->print_fh);
770 #endif
771
772   close_print_dest(to_file, cf->print_fh);
773   cf->print_fh = NULL;
774   return TRUE;
775 }
776
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. */
780 void
781 change_time_formats(capture_file *cf)
782 {
783   frame_data *fd;
784   int i;
785   GtkStyle  *pl_style;
786
787   /* Freeze the packet list while we redo it, so we don't get any
788      screen updates while it happens. */
789   freeze_clist(cf);
790
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) {
796     if (fd->row != -1) {
797       /* This packet is in the summary list, on row "fd->row". */
798
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';
809         }
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]);
817           }
818         }
819       }
820     }
821   }
822
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));
830     }
831   }
832
833   /* Unfreeze the packet list. */
834   thaw_clist(cf);
835 }
836
837 static void
838 clear_tree_and_hex_views(void)
839 {
840   GList *selection;
841   GtkWidget *tmp_item;
842
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));
849
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()
853    */
854   if (GTK_TREE(tree_view)->root_tree) {
855           selection = GTK_TREE(tree_view)->root_tree->selection;
856           while (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;
861           }
862           g_list_free(GTK_TREE(tree_view)->root_tree->selection);
863           GTK_TREE(tree_view)->root_tree->selection = NULL;
864   }
865
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);
869 }
870
871
872 /* Select the packet on a given row. */
873 void
874 select_packet(capture_file *cf, int row)
875 {
876   frame_data *fd;
877   int i;
878
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)));
884
885   /* Search through the list of frames to see which one is in
886      this row. */
887   for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
888     if (fd->row == row)
889       break;
890   }
891   cf->fd = fd;
892
893   /* Remember the ordinal number of that frame. */
894   cf->selected_packet = i;
895
896   /* Get the data in that frame. */
897   wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
898
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);
905
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));
911
912   /* A packet is selected, so "File/Print Packet" has something to print. */
913   set_menu_sensitivity("/File/Print Packet", TRUE);
914 }
915
916 /* Unselect the selected packet, if any. */
917 void
918 unselect_packet(capture_file *cf)
919 {
920   cf->selected_packet = -1;     /* nothing there to be selected */
921   cf->selected_row = -1;
922
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;
927   }
928
929   /* Clear out the display of that packet. */
930   clear_tree_and_hex_views();
931
932   /* No packet is selected, so "File/Print Packet" has nothing to print. */
933   set_menu_sensitivity("/File/Print Packet", FALSE);
934 }
935
936 static void
937 freeze_clist(capture_file *cf)
938 {
939   int i;
940
941   /* Make the column sizes static, so they don't adjust while
942      we're reading the capture file (freezing the clist doesn't
943      seem to suffice). */
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));
947 }
948
949 static void
950 thaw_clist(capture_file *cf)
951 {
952   int i;
953
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]);
959     } else {
960       /* Make this column's size dynamic, so that it adjusts to the
961          appropriate size. */
962       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
963     }
964   }
965   gtk_clist_thaw(GTK_CLIST(packet_list));
966
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);
972 }
973
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
976  */
977 int
978 file_mv(char *from, char *to)
979 {
980
981 #define COPY_BUFFER_SIZE        8192
982
983         int retval;
984
985 #ifndef WIN32
986         /* try a hard link */
987         retval = link(from, to);
988
989         /* or try a copy */
990         if (retval < 0) {
991 #endif
992                 retval = file_cp(from, to);
993                 if (!retval) {
994                         return 0;
995                 }
996 #ifndef WIN32
997         }
998 #endif
999
1000         unlink(from);
1001         return 1;
1002 }
1003
1004 /* Copies a file.
1005  * Returns 0 on failure to do either, 1 on success of either
1006  */
1007 int
1008 file_cp(char *from, char *to)
1009 {
1010
1011 #define COPY_BUFFER_SIZE        8192
1012
1013         int from_fd, to_fd, nread, nwritten;
1014         char *buffer;
1015
1016         buffer = g_malloc(COPY_BUFFER_SIZE);
1017
1018         from_fd = open(from, O_RDONLY);
1019         if (from_fd < 0) {
1020                 simple_dialog(ESD_TYPE_WARN, NULL,
1021                         file_open_error_message(errno, TRUE), from);
1022                 return 0;
1023         }
1024
1025         to_fd = creat(to, 0644);
1026         if (to_fd < 0) {
1027                 simple_dialog(ESD_TYPE_WARN, NULL,
1028                         file_open_error_message(errno, TRUE), to);
1029                 close(from_fd);
1030                 return 0;
1031         }
1032
1033         while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
1034                 nwritten = write(to_fd, buffer, nread);
1035                 if (nwritten < nread) {
1036                         if (nwritten < 0) {
1037                                 simple_dialog(ESD_TYPE_WARN, NULL,
1038                                         file_write_error_message(errno), to);
1039                         } else {
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);
1043                         }
1044                         close(from_fd);
1045                         close(to_fd);
1046                         return 0;
1047                 }
1048         }
1049         if (nread < 0) {
1050                 simple_dialog(ESD_TYPE_WARN, NULL,
1051                         file_read_error_message(errno), from);
1052                 close(from_fd);
1053                 close(to_fd);
1054                 return 0;
1055         }
1056         close(from_fd);
1057         close(to_fd);
1058
1059         return 1;
1060 }
1061
1062 char *
1063 file_open_error_message(int err, int for_writing)
1064 {
1065   char *errmsg;
1066   static char errmsg_errno[1024+1];
1067
1068   switch (err) {
1069
1070   case WTAP_ERR_NOT_REGULAR_FILE:
1071     errmsg = "The file \"%s\" is invalid.";
1072     break;
1073
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.";
1077     break;
1078
1079   case WTAP_ERR_BAD_RECORD:
1080     errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1081     break;
1082
1083   case WTAP_ERR_CANT_OPEN:
1084     if (for_writing)
1085       errmsg = "The file \"%s\" could not be created for some unknown reason.";
1086     else
1087       errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1088     break;
1089
1090   case WTAP_ERR_SHORT_READ:
1091     errmsg = "The file \"%s\" appears to have been cut short"
1092              " in the middle of a packet.";
1093     break;
1094
1095   case ENOENT:
1096     if (for_writing)
1097       errmsg = "The path to the file \"%s\" does not exist.";
1098     else
1099       errmsg = "The file \"%s\" does not exist.";
1100     break;
1101
1102   case EACCES:
1103     if (for_writing)
1104       errmsg = "You do not have permission to create or write to the file \"%s\".";
1105     else
1106       errmsg = "You do not have permission to read the file \"%s\".";
1107     break;
1108
1109   default:
1110     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1111                                 wtap_strerror(err));
1112     errmsg = errmsg_errno;
1113     break;
1114   }
1115   return errmsg;
1116 }
1117
1118 char *
1119 file_read_error_message(int err)
1120 {
1121   static char errmsg_errno[1024+1];
1122
1123   sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
1124                                 wtap_strerror(err));
1125   return errmsg_errno;
1126 }
1127
1128 char *
1129 file_write_error_message(int err)
1130 {
1131   char *errmsg;
1132   static char errmsg_errno[1024+1];
1133
1134   switch (err) {
1135
1136   case ENOSPC:
1137     errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1138     break;
1139
1140 #ifdef EDQUOT
1141   case EDQUOT:
1142     errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1143     break;
1144 #endif
1145
1146   default:
1147     sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
1148                                 wtap_strerror(err));
1149     errmsg = errmsg_errno;
1150     break;
1151   }
1152   return errmsg;
1153 }