Added Aaron Hillegass' summary dialogue. We're ignoring the problem with
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id: file.c,v 1.33 1999/06/22 22:02:11 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 #ifdef WITH_WIRETAP
33 #include <pcap.h>
34 #endif
35
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <errno.h>
41 #include <fcntl.h>
42
43 #ifdef NEED_SNPRINTF_H
44 # ifdef HAVE_STDARG_H
45 #  include <stdarg.h>
46 # else
47 #  include <varargs.h>
48 # endif
49 # include "snprintf.h"
50 #endif
51
52 #ifdef NEED_STRERROR_H
53 #include "strerror.h"
54 #endif
55
56 #ifdef HAVE_SYS_TYPES_H
57 # include <sys/types.h>
58 #endif
59
60 #ifdef HAVE_NETINET_IN_H
61 # include <netinet/in.h>
62 #endif
63
64 #include "ethereal.h"
65 #include "column.h"
66 #include "menu.h"
67 #include "packet.h"
68 #include "file.h"
69 #include "util.h"
70
71 #include "packet-ncp.h"
72
73 #define TAIL_TIMEOUT    2000  /* msec */
74
75 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
76 extern GtkStyle  *pl_style;
77 extern guint      file_ctx;
78 extern int        sync_mode;
79 extern int        sync_pipe[];
80
81 guint cap_input_id, tail_timeout_id;
82
83 static guint32 firstsec, firstusec;
84 static guint32 lastsec, lastusec;
85
86 #ifdef WITH_WIRETAP
87 static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
88     const u_char *);
89 #else
90 static void pcap_dispatch_cb(u_char *, const struct pcap_pkthdr *,
91     const u_char *);
92 #endif
93
94 static void init_col_widths(capture_file *);
95 static void set_col_widths(capture_file *);
96
97 static gint tail_timeout_cb(gpointer);
98
99 int
100 open_cap_file(char *fname, capture_file *cf) {
101 #ifndef WITH_WIRETAP
102   guint32     magic[2];
103   char        err_str[PCAP_ERRBUF_SIZE];
104 #endif
105   struct stat cf_stat;
106
107   /* First, make sure the file is valid */
108   if (stat(fname, &cf_stat))
109     return (errno);
110   if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode))
111     return (OPEN_CAP_FILE_NOT_REGULAR);
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 #ifndef WITH_WIRETAP
121   fseek(cf->fh, 0L, SEEK_SET);
122   fread(magic, sizeof(guint32), 2, cf->fh);
123   fseek(cf->fh, 0L, SEEK_SET);
124 #endif
125   fclose(cf->fh);
126   cf->fh = NULL;
127   /* set the file name beacuse we need it to set the follow stream filter */
128   cf->filename = g_strdup( fname );
129
130   /* Next, find out what type of file we're dealing with */
131 #ifdef WITH_WIRETAP 
132   cf->cd_t  = WTAP_FILE_UNKNOWN;
133 #else
134   cf->cd_t  = CD_UNKNOWN;
135   cf->lnk_t = DLT_NULL;
136   cf->swap  = 0;
137 #endif
138   cf->count = 0;
139   cf->drops = 0;
140   cf->esec  = 0;
141   cf->eusec = 0;
142   cf->snap  = 0;
143   firstsec = 0, firstusec = 0;
144   lastsec = 0, lastusec = 0;
145  
146 #ifndef WITH_WIRETAP
147   if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) {
148
149     /* Pcap/Tcpdump file */
150     cf->pfh = pcap_open_offline(fname, err_str);
151     if (cf->pfh == NULL) {
152 #else
153         cf->wth = wtap_open_offline(fname);
154         if (cf->wth == NULL) {
155 #endif
156
157       /* XXX - we assume that, because we were able to open it above,
158          this must have failed because it's not a capture file in
159          a format we can read. */
160       return (OPEN_CAP_FILE_UNKNOWN_FORMAT);
161     }
162
163 #ifndef WITH_WIRETAP
164     if (cf->dfilter) {
165       if (pcap_compile(cf->pfh, &cf->fcode, cf->dfilter, 1, 0) < 0) {
166         simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
167           "\"%s\".", cf->dfilter);
168       } else if (pcap_setfilter(cf->pfh, &cf->fcode) < 0) {
169         simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
170       }
171     }
172
173     cf->fh   = pcap_file(cf->pfh);
174     cf->swap = pcap_is_swapped(cf->pfh);    
175     if ((cf->swap && BYTE_ORDER == BIG_ENDIAN) ||
176       (!cf->swap && BYTE_ORDER == LITTLE_ENDIAN)) {
177       /* Data is big-endian */
178       cf->cd_t = CD_PCAP_BE;
179     } else {
180       cf->cd_t = CD_PCAP_LE;
181     }
182     cf->vers  = ( ((pcap_major_version(cf->pfh) & 0x0000ffff) << 16) |
183                   pcap_minor_version(cf->pfh) );
184     cf->snap  = pcap_snapshot(cf->pfh);
185     cf->lnk_t = pcap_datalink(cf->pfh);
186   } else if (ntohl(magic[0]) == SNOOP_MAGIC_1 && ntohl(magic[1]) == SNOOP_MAGIC_2) {
187     return (OPEN_CAP_FILE_UNKNOWN_FORMAT);
188   }
189   
190   if (cf->cd_t == CD_UNKNOWN)
191     return (OPEN_CAP_FILE_UNKNOWN_FORMAT);
192 #else
193     if (cf->dfilter) {
194       if (wtap_offline_filter(cf->wth, cf->dfilter) < 0) {
195         simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string "
196           "\"%s\".", cf->dfilter);
197       }
198     }
199   cf->fh = wtap_file(cf->wth);
200   cf->cd_t = wtap_file_type(cf->wth);
201   cf->snap = wtap_snapshot_length(cf->wth);
202 #endif
203
204   return (0);
205 }
206
207 static void
208 free_packets_cb(gpointer data, gpointer user_data)
209 {
210   g_free(data);
211 }
212
213 /* Reset everything to a pristine state */
214 void
215 close_cap_file(capture_file *cf, void *w, guint context) {
216   if (cf->fh) {
217     fclose(cf->fh);
218     cf->fh = NULL;
219   }
220 #ifdef WITH_WIRETAP
221   if (cf->wth) {
222     wtap_close(cf->wth);
223     cf->wth = NULL;
224   }
225 #else
226   if (cf->pfh) {
227     pcap_close(cf->pfh);
228     cf->pfh = NULL;
229   }
230 #endif
231   if (cf->plist) {
232     g_list_foreach(cf->plist, free_packets_cb, NULL);
233     g_list_free(cf->plist);
234     cf->plist = NULL;
235   }
236   gtk_text_freeze(GTK_TEXT(byte_view));
237   gtk_text_set_point(GTK_TEXT(byte_view), 0);
238   gtk_text_forward_delete(GTK_TEXT(byte_view),
239     gtk_text_get_length(GTK_TEXT(byte_view)));
240   gtk_text_thaw(GTK_TEXT(byte_view));
241   gtk_tree_clear_items(GTK_TREE(tree_view), 0,
242     g_list_length(GTK_TREE(tree_view)->children));
243
244   gtk_clist_freeze(GTK_CLIST(packet_list));
245   gtk_clist_clear(GTK_CLIST(packet_list));
246   gtk_clist_thaw(GTK_CLIST(packet_list));
247   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
248 }
249
250 int
251 load_cap_file(char *fname, capture_file *cf) {
252   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
253   gchar  *done_fmt = " File: %s  Drops: %d";
254   gchar  *err_fmt  = " Error: Could not load '%s'";
255   gint    timeout;
256   size_t  msg_len;
257   int     err;
258
259   close_cap_file(cf, info_bar, file_ctx);
260
261   /* Initialize protocol-specific variables */
262   ncp_init_protocol();
263
264   if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
265     name_ptr = fname;
266   else
267     name_ptr++;
268   load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
269   sprintf(load_msg, load_fmt, name_ptr);
270   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
271   
272   timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf);
273   
274   err = open_cap_file(fname, cf);
275 #ifdef WITH_WIRETAP
276   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
277 #else
278   if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
279 #endif
280     gtk_clist_freeze(GTK_CLIST(packet_list));
281     init_col_widths(cf);
282 #ifdef WITH_WIRETAP
283     wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);
284     wtap_close(cf->wth);
285     cf->wth = NULL;
286 #else
287     pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
288     pcap_close(cf->pfh);
289     cf->pfh = NULL;
290 #endif
291     cf->fh = fopen(fname, "r");
292
293     set_col_widths(cf);
294     gtk_clist_thaw(GTK_CLIST(packet_list));
295   }
296   
297   gtk_timeout_remove(timeout);
298   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
299
300   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
301
302   if (err == 0) {
303     msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
304     load_msg = g_realloc(load_msg, msg_len);
305
306     if (cf->user_saved || !cf->save_file)
307             snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
308     else
309             snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
310
311     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
312     g_free(load_msg);
313
314 /*    name_ptr[-1] = '\0';  Why is this here? It causes problems with capture files */
315 #ifdef USE_ITEM
316     set_menu_sensitivity("/File/Close", TRUE);
317     set_menu_sensitivity("/File/Reload", TRUE);
318     set_menu_sensitivity("/Tools/Summary", TRUE);
319 #else
320     set_menu_sensitivity("<Main>/File/Close", TRUE);
321     set_menu_sensitivity("<Main>/File/Reload", TRUE);
322     set_menu_sensitivity("<Main>/Tools/Summary", TRUE);
323 #endif
324   } else {
325     msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
326     load_msg = g_realloc(load_msg, msg_len);
327     snprintf(load_msg, msg_len, err_fmt, name_ptr);
328     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
329     g_free(load_msg);
330 #ifdef USE_ITEM
331     set_menu_sensitivity("/File/Close", FALSE);
332     set_menu_sensitivity("/File/Save", FALSE);
333     set_menu_sensitivity("/File/Save As...", FALSE);
334     set_menu_sensitivity("/File/Reload", FALSE);
335     set_menu_sensitivity("/Tools/Summary", FALSE);
336
337 #else
338     set_menu_sensitivity("<Main>/File/Close", FALSE);
339     set_menu_sensitivity("<Main>/File/Save", FALSE);
340     set_menu_sensitivity("<Main>/File/Save As...", FALSE);
341     set_menu_sensitivity("<Main>/File/Reload", FALSE);
342     set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
343 #endif
344   }
345   return err;
346 }
347
348 void 
349 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
350   
351   capture_file *cf = (capture_file *)data;
352   char buffer[256];
353
354   /* avoid reentrancy problems and stack overflow */
355   gtk_input_remove(cap_input_id);
356   if (tail_timeout_id != -1) gtk_timeout_remove(tail_timeout_id);
357
358   if (read(sync_pipe[0], buffer, 256) <= 0) {
359
360     /* process data until end of file and stop capture (restore menu items) */
361     gtk_clist_freeze(GTK_CLIST(packet_list));
362     init_col_widths(cf);
363 #ifdef WITH_WIRETAP
364     wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
365 #else
366     pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
367 #endif
368
369     set_col_widths(cf);
370     gtk_clist_thaw(GTK_CLIST(packet_list));
371
372 #ifdef WITH_WIRETAP
373     wtap_close(cf->wth);
374     cf->wth = NULL;
375 #else
376     pcap_close(cf->pfh);
377     cf->pfh = NULL;
378 #endif
379 #ifdef USE_ITEM
380     set_menu_sensitivity("/File/Open...", TRUE);
381     set_menu_sensitivity("/File/Close", TRUE);
382     set_menu_sensitivity("/File/Save As...", TRUE);
383     set_menu_sensitivity("/File/Reload", TRUE);
384     set_menu_sensitivity("/Capture/Start...", TRUE);
385     set_menu_sensitivity("/Tools/Capture...", TRUE);
386     set_menu_sensitivity("/Tools/Summary", TRUE);
387
388 #else
389     set_menu_sensitivity("<Main>/File/Open...", TRUE);
390     set_menu_sensitivity("<Main>/File/Close", TRUE);
391     set_menu_sensitivity("<Main>/File/Save As...", TRUE);
392     set_menu_sensitivity("<Main>/File/Reload", TRUE);
393     set_menu_sensitivity("<Main>/Capture/Start...", TRUE);
394     set_menu_sensitivity("<Main>/Tools/Capture...", TRUE);
395     set_menu_sensitivity("<Main>/Tools/Summary", TRUE);
396 #endif
397     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
398     return;
399   }
400
401   gtk_clist_freeze(GTK_CLIST(packet_list));
402   init_col_widths(cf);
403 #ifdef WITH_WIRETAP
404   wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
405 #else
406   pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
407 #endif
408
409   set_col_widths(cf);
410   gtk_clist_thaw(GTK_CLIST(packet_list));
411
412   /* restore pipe handler */
413   cap_input_id = gtk_input_add_full (sync_pipe[0],
414                                      GDK_INPUT_READ,
415                                      cap_file_input_cb,
416                                      NULL,
417                                      (gpointer) cf,
418                                      NULL);
419
420   /* only useful in case of low amount of captured data */
421   tail_timeout_id = gtk_timeout_add(TAIL_TIMEOUT, tail_timeout_cb, (gpointer) cf);
422
423 }
424
425 gint
426 tail_timeout_cb(gpointer data) {
427
428   capture_file *cf = (capture_file *)data;
429
430   /* avoid reentrancy problems and stack overflow */
431   gtk_input_remove(cap_input_id);
432
433   gtk_clist_freeze(GTK_CLIST(packet_list));
434   init_col_widths(cf);
435 #ifdef WITH_WIRETAP
436   wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf);      
437 #else
438   pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf);
439 #endif
440
441   set_col_widths(cf);
442   gtk_clist_thaw(GTK_CLIST(packet_list));
443
444   cap_input_id = gtk_input_add_full (sync_pipe[0],
445                                      GDK_INPUT_READ,
446                                      cap_file_input_cb,
447                                      NULL,
448                                      (gpointer) cf,
449                                      NULL);
450
451   return TRUE;
452 }
453
454 int
455 tail_cap_file(char *fname, capture_file *cf) {
456   int     err;
457
458   close_cap_file(cf, info_bar, file_ctx);
459
460   /* Initialize protocol-speficic variables */
461   ncp_init_protocol();
462   
463   err = open_cap_file(fname, cf);
464 #ifdef WITH_WIRETAP
465   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
466 #else
467   if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) {
468 #endif
469
470 #ifdef USE_ITEM
471     set_menu_sensitivity("/File/Open...", FALSE);
472     set_menu_sensitivity("/File/Close", FALSE);
473     set_menu_sensitivity("/File/Reload", FALSE);
474     set_menu_sensitivity("/Capture/Start...", FALSE);
475     set_menu_sensitivity("/Tools/Capture...", FALSE);
476     set_menu_sensitivity("/Tools/Summary", FALSE);
477
478 #else
479     set_menu_sensitivity("<Main>/File/Open...", FALSE);
480     set_menu_sensitivity("<Main>/File/Close", FALSE);
481     set_menu_sensitivity("<Main>/File/Reload", FALSE);
482     set_menu_sensitivity("<Main>/Capture/Start...", FALSE);
483     set_menu_sensitivity("<Main>/Tools/Capture...", FALSE);
484     set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
485
486 #endif
487     cf->fh = fopen(fname, "r");
488     tail_timeout_id = -1;
489     cap_input_id = gtk_input_add_full (sync_pipe[0],
490                                        GDK_INPUT_READ,
491                                        cap_file_input_cb,
492                                        NULL,
493                                        (gpointer) cf,
494                                        NULL);
495     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, 
496                        " <live capture in progress>");
497   }
498   else {
499 #ifdef USE_ITEM
500     set_menu_sensitivity("/File/Close", FALSE);
501     set_menu_sensitivity("/File/Save", FALSE);
502     set_menu_sensitivity("/File/Save As...", FALSE);
503     set_menu_sensitivity("/File/Reload", FALSE);
504     set_menu_sensitivity("/Tools/Summary", FALSE);
505 #else
506     set_menu_sensitivity("<Main>/File/Close", FALSE);
507     set_menu_sensitivity("<Main>/File/Save", FALSE);
508     set_menu_sensitivity("<Main>/File/Save As...", FALSE);
509     set_menu_sensitivity("<Main>/File/Reload", FALSE);
510     set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
511 #endif
512     close(sync_pipe[0]);
513   }
514   return err;
515 }
516
517 static void
518 compute_time_stamps(frame_data *fdata, capture_file *cf)
519 {
520   /* If we don't have the time stamp of the first packet, it's because this
521      is the first packet.  Save the time stamp of this packet as the time
522      stamp of the first packet. */
523   if (!firstsec && !firstusec) {
524     firstsec  = fdata->abs_secs;
525     firstusec = fdata->abs_usecs;
526   }
527
528   /* Do the same for the time stamp of the previous packet. */
529   if (!lastsec && !lastusec) {
530     lastsec  = fdata->abs_secs;
531     lastusec = fdata->abs_usecs;
532   }
533
534   /* Get the time elapsed between the first packet and this packet. */
535   cf->esec = fdata->abs_secs - firstsec;
536   if (firstusec <= fdata->abs_usecs) {
537     cf->eusec = fdata->abs_usecs - firstusec;
538   } else {
539     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
540     cf->esec--;
541   }
542   fdata->rel_secs = cf->esec;
543   fdata->rel_usecs = cf->eusec;
544   
545   /* Do the same for the previous packet */
546   fdata->del_secs = fdata->abs_secs - lastsec;
547   if (lastusec <= fdata->abs_usecs) {
548     fdata->del_usecs = fdata->abs_usecs - lastusec;
549   } else {
550     fdata->del_usecs = (fdata->abs_usecs + 1000000) - lastusec;
551     fdata->del_secs--;
552   }
553   lastsec = fdata->abs_secs;
554   lastusec = fdata->abs_usecs;
555 }
556
557 static void
558 change_time_format_in_packet_list(frame_data *fdata, capture_file *cf)
559 {
560   gint          i, col_width;
561
562   /* XXX - there really should be a way of checking "cf->cinfo" for this;
563      the answer isn't going to change from packet to packet, so we should
564      simply skip all the "change_time_formats()" work if we're not
565      changing anything. */
566   fdata->cinfo = &cf->cinfo;
567   if (!check_col(fdata, COL_CLS_TIME)) {
568     /* There are no columns that show the time in the "command-line-specified"
569        format, so there's nothing we need to do. */
570     return;
571   }
572
573   compute_time_stamps(fdata, cf);
574
575   for (i = 0; i < fdata->cinfo->num_cols; i++) {
576     fdata->cinfo->col_data[i][0] = '\0';
577   }
578   col_add_cls_time(fdata);
579   for (i = 0; i < fdata->cinfo->num_cols; i++) {
580     if (fdata->cinfo->fmt_matx[i][COL_CLS_TIME]) {
581       /* This is one of the columns that shows the time in
582          "command-line-specified" format; update it. */
583       col_width = gdk_string_width(pl_style->font, fdata->cinfo->col_data[i]);
584       if (col_width > fdata->cinfo->col_width[i])
585         fdata->cinfo->col_width[i] = col_width;
586       gtk_clist_set_text(GTK_CLIST(packet_list), cf->count - 1, i,
587                           fdata->cinfo->col_data[i]);
588     }
589   }
590   fdata->cinfo = NULL;
591 }
592
593 static void
594 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
595 {
596   gint          i, row, col_width;
597
598   compute_time_stamps(fdata, cf);
599
600   fdata->cinfo = &cf->cinfo;
601   for (i = 0; i < fdata->cinfo->num_cols; i++) {
602     fdata->cinfo->col_data[i][0] = '\0';
603   }
604   if (check_col(fdata, COL_NUMBER))
605     col_add_fstr(fdata, COL_NUMBER, "%d", cf->count);
606   dissect_packet(buf, fdata, NULL);
607   for (i = 0; i < fdata->cinfo->num_cols; i++) {
608     col_width = gdk_string_width(pl_style->font, fdata->cinfo->col_data[i]);
609     if (col_width > fdata->cinfo->col_width[i])
610       fdata->cinfo->col_width[i] = col_width;
611   }
612   row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
613   fdata->cinfo = NULL;
614 }
615
616 static void
617 #ifdef WITH_WIRETAP
618 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
619 #else
620 pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr,
621 #endif
622   const u_char *buf) {
623   frame_data   *fdata;
624   capture_file *cf = (capture_file *) user;
625
626   while (gtk_events_pending())
627     gtk_main_iteration();
628
629   /* Allocate the next list entry, and add it to the list. */
630   fdata = (frame_data *) g_malloc(sizeof(frame_data));
631   cf->plist = g_list_append(cf->plist, (gpointer) fdata);
632
633   cf->cur = fdata;
634   cf->count++;
635
636   fdata->pkt_len  = phdr->len;
637   fdata->cap_len  = phdr->caplen;
638 #ifdef WITH_WIRETAP
639   fdata->file_off = offset;
640   fdata->lnk_t = phdr->pkt_encap;
641 #else
642   fdata->file_off = ftell(pcap_file(cf->pfh)) - phdr->caplen;
643 #endif
644   fdata->abs_secs  = phdr->ts.tv_sec;
645   fdata->abs_usecs = phdr->ts.tv_usec;
646
647   add_packet_to_packet_list(fdata, cf, buf);
648 }
649
650 static void
651 filter_packets_cb(gpointer data, gpointer user_data)
652 {
653   frame_data *fd = data;
654   capture_file *cf = user_data;
655
656   cf->cur = fd;
657   cf->count++;
658
659   fseek(cf->fh, fd->file_off, SEEK_SET);
660   fread(cf->pd, sizeof(guint8), fd->cap_len, cf->fh);
661
662   add_packet_to_packet_list(fd, cf, cf->pd);
663 }
664
665 void
666 filter_packets(capture_file *cf)
667 {
668   /* Freeze the packet list while we redo it, so we don't get any
669      screen updates while it happens. */
670   gtk_clist_freeze(GTK_CLIST(packet_list));
671
672   /* Clear it out. */
673   gtk_clist_clear(GTK_CLIST(packet_list));
674
675   /*
676    * Iterate through the list of packets, calling a routine
677    * to run the filter on the packet, see if it matches, and
678    * put it in the display list if so.
679    *
680    * XXX - we don't yet have anything to run a filter on a packet;
681    * this code awaits the arrival of display filter code.
682    */
683   firstsec = 0;
684   firstusec = 0;
685   lastsec = 0;
686   lastusec = 0;
687   cf->count = 0;
688   g_list_foreach(cf->plist, filter_packets_cb, cf);
689
690   /* Unfreeze the packet list. */
691   gtk_clist_thaw(GTK_CLIST(packet_list));
692 }
693
694 static void
695 change_time_formats_cb(gpointer data, gpointer user_data)
696 {
697   frame_data *fd = data;
698   capture_file *cf = user_data;
699
700   cf->cur = fd;
701   cf->count++;
702
703   change_time_format_in_packet_list(fd, cf);
704 }
705
706 /* Scan through the packet list and change all columns that use the
707    "command-line-specified" time stamp format to use the current
708    value of that format. */
709 void
710 change_time_formats(capture_file *cf)
711 {
712   int i;
713
714   /* Freeze the packet list while we redo it, so we don't get any
715      screen updates while it happens. */
716   gtk_clist_freeze(GTK_CLIST(packet_list));
717
718   /* Zero out the column widths. */
719   init_col_widths(cf);
720
721   /*
722    * Iterate through the list of packets, calling a routine
723    * to run the filter on the packet, see if it matches, and
724    * put it in the display list if so.
725    */
726   firstsec = 0;
727   firstusec = 0;
728   lastsec = 0;
729   lastusec = 0;
730   cf->count = 0;
731   g_list_foreach(cf->plist, change_time_formats_cb, cf);
732
733   /* Set the column widths of those columns that show the time in
734      "command-line-specified" format. */
735   for (i = 0; i < cf->cinfo.num_cols; i++) {
736     if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
737       gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
738         cf->cinfo.col_width[i]);
739     }
740   }
741
742   /* Unfreeze the packet list. */
743   gtk_clist_thaw(GTK_CLIST(packet_list));
744 }
745
746 /* Initialize the maximum widths of the columns to the widths of their
747    titles. */
748 static void
749 init_col_widths(capture_file *cf)
750 {
751   int i;
752
753   /* XXX - this should use the column *title* font, not the font for
754      the items in the list.
755
756      Unfortunately, it's not clear how to get that font - it'd be
757      the font used for buttons; there doesn't seem to be a way to get
758      that from a clist, or to get one of the buttons in that clist from
759      the clist in order to get its font. */
760   for (i = 0; i < cf->cinfo.num_cols; i++)
761     cf->cinfo.col_width[i] = gdk_string_width(pl_style->font,
762                                                cf->cinfo.col_title[i]);
763 }
764
765 /* Set the widths of the columns to the maximum widths we found. */
766 static void
767 set_col_widths(capture_file *cf)
768 {
769   int i;
770
771   for (i = 0; i < cf->cinfo.num_cols; i++) {
772     gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
773       cf->cinfo.col_width[i]);
774   }
775 }
776
777 /* Tries to mv a file. If unsuccessful, tries to cp the file.
778  * Returns 0 on failure to do either, 1 on success of either
779  */
780 int
781 file_mv(char *from, char *to)
782 {
783
784 #define COPY_BUFFER_SIZE        8192
785
786         int retval;
787
788         /* try a hard link */
789         retval = link(from, to);
790
791         /* or try a copy */
792         if (retval < 0) {
793                 retval = file_cp(from, to);
794                 if (!retval) {
795                         return 0;
796                 }
797         }
798
799         unlink(from);
800         return 1;
801 }
802
803 /* Copies a file.
804  * Returns 0 on failure to do either, 1 on success of either
805  */
806 int
807 file_cp(char *from, char *to)
808 {
809
810 #define COPY_BUFFER_SIZE        8192
811
812         int from_fd, to_fd, nread, nwritten;
813         char *buffer;
814         gint dialogue_button = ESD_BTN_OK;
815
816         buffer = g_malloc(COPY_BUFFER_SIZE);
817
818         from_fd = open(from, O_RDONLY);
819         if (from_fd < 0) {
820                 simple_dialog(ESD_TYPE_WARN, &dialogue_button,
821                         file_open_error_message(errno, TRUE), from);
822                 return 0;
823         }
824
825         to_fd = creat(to, 0644);
826         if (to_fd < 0) {
827                 simple_dialog(ESD_TYPE_WARN, &dialogue_button,
828                         file_open_error_message(errno, TRUE), to);
829                 close(from_fd);
830                 return 0;
831         }
832
833         while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
834                 nwritten = write(to_fd, buffer, nread);
835                 if (nwritten < nread) {
836                         if (nwritten < 0) {
837                                 simple_dialog(ESD_TYPE_WARN, &dialogue_button,
838                                         file_write_error_message(errno), to);
839                         } else {
840                                 simple_dialog(ESD_TYPE_WARN, &dialogue_button,
841 "The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
842                                         to, nread, nwritten);
843                         }
844                         close(from_fd);
845                         close(to_fd);
846                         return 0;
847                 }
848         }
849         if (nread < 0) {
850                 simple_dialog(ESD_TYPE_WARN, &dialogue_button,
851                         file_read_error_message(errno), from);
852                 close(from_fd);
853                 close(to_fd);
854                 return 0;
855         }
856         close(from_fd);
857         close(to_fd);
858
859         return 1;
860 }
861
862 char *
863 file_open_error_message(int err, int for_writing)
864 {
865   char *errmsg;
866   static char errmsg_errno[1024+1];
867
868   switch (err) {
869
870   case OPEN_CAP_FILE_NOT_REGULAR:
871     errmsg = "The file \"%s\" is invalid.";
872     break;
873
874   case OPEN_CAP_FILE_UNKNOWN_FORMAT:
875     errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
876     break;
877
878   case ENOENT:
879     if (for_writing)
880       errmsg = "The path to the file \"%s\" does not exist.";
881     else
882       errmsg = "The file \"%s\" does not exist.";
883     break;
884
885   case EACCES:
886     if (for_writing)
887       errmsg = "You do not have permission to create or write to the file \"%s\".";
888     else
889       errmsg = "You do not have permission to open the file \"%s\".";
890     break;
891
892   default:
893     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.", strerror(err));
894     errmsg = errmsg_errno;
895     break;
896   }
897   return errmsg;
898 }
899
900 char *
901 file_read_error_message(int err)
902 {
903   static char errmsg_errno[1024+1];
904
905   sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.", strerror(err));
906   return errmsg_errno;
907 }
908
909 char *
910 file_write_error_message(int err)
911 {
912   char *errmsg;
913   static char errmsg_errno[1024+1];
914
915   switch (err) {
916
917   case ENOSPC:
918     errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
919     break;
920
921 #ifdef EDQUOT
922   case EDQUOT:
923     errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
924     break;
925 #endif
926
927   default:
928     sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.", strerror(err));
929     errmsg = errmsg_errno;
930     break;
931   }
932   return errmsg;
933 }