Oops, forgot to get rid of the "open_cap_file()" in "load_cap_file()"
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id: file.c,v 1.69 1999/08/15 00:55:22 guy 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 #ifdef HAVE_IO_H
39 #include <io.h>
40 #endif
41
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/stat.h>
45 #include <errno.h>
46 #include <fcntl.h>
47
48 #ifdef NEED_SNPRINTF_H
49 # ifdef HAVE_STDARG_H
50 #  include <stdarg.h>
51 # else
52 #  include <varargs.h>
53 # endif
54 # include "snprintf.h"
55 #endif
56
57 #ifdef NEED_STRERROR_H
58 #include "strerror.h"
59 #endif
60
61 #ifdef HAVE_SYS_TYPES_H
62 # include <sys/types.h>
63 #endif
64
65 #ifdef HAVE_NETINET_IN_H
66 # include <netinet/in.h>
67 #endif
68
69 #include "ethereal.h"
70 #include "column.h"
71 #include "menu.h"
72 #include "packet.h"
73 #include "print.h"
74 #include "file.h"
75 #include "util.h"
76 #include "gtkpacket.h"
77 #include "dfilter.h"
78 #include "timestamp.h"
79
80 #include "packet-ncp.h"
81
82 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
83 extern guint      file_ctx;
84 extern int        sync_mode;
85 extern int        sync_pipe[];
86
87 guint cap_input_id;
88
89 static guint32 firstsec, firstusec;
90 static guint32 prevsec, prevusec;
91
92 static dfilter *rfcode = NULL; 
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 static gint dfilter_progress_cb(gpointer p);
101
102 int
103 open_cap_file(char *fname, capture_file *cf) {
104   struct stat cf_stat;
105   FILE       *fh;
106   wtap       *wth;
107   int        err;
108
109   /* First, make sure the file is valid */
110   if (stat(fname, &cf_stat)) {
111     err = errno;
112     goto fail;
113   }
114 #ifndef WIN32
115   if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode)) {
116     err = OPEN_CAP_FILE_NOT_REGULAR;
117     goto fail;
118   }
119 #endif
120
121   /* Next, try to open the file.
122      XXX - we only need to do this because "wtap_open_offline()"
123      doesn't return an indication of whether the open failed because
124      we don't have access to the file, or because it's not a valid
125      capture file, so we first have to open it with "fopen()" to
126      make sure we have access to it as a boring ordinary file. */
127   fh = fopen(fname, "r");
128   if (fh == NULL) {
129     err = errno;
130     goto fail;
131   }
132   fclose(fh);
133
134   /* Next, try to open it as a wiretap capture file. */
135   wth = wtap_open_offline(fname);
136   if (wth == NULL) {
137     /* XXX - we assume that, because we were able to open it above,
138        this must have failed because it's not a capture file in
139        a format we can read. */
140     err = OPEN_CAP_FILE_UNKNOWN_FORMAT;
141     goto fail;
142   }
143
144   /* The open succeeded.  Close whatever capture file we had open,
145      and fill in the information for this file. */
146   close_cap_file(cf, info_bar, file_ctx);
147
148   /* Initialize protocol-specific variables */
149   ncp_init_protocol();
150
151   cf->wth = wth;
152   cf->fh = wtap_file(cf->wth);
153   cf->f_len = cf_stat.st_size;
154
155   /* set the file name because we need it to set the follow stream filter */
156   cf->filename = g_strdup(fname);
157
158   cf->cd_t      = wtap_file_type(cf->wth);
159   cf->cd_t_desc = wtap_file_type_string(cf->wth);
160   cf->count     = 0;
161   cf->drops     = 0;
162   cf->esec      = 0;
163   cf->eusec     = 0;
164   cf->snap      = wtap_snapshot_length(cf->wth);
165   firstsec = 0, firstusec = 0;
166   prevsec = 0, prevusec = 0;
167  
168   return (0);
169
170 fail:
171   simple_dialog(ESD_TYPE_WARN, NULL,
172                         file_open_error_message(err, FALSE), fname);
173   return (err);
174 }
175
176 /* Reset everything to a pristine state */
177 void
178 close_cap_file(capture_file *cf, void *w, guint context) {
179   frame_data *fd, *fd_next;
180
181   if (cf->fh) {
182     fclose(cf->fh);
183     cf->fh = NULL;
184   }
185   if (cf->wth) {
186     wtap_close(cf->wth);
187     cf->wth = NULL;
188   }
189   for (fd = cf->plist; fd != NULL; fd = fd_next) {
190     fd_next = fd->next;
191     g_free(fd);
192   }
193   cf->plist = NULL;
194   cf->plist_end = NULL;
195   unselect_packet(cf);  /* nothing to select */
196
197   gtk_clist_freeze(GTK_CLIST(packet_list));
198   gtk_clist_clear(GTK_CLIST(packet_list));
199   gtk_clist_thaw(GTK_CLIST(packet_list));
200   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
201
202   /* Disable all menu items that make sense only if you have a capture. */
203   set_menu_sensitivity("/File/Save", FALSE);
204   set_menu_sensitivity("/File/Save As...", FALSE);
205   set_menu_sensitivity("/File/Close", FALSE);
206   set_menu_sensitivity("/File/Reload", FALSE);
207   set_menu_sensitivity("/File/Print...", FALSE);
208   set_menu_sensitivity("/Display/Options...", FALSE);
209   set_menu_sensitivity("/Tools/Summary", FALSE);
210 }
211
212 int
213 read_cap_file(char *fname, char *rfilter, capture_file *cf) {
214   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
215   gchar  *done_fmt = " File: %s  Drops: %d";
216   gchar  *err_fmt  = " Error: Could not load '%s'";
217   gint    timeout;
218   size_t  msg_len;
219
220   if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
221     name_ptr = fname;
222   else
223     name_ptr++;
224
225   if (rfilter) {
226     rfcode = dfilter_new();
227     if (dfilter_compile(rfcode, rfilter) != 0) {
228       simple_dialog(ESD_TYPE_WARN, NULL,
229         "Unable to parse filter string \"%s\".", rfilter);
230       goto fail;
231     }
232   }
233
234   load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
235   sprintf(load_msg, load_fmt, name_ptr);
236   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
237   
238   timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) cf);
239
240   freeze_clist(cf);
241   wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);
242   wtap_close(cf->wth);
243   cf->wth = NULL;
244   cf->fh = fopen(fname, "r");
245   thaw_clist(cf);
246   
247   gtk_timeout_remove(timeout);
248   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
249
250   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
251
252   msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
253   load_msg = g_realloc(load_msg, msg_len);
254
255   if (cf->user_saved || !cf->save_file)
256     snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
257   else
258     snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
259
260   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
261   g_free(load_msg);
262
263 /*  name_ptr[-1] = '\0';  Why is this here? It causes problems with capture files */
264
265   /* Remember the new read filter string. */
266   if (cf->rfilter != NULL)
267     g_free(cf->rfilter);
268   cf->rfilter = rfilter;
269
270   /* Enable menu items that make sense if you have a capture. */
271   set_menu_sensitivity("/File/Close", TRUE);
272   set_menu_sensitivity("/File/Reload", TRUE);
273   set_menu_sensitivity("/File/Print...", TRUE);
274   set_menu_sensitivity("/Display/Options...", TRUE);
275   set_menu_sensitivity("/Tools/Summary", TRUE);
276   return 0;
277
278 fail:
279   msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
280   load_msg = g_malloc(msg_len);
281   snprintf(load_msg, msg_len, err_fmt, name_ptr);
282   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
283   g_free(load_msg);
284   if (rfilter != NULL)
285     g_free(rfilter);    /* assumed to be "g_strdup()"ed, if not null */
286   return -1;
287 }
288
289 #ifdef HAVE_LIBPCAP
290 void 
291 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
292   
293   capture_file *cf = (capture_file *)data;
294   char buffer[256], *p = buffer, *q = buffer;
295   int  nread;
296   int  to_read = 0;
297   gboolean exit_loop = FALSE;
298
299   /* avoid reentrancy problems and stack overflow */
300   gtk_input_remove(cap_input_id);
301
302   if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
303
304     /* The child has closed the sync pipe, meaning it's not going to be
305        capturing any more packets.  Read what remains of the capture file,
306        and stop capture (restore menu items) */
307     gtk_clist_freeze(GTK_CLIST(packet_list));
308
309     wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
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   wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf);      
350   gtk_clist_thaw(GTK_CLIST(packet_list));
351
352   /* restore pipe handler */
353   cap_input_id = gtk_input_add_full (sync_pipe[0],
354                                      GDK_INPUT_READ,
355                                      cap_file_input_cb,
356                                      NULL,
357                                      (gpointer) cf,
358                                      NULL);
359 }
360
361 int
362 tail_cap_file(char *fname, capture_file *cf) {
363   int     err;
364   int     i;
365
366   err = open_cap_file(fname, cf);
367   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
368
369     set_menu_sensitivity("/File/Open...", FALSE);
370     set_menu_sensitivity("/Display/Options...", TRUE);
371 #ifdef HAVE_LIBPCAP
372     set_menu_sensitivity("/Capture/Start...", FALSE);
373 #endif
374
375     for (i = 0; i < cf->cinfo.num_cols; i++) {
376       if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
377         gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
378       else {
379         gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
380         gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
381                                 cf->cinfo.col_width[i]);
382         gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
383       }
384     }
385
386     cf->fh = fopen(fname, "r");
387
388     cap_input_id = gtk_input_add_full (sync_pipe[0],
389                                        GDK_INPUT_READ,
390                                        cap_file_input_cb,
391                                        NULL,
392                                        (gpointer) cf,
393                                        NULL);
394     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, 
395                        " <live capture in progress>");
396   }
397   else {
398     close(sync_pipe[0]);
399   }
400   return err;
401 }
402 #endif
403
404 /* To do: Add check_col checks to the col_add* routines */
405
406 static void
407 col_add_abs_time(frame_data *fd, gint el)
408 {
409   struct tm *tmp;
410   time_t then;
411
412   then = fd->abs_secs;
413   tmp = localtime(&then);
414   col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
415     tmp->tm_hour,
416     tmp->tm_min,
417     tmp->tm_sec,
418     (long)fd->abs_usecs/100);
419 }
420
421 static void
422 col_add_rel_time(frame_data *fd, gint el)
423 {
424   col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
425 }
426
427 static void
428 col_add_delta_time(frame_data *fd, gint el)
429 {
430   col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
431 }
432
433 /* Add "command-line-specified" time. */
434 static void
435 col_add_cls_time(frame_data *fd)
436 {
437   switch (timestamp_type) {
438     case ABSOLUTE:
439       col_add_abs_time(fd, COL_CLS_TIME);
440       break;
441
442     case RELATIVE:
443       col_add_rel_time(fd, COL_CLS_TIME);
444       break;
445
446     case DELTA:
447       col_add_delta_time(fd, COL_CLS_TIME);
448       break;
449   }
450 }
451
452 static void
453 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
454 {
455   gint          i, row;
456   proto_tree   *protocol_tree;
457
458   /* If we don't have the time stamp of the first packet in the
459      capture, it's because this is the first packet.  Save the time
460      stamp of this packet as the time stamp of the first packet. */
461   if (!firstsec && !firstusec) {
462     firstsec  = fdata->abs_secs;
463     firstusec = fdata->abs_usecs;
464   }
465
466   /* Get the time elapsed between the first packet and this packet. */
467   cf->esec = fdata->abs_secs - firstsec;
468   if (firstusec <= fdata->abs_usecs) {
469     cf->eusec = fdata->abs_usecs - firstusec;
470   } else {
471     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
472     cf->esec--;
473   }
474
475   fdata->cinfo = &cf->cinfo;
476   for (i = 0; i < fdata->cinfo->num_cols; i++) {
477     fdata->cinfo->col_data[i][0] = '\0';
478   }
479
480   /* Apply the display filter */
481   if (DFILTER_CONTAINS_FILTER(cf->dfcode)) {
482         protocol_tree = proto_tree_create_root();
483         dissect_packet(buf, fdata, protocol_tree);
484         fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
485         proto_tree_free(protocol_tree);
486   }
487   else {
488         dissect_packet(buf, fdata, NULL);
489         fdata->passed_dfilter = TRUE;
490   }
491   if (fdata->passed_dfilter) {
492     if (check_col(fdata, COL_NUMBER))
493       col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
494
495     /* If we don't have the time stamp of the previous displayed packet,
496        it's because this is the first displayed packet.  Save the time
497        stamp of this packet as the time stamp of the previous displayed
498        packet. */
499     if (!prevsec && !prevusec) {
500       prevsec  = fdata->abs_secs;
501       prevusec = fdata->abs_usecs;
502     }
503
504     /* Get the time elapsed between the first packet and this packet. */
505     fdata->rel_secs = cf->esec;
506     fdata->rel_usecs = cf->eusec;
507   
508     /* Get the time elapsed between the previous displayed packet and
509        this packet. */
510     fdata->del_secs = fdata->abs_secs - prevsec;
511     if (prevusec <= fdata->abs_usecs) {
512       fdata->del_usecs = fdata->abs_usecs - prevusec;
513     } else {
514       fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
515       fdata->del_secs--;
516     }
517     prevsec = fdata->abs_secs;
518     prevusec = fdata->abs_usecs;
519
520     /* Set any time stamp columns. */
521     if (check_col(fdata, COL_CLS_TIME))
522       col_add_cls_time(fdata);
523     if (check_col(fdata, COL_ABS_TIME))
524       col_add_abs_time(fdata, COL_ABS_TIME);
525     if (check_col(fdata, COL_REL_TIME))
526       col_add_rel_time(fdata, COL_REL_TIME);
527     if (check_col(fdata, COL_DELTA_TIME))
528       col_add_delta_time(fdata, COL_DELTA_TIME);
529
530     if (check_col(fdata, COL_PACKET_LENGTH))
531       col_add_fstr(fdata, COL_PACKET_LENGTH, "%d", fdata->pkt_len);
532
533     row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
534     fdata->row = row;
535
536     /* If this was the selected packet, remember the row it's in, so
537        we can re-select it.  ("selected_packet" is 0-origin, as it's
538        a GList index; "count", however, is 1-origin.) */
539     if (cf->selected_packet == cf->count - 1)
540       cf->selected_row = row;
541   } else
542     fdata->row = -1;    /* not in the display */
543   fdata->cinfo = NULL;
544 }
545
546 static void
547 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
548   const u_char *buf) {
549   frame_data   *fdata;
550   capture_file *cf = (capture_file *) user;
551   int           passed;
552   proto_tree   *protocol_tree;
553   frame_data   *plist_end;
554
555   while (gtk_events_pending())
556     gtk_main_iteration();
557
558   /* Allocate the next list entry, and add it to the list. */
559   fdata = (frame_data *) g_malloc(sizeof(frame_data));
560
561   fdata->next = NULL;
562   fdata->pkt_len  = phdr->len;
563   fdata->cap_len  = phdr->caplen;
564   fdata->file_off = offset;
565   fdata->lnk_t = phdr->pkt_encap;
566   fdata->abs_secs  = phdr->ts.tv_sec;
567   fdata->abs_usecs = phdr->ts.tv_usec;
568   fdata->flags = phdr->flags;
569   fdata->cinfo = NULL;
570
571   passed = TRUE;
572   if (rfcode) {
573           if (DFILTER_CONTAINS_FILTER(rfcode)) {
574             protocol_tree = proto_tree_create_root();
575             dissect_packet(buf, fdata, protocol_tree);
576             passed = dfilter_apply(rfcode, protocol_tree, cf->pd);
577             proto_tree_free(protocol_tree);
578           }
579   }   
580   if (passed) {
581     plist_end = cf->plist_end;
582     if (plist_end != NULL)
583       plist_end->next = fdata;
584     else
585       cf->plist = fdata;
586     cf->plist_end = fdata;
587
588     cf->count++;
589     add_packet_to_packet_list(fdata, cf, buf);
590   } else
591     g_free(fdata);
592 }
593
594 void
595 filter_packets(capture_file *cf)
596 {
597 /*  gint timeout;*/
598   frame_data *fd;
599
600   if (cf->dfilter == NULL) {
601         dfilter_clear_filter(cf->dfcode);
602   }
603   else {
604     /*
605      * Compile the filter.
606      */
607     if (dfilter_compile(cf->dfcode, cf->dfilter) != 0) {
608       simple_dialog(ESD_TYPE_WARN, NULL,
609       "Unable to parse filter string \"%s\".", cf->dfilter);
610       return;
611     }
612   }
613
614   /* Freeze the packet list while we redo it, so we don't get any
615      screen updates while it happens. */
616   gtk_clist_freeze(GTK_CLIST(packet_list));
617
618   /* Clear it out. */
619   gtk_clist_clear(GTK_CLIST(packet_list));
620
621   /* If a packet was selected, we don't know yet what row, if any, it'll
622      get. */
623   cf->selected_row = -1;
624
625   /* Iterate through the list of packets, calling a routine
626      to run the filter on the packet, see if it matches, and
627      put it in the display list if so.  */
628   firstsec = 0;
629   firstusec = 0;
630   prevsec = 0;
631   prevusec = 0;
632   cf->unfiltered_count = cf->count;
633   cf->count = 0;
634
635 /*  timeout = gtk_timeout_add(250, dfilter_progress_cb, cf);*/
636   for (fd = cf->plist; fd != NULL; fd = fd->next) {
637     cf->count++;
638
639     fseek(cf->fh, fd->file_off, SEEK_SET);
640     fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh);
641
642     add_packet_to_packet_list(fd, cf, cf->pd);
643
644     if (cf->count % 20 == 0) {
645       dfilter_progress_cb(cf);
646     }
647   }
648 /*  gtk_timeout_remove(timeout);*/
649  
650   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
651
652   if (cf->selected_row != -1) {
653     /* We had a selected packet and it passed the filter. */
654     gtk_clist_select_row(GTK_CLIST(packet_list), cf->selected_row, -1);
655   } else {
656     /* If we had one, it didn't pass the filter. */
657     unselect_packet(cf);
658   }
659
660   /* Unfreeze the packet list. */
661   gtk_clist_thaw(GTK_CLIST(packet_list));
662 }
663
664 /* Update the progress bar */
665 static gint
666 dfilter_progress_cb(gpointer p) {
667   capture_file *cf = (capture_file*)p;
668
669   /* let's not divide by zero. I should never be started
670    * with unfiltered_count == 0, so let's assert that
671    */
672   g_assert(cf->unfiltered_count > 0);
673
674   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
675     (gfloat) cf->count / cf->unfiltered_count);
676
677   /* Have GTK+ repaint what is pending */
678   while (gtk_events_pending ()) {
679           gtk_main_iteration();
680   }
681   return TRUE;
682 }
683
684
685 int
686 print_packets(capture_file *cf, int to_file, const char *dest)
687 {
688   frame_data *fd;
689   proto_tree *protocol_tree;
690
691   cf->print_fh = open_print_dest(to_file, dest);
692   if (cf->print_fh == NULL)
693     return FALSE;       /* attempt to open destination failed */
694
695   /* XXX - printing multiple frames in PostScript looks as if it's
696      tricky - you have to deal with page boundaries, I think -
697      and I'll have to spend some time learning enough about
698      PostScript to figure it out, so, for now, we only print
699      multiple frames as text. */
700 #if 0
701   print_preamble(cf->print_fh);
702 #endif
703
704   /* Iterate through the list of packets, printing each of them.  */
705   cf->count = 0;
706   for (fd = cf->plist; fd != NULL; fd = fd->next) {
707     cf->count++;
708
709     fseek(cf->fh, fd->file_off, SEEK_SET);
710     fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh);
711
712     /* create the logical protocol tree */
713     protocol_tree = proto_tree_create_root();
714     dissect_packet(cf->pd, fd, protocol_tree);
715
716     /* Print the packet */
717     proto_tree_print(cf->count, (GNode *)protocol_tree, cf->pd, fd, cf->print_fh);
718
719     proto_tree_free(protocol_tree);
720   }
721
722 #if 0
723   print_finale(cf->print_fh);
724 #endif
725
726   close_print_dest(to_file, cf->print_fh);
727   cf->print_fh = NULL;
728   return TRUE;
729 }
730
731 /* Scan through the packet list and change all columns that use the
732    "command-line-specified" time stamp format to use the current
733    value of that format. */
734 void
735 change_time_formats(capture_file *cf)
736 {
737   frame_data *fd;
738   int i;
739   GtkStyle  *pl_style;
740
741   /* Freeze the packet list while we redo it, so we don't get any
742      screen updates while it happens. */
743   freeze_clist(cf);
744
745   /* Iterate through the list of packets, checking whether the packet
746      is in a row of the summary list and, if so, whether there are
747      any columns that show the time in the "command-line-specified"
748      format and, if so, update that row. */
749   for (fd = cf->plist; fd != NULL; fd = fd->next) {
750     if (fd->row != -1) {
751       /* This packet is in the summary list, on row "fd->row". */
752
753       /* XXX - there really should be a way of checking "cf->cinfo" for this;
754          the answer isn't going to change from packet to packet, so we should
755          simply skip all the "change_time_formats()" work if we're not
756          changing anything. */
757       fd->cinfo = &cf->cinfo;
758       if (check_col(fd, COL_CLS_TIME)) {
759         /* There are columns that show the time in the "command-line-specified"
760            format; update them. */
761         for (i = 0; i < cf->cinfo.num_cols; i++) {
762           cf->cinfo.col_data[i][0] = '\0';
763         }
764         col_add_cls_time(fd);
765         for (i = 0; i < cf->cinfo.num_cols; i++) {
766           if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
767             /* This is one of the columns that shows the time in
768                "command-line-specified" format; update it. */
769             gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
770                           cf->cinfo.col_data[i]);
771           }
772         }
773       }
774     }
775   }
776
777   /* Set the column widths of those columns that show the time in
778      "command-line-specified" format. */
779   pl_style = gtk_widget_get_style(packet_list);
780   for (i = 0; i < cf->cinfo.num_cols; i++) {
781     if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
782       gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
783         get_column_width(COL_CLS_TIME, pl_style->font));
784     }
785   }
786
787   /* Unfreeze the packet list. */
788   thaw_clist(cf);
789 }
790
791 static void
792 clear_tree_and_hex_views(void)
793 {
794   /* Clear the hex dump. */
795   gtk_text_freeze(GTK_TEXT(byte_view));
796   gtk_text_set_point(GTK_TEXT(byte_view), 0);
797   gtk_text_forward_delete(GTK_TEXT(byte_view),
798     gtk_text_get_length(GTK_TEXT(byte_view)));
799   gtk_text_thaw(GTK_TEXT(byte_view));
800
801   /* Clear the protocol tree view. */
802   gtk_tree_clear_items(GTK_TREE(tree_view), 0,
803     g_list_length(GTK_TREE(tree_view)->children));
804 }
805
806 /* Select the packet on a given row. */
807 void
808 select_packet(capture_file *cf, int row)
809 {
810   frame_data *fd;
811   int i;
812
813   /* Clear out whatever's currently in the hex dump. */
814   gtk_text_freeze(GTK_TEXT(byte_view));
815   gtk_text_set_point(GTK_TEXT(byte_view), 0);
816   gtk_text_forward_delete(GTK_TEXT(byte_view),
817     gtk_text_get_length(GTK_TEXT(byte_view)));
818
819   /* Search through the list of frames to see which one is in
820      this row. */
821   for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
822     if (fd->row == row)
823       break;
824   }
825   cf->fd = fd;
826
827   /* Remember the ordinal number of that frame. */
828   cf->selected_packet = i;
829
830   /* Get the data in that frame. */
831   fseek(cf->fh, cf->fd->file_off, SEEK_SET);
832   fread(cf->pd, sizeof(guint8), cf->fd->cap_len, cf->fh);
833
834   /* Create the logical protocol tree. */
835   if (cf->protocol_tree)
836       proto_tree_free(cf->protocol_tree);
837   cf->protocol_tree = proto_tree_create_root();
838   dissect_packet(cf->pd, cf->fd, cf->protocol_tree);
839
840   /* Display the GUI protocol tree and hex dump. */
841   clear_tree_and_hex_views();
842   proto_tree_draw(cf->protocol_tree, tree_view);
843   packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->fd->cap_len, -1, -1);
844   gtk_text_thaw(GTK_TEXT(byte_view));
845
846   /* A packet is selected, so "File/Print Packet" has something to print. */
847   set_menu_sensitivity("/File/Print Packet", TRUE);
848 }
849
850 /* Unselect the selected packet, if any. */
851 void
852 unselect_packet(capture_file *cf)
853 {
854   cf->selected_packet = -1;     /* nothing there to be selected */
855   cf->selected_row = -1;
856
857   /* Destroy the protocol tree for that packet. */
858   if (cf->protocol_tree != NULL) {
859     proto_tree_free(cf->protocol_tree);
860     cf->protocol_tree = NULL;
861   }
862
863   /* Clear out the display of that packet. */
864   clear_tree_and_hex_views();
865
866   /* No packet is selected, so "File/Print Packet" has nothing to print. */
867   set_menu_sensitivity("/File/Print Packet", FALSE);
868 }
869
870 static void
871 freeze_clist(capture_file *cf)
872 {
873   int i;
874
875   /* Make the column sizes static, so they don't adjust while
876      we're reading the capture file (freezing the clist doesn't
877      seem to suffice). */
878   for (i = 0; i < cf->cinfo.num_cols; i++)
879     gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
880   gtk_clist_freeze(GTK_CLIST(packet_list));
881 }
882
883 static void
884 thaw_clist(capture_file *cf)
885 {
886   int i;
887
888   for (i = 0; i < cf->cinfo.num_cols; i++) {
889     if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
890       /* Set this column's width to the appropriate value. */
891       gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
892                                 cf->cinfo.col_width[i]);
893     } else {
894       /* Make this column's size dynamic, so that it adjusts to the
895          appropriate size. */
896       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
897     }
898   }
899   gtk_clist_thaw(GTK_CLIST(packet_list));
900
901   /* Hopefully, the columns have now gotten their appropriate sizes;
902      make them resizeable - a column that auto-resizes cannot be
903      resized by the user, and *vice versa*. */
904   for (i = 0; i < cf->cinfo.num_cols; i++)
905     gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
906 }
907
908 /* Tries to mv a file. If unsuccessful, tries to cp the file.
909  * Returns 0 on failure to do either, 1 on success of either
910  */
911 int
912 file_mv(char *from, char *to)
913 {
914
915 #define COPY_BUFFER_SIZE        8192
916
917         int retval;
918
919 #ifndef WIN32
920         /* try a hard link */
921         retval = link(from, to);
922
923         /* or try a copy */
924         if (retval < 0) {
925 #endif
926                 retval = file_cp(from, to);
927                 if (!retval) {
928                         return 0;
929                 }
930 #ifndef WIN32
931         }
932 #endif
933
934         unlink(from);
935         return 1;
936 }
937
938 /* Copies a file.
939  * Returns 0 on failure to do either, 1 on success of either
940  */
941 int
942 file_cp(char *from, char *to)
943 {
944
945 #define COPY_BUFFER_SIZE        8192
946
947         int from_fd, to_fd, nread, nwritten;
948         char *buffer;
949
950         buffer = g_malloc(COPY_BUFFER_SIZE);
951
952         from_fd = open(from, O_RDONLY);
953         if (from_fd < 0) {
954                 simple_dialog(ESD_TYPE_WARN, NULL,
955                         file_open_error_message(errno, TRUE), from);
956                 return 0;
957         }
958
959         to_fd = creat(to, 0644);
960         if (to_fd < 0) {
961                 simple_dialog(ESD_TYPE_WARN, NULL,
962                         file_open_error_message(errno, TRUE), to);
963                 close(from_fd);
964                 return 0;
965         }
966
967         while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
968                 nwritten = write(to_fd, buffer, nread);
969                 if (nwritten < nread) {
970                         if (nwritten < 0) {
971                                 simple_dialog(ESD_TYPE_WARN, NULL,
972                                         file_write_error_message(errno), to);
973                         } else {
974                                 simple_dialog(ESD_TYPE_WARN, NULL,
975 "The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
976                                         to, nread, nwritten);
977                         }
978                         close(from_fd);
979                         close(to_fd);
980                         return 0;
981                 }
982         }
983         if (nread < 0) {
984                 simple_dialog(ESD_TYPE_WARN, NULL,
985                         file_read_error_message(errno), from);
986                 close(from_fd);
987                 close(to_fd);
988                 return 0;
989         }
990         close(from_fd);
991         close(to_fd);
992
993         return 1;
994 }
995
996 char *
997 file_open_error_message(int err, int for_writing)
998 {
999   char *errmsg;
1000   static char errmsg_errno[1024+1];
1001
1002   switch (err) {
1003
1004   case OPEN_CAP_FILE_NOT_REGULAR:
1005     errmsg = "The file \"%s\" is invalid.";
1006     break;
1007
1008   case OPEN_CAP_FILE_UNKNOWN_FORMAT:
1009     errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
1010     break;
1011
1012   case ENOENT:
1013     if (for_writing)
1014       errmsg = "The path to the file \"%s\" does not exist.";
1015     else
1016       errmsg = "The file \"%s\" does not exist.";
1017     break;
1018
1019   case EACCES:
1020     if (for_writing)
1021       errmsg = "You do not have permission to create or write to the file \"%s\".";
1022     else
1023       errmsg = "You do not have permission to open the file \"%s\".";
1024     break;
1025
1026   default:
1027     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.", strerror(err));
1028     errmsg = errmsg_errno;
1029     break;
1030   }
1031   return errmsg;
1032 }
1033
1034 char *
1035 file_read_error_message(int err)
1036 {
1037   static char errmsg_errno[1024+1];
1038
1039   sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.", strerror(err));
1040   return errmsg_errno;
1041 }
1042
1043 char *
1044 file_write_error_message(int err)
1045 {
1046   char *errmsg;
1047   static char errmsg_errno[1024+1];
1048
1049   switch (err) {
1050
1051   case ENOSPC:
1052     errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1053     break;
1054
1055 #ifdef EDQUOT
1056   case EDQUOT:
1057     errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1058     break;
1059 #endif
1060
1061   default:
1062     sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.", strerror(err));
1063     errmsg = errmsg_errno;
1064     break;
1065   }
1066   return errmsg;
1067 }