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