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