Consolidate flags in struct frame_data, and add "visited" flag. Use
[obnox/wireshark/wip.git] / tethereal.c
1 /* tethereal.c
2  *
3  * $Id: tethereal.c,v 1.25 2000/04/13 20:39:19 gram Exp $
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@zing.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Text-mode variant, by Gilbert Ramirez <gram@xiexie.org>.
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
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <signal.h>
44
45 #ifdef NEED_SNPRINTF_H
46 # ifdef HAVE_STDARG_H
47 #  include <stdarg.h>
48 # else
49 #  include <varargs.h>
50 # endif
51 # include "snprintf.h"
52 #endif
53
54 #if defined(HAVE_UCD_SNMP_SNMP_H)
55 #ifdef HAVE_UCD_SNMP_VERSION_H
56 #include <ucd-snmp/version.h>
57 #endif /* HAVE_UCD_SNMP_VERSION_H */
58 #elif defined(HAVE_SNMP_SNMP_H)
59 #ifdef HAVE_SNMP_VERSION_H
60 #include <snmp/version.h>
61 #endif /* HAVE_SNMP_VERSION_H */
62 #endif /* SNMP */
63
64 #ifdef NEED_STRERROR_H
65 #include "strerror.h"
66 #endif
67
68 #ifdef NEED_GETOPT_H
69 #include "getopt.h"
70 #endif
71
72 #include "globals.h"
73 #include "timestamp.h"
74 #include "packet.h"
75 #include "file.h"
76 #include "prefs.h"
77 #include "column.h"
78 #include "print.h"
79 #include "resolv.h"
80 #include "follow.h"
81 #include "util.h"
82 #include "ui_util.h"
83 #include "conversation.h"
84 #include "plugins.h"
85
86 static guint32 firstsec, firstusec;
87 static guint32 prevsec, prevusec;
88 static gchar   comp_info_str[256];
89 static gboolean verbose;
90 static gboolean print_hex;
91
92 #ifdef HAVE_LIBPCAP
93 typedef struct _loop_data {
94   gint           linktype;
95   pcap_t        *pch;
96   wtap_dumper   *pdh;
97 } loop_data;
98
99 static loop_data ld;
100
101 static int capture(int, int);
102 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
103   const u_char *);
104 static void capture_cleanup(int);
105 #endif
106
107 typedef struct {
108   capture_file *cf;
109   wtap_dumper *pdh;
110 } cb_args_t;
111
112 static int load_cap_file(capture_file *, int);
113 static void wtap_dispatch_cb_write(u_char *, const struct wtap_pkthdr *, int,
114     const u_char *);
115 static void wtap_dispatch_cb_print(u_char *, const struct wtap_pkthdr *, int,
116     const u_char *);
117 static gchar *col_info(frame_data *, gint);
118
119 packet_info  pi;
120 capture_file cf;
121 FILE        *data_out_file = NULL;
122 guint        main_ctx, file_ctx;
123 ts_type timestamp_type = RELATIVE;
124
125 static void 
126 print_usage(void)
127 {
128   int i;
129
130   fprintf(stderr, "This is GNU t%s %s, compiled with %s\n", PACKAGE,
131           VERSION, comp_info_str);
132 #ifdef HAVE_LIBPCAP
133   fprintf(stderr, "t%s [ -vVh ] [ -c count ] [ -D ] [ -f <filter expression> ]\n", PACKAGE);
134   fprintf(stderr, "\t[ -F <capture file type> ] [ -i iface ] [ -n ] [ -r infile ]\n");
135   fprintf(stderr, "\t[ -R <filter expression> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
136   fprintf(stderr, "\t[ -w savefile ] [ -x ]\n");
137 #else
138   fprintf(stderr, "t%s [ -vVh ] [ -D ] [ -F <capture file type> ] [ -n ] [ -r infile ]\n", PACKAGE);
139   fprintf(stderr, "\t[ -R <filter expression> ] [ -t <time stamp format> ] [ -w savefile ]\n");
140   fprintf(stderr, "\t[ -x ]\n");
141 #endif
142   fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
143   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
144     if (wtap_dump_can_open(i))
145       fprintf(stderr, "\t%s - %s\n",
146         wtap_file_type_short_string(i), wtap_file_type_string(i));
147   }
148   fprintf(stderr, "\tdefault is libpcap\n");
149 }
150
151 int
152 main(int argc, char *argv[])
153 {
154   int                  opt, i;
155   extern char         *optarg;
156   gboolean             arg_error = FALSE;
157 #ifdef HAVE_LIBPCAP
158 #ifdef WIN32
159   char pcap_version[] = "0.4a6";
160 #else
161   extern char          pcap_version[];
162 #endif
163 #endif
164   char                *pf_path;
165   int                  err;
166 #ifdef HAVE_LIBPCAP
167   gboolean             capture_filter_specified = FALSE;
168   int                  packet_count = 0;
169   GList               *if_list;
170   gchar                err_str[PCAP_ERRBUF_SIZE];
171 #else
172   gboolean             capture_option_specified = FALSE;
173 #endif
174   int                 out_file_type = WTAP_FILE_PCAP;
175   gchar               *cf_name = NULL, *rfilter = NULL;
176   dfilter             *rfcode = NULL;
177   e_prefs             *prefs;
178
179   /* If invoked with the "-G" flag, we dump out a glossary of
180      display filter symbols.
181
182      We do this here to mirror what happens in the GTK+ version, although
183      it's not necessary here. */
184   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
185     dissect_init();
186     proto_registrar_dump();
187     exit(0);
188   }
189
190   prefs = read_prefs(&pf_path);
191   if (pf_path != NULL) {
192     fprintf(stderr, "Can't open preferences file \"%s\": %s.\n", pf_path,
193         strerror(errno));
194   }
195     
196   /* Initialize the capture file struct */
197   cf.plist              = NULL;
198   cf.plist_end          = NULL;
199   cf.wth                = NULL;
200   cf.fh                 = NULL;
201   cf.filename           = NULL;
202   cf.user_saved         = FALSE;
203   cf.is_tempfile        = FALSE;
204   cf.rfcode             = NULL;
205   cf.dfilter            = NULL;
206   cf.dfcode             = NULL;
207 #ifdef HAVE_LIBPCAP
208   cf.cfilter            = g_strdup("");
209 #endif
210   cf.iface              = NULL;
211   cf.save_file          = NULL;
212   cf.save_file_fd       = -1;
213   cf.snap               = WTAP_MAX_PACKET_SIZE;
214   cf.count              = 0;
215   cf.cinfo.num_cols     = prefs->num_cols;
216   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
217   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
218   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
219   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
220   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
221
222   /* Assemble the compile-time options */
223   snprintf(comp_info_str, 256,
224 #ifdef GTK_MAJOR_VERSION
225     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
226     GTK_MICRO_VERSION,
227 #else
228     "GTK+ (version unknown), %s%s, %s%s, %s%s",
229 #endif
230
231 #ifdef HAVE_LIBPCAP
232    "with libpcap ", pcap_version,
233 #else
234    "without libpcap", "",
235 #endif
236
237 #ifdef HAVE_LIBZ
238 #ifdef ZLIB_VERSION
239    "with libz ", ZLIB_VERSION,
240 #else /* ZLIB_VERSION */
241    "with libz ", "(version unknown)",
242 #endif /* ZLIB_VERSION */
243 #else /* HAVE_LIBZ */
244    "without libz", "",
245 #endif /* HAVE_LIBZ */
246
247 /* Oh, this is pretty */
248 #if defined(HAVE_UCD_SNMP_SNMP_H)
249 #ifdef HAVE_UCD_SNMP_VERSION_H
250    "with UCD SNMP ", VersionInfo
251 #else /* HAVE_UCD_SNMP_VERSION_H */
252    "with UCD SNMP ", "(version unknown)"
253 #endif /* HAVE_UCD_SNMP_VERSION_H */
254 #elif defined(HAVE_SNMP_SNMP_H)
255 #ifdef HAVE_SNMP_VERSION_H
256    "with CMU SNMP ", snmp_Version()
257 #else /* HAVE_SNMP_VERSION_H */
258    "with CMU SNMP ", "(version unknown)"
259 #endif /* HAVE_SNMP_VERSION_H */
260 #else /* no SNMP */
261    "without SNMP", ""
262 #endif
263    );
264     
265   /* Now get our args */
266   while ((opt = getopt(argc, argv, "c:Df:F:hi:nr:R:s:t:vw:Vx")) != EOF) {
267     switch (opt) {
268       case 'c':        /* Capture xxx packets */
269 #ifdef HAVE_LIBPCAP
270         packet_count = atoi(optarg);
271 #else
272         capture_option_specified = TRUE;
273         arg_error = TRUE;
274 #endif
275         break;
276       case 'D':        /* Turn off DSCP printing */
277         g_ip_dscp_actif = FALSE;
278         break;
279       case 'f':
280 #ifdef HAVE_LIBPCAP
281         capture_filter_specified = TRUE;
282         cf.cfilter = g_strdup(optarg);
283 #else
284         capture_option_specified = TRUE;
285         arg_error = TRUE;
286 #endif
287         break;
288       case 'F':
289         out_file_type = wtap_short_string_to_file_type(optarg);
290         if (out_file_type < 0) {
291           fprintf(stderr, "tethereal: \"%s\" is not a valid capture file type\n",
292                         optarg);
293           exit(1);
294         }
295         break;
296       case 'h':        /* Print help and exit */
297         print_usage();
298         exit(0);
299         break;
300       case 'i':        /* Use interface xxx */
301 #ifdef HAVE_LIBPCAP
302         cf.iface = g_strdup(optarg);
303 #else
304         capture_option_specified = TRUE;
305         arg_error = TRUE;
306 #endif
307         break;
308       case 'n':        /* No name resolution */
309         g_resolving_actif = 0;
310         break;
311       case 'r':        /* Read capture file xxx */
312         cf_name = g_strdup(optarg);
313         break;
314       case 'R':        /* Read file filter */
315         rfilter = optarg;
316         break;
317       case 's':        /* Set the snapshot (capture) length */
318 #ifdef HAVE_LIBPCAP
319         cf.snap = atoi(optarg);
320 #else
321         capture_option_specified = TRUE;
322         arg_error = TRUE;
323 #endif
324         break;
325       case 't':        /* Time stamp type */
326         if (strcmp(optarg, "r") == 0)
327           timestamp_type = RELATIVE;
328         else if (strcmp(optarg, "a") == 0)
329           timestamp_type = ABSOLUTE;
330         else if (strcmp(optarg, "d") == 0)
331           timestamp_type = DELTA;
332         else {
333           fprintf(stderr, "tethereal: Invalid time stamp type \"%s\"\n",
334             optarg);
335           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
336           fprintf(stderr, "or \"d\" for delta.\n");
337           exit(1);
338         }
339         break;
340       case 'v':        /* Show version and exit */
341         printf("t%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
342         exit(0);
343         break;
344       case 'w':        /* Write to capture file xxx */
345         cf.save_file = g_strdup(optarg);
346         break;
347       case 'V':        /* Verbose */
348         verbose = TRUE;
349         break;
350       case 'x':        /* Print packet data in hex (and ASCII) */
351         print_hex = TRUE;
352         break;
353     }
354   }
355   
356   /* If no capture filter or read filter has been specified, and there are
357      still command-line arguments, treat them as the tokens of a capture
358      filter (if no "-r" flag was specified) or a read filter (if a "-r"
359      flag was specified. */
360   if (optind < argc) {
361     if (cf_name != NULL) {
362       if (rfilter != NULL) {
363         fprintf(stderr,
364 "tethereal: Read filters were specified both with \"-R\" and with additional command-line arguments\n");
365         exit(2);
366       }
367       rfilter = get_args_as_string(argc, argv, optind);
368     } else {
369 #ifdef HAVE_LIBPCAP
370       if (capture_filter_specified) {
371         fprintf(stderr,
372 "tethereal: Capture filters were specified both with \"-f\" and with additional command-line arguments\n");
373         exit(2);
374       }
375       cf.cfilter = get_args_as_string(argc, argv, optind);
376 #else
377       capture_option_specified = TRUE;
378 #endif
379     }
380   }
381
382 #ifndef HAVE_LIBPCAP
383   if (capture_option_specified)
384     fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
385 #endif
386   if (arg_error)
387     print_usage();
388
389   /* Build the column format array */  
390   for (i = 0; i < cf.cinfo.num_cols; i++) {
391     cf.cinfo.col_fmt[i] = get_column_format(i);
392     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
393     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
394       NUM_COL_FMTS);
395     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
396     if (cf.cinfo.col_fmt[i] == COL_INFO)
397       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
398     else
399       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
400   }
401
402   if (cf.snap < 1)
403     cf.snap = WTAP_MAX_PACKET_SIZE;
404   else if (cf.snap < MIN_PACKET_SIZE)
405     cf.snap = MIN_PACKET_SIZE;
406   
407   dissect_init();   /* Init anything that needs initializing */
408
409   if (rfilter != NULL) {
410     if (dfilter_compile(rfilter, &rfcode) != 0) {
411       fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
412       dissect_cleanup();
413       exit(2);
414     }
415   }
416   cf.rfcode = rfcode;
417   if (cf_name) {
418     err = open_cap_file(cf_name, FALSE, &cf);
419     if (err != 0) {
420       dissect_cleanup();
421       exit(2);
422     }
423     err = load_cap_file(&cf, out_file_type);
424     if (err != 0) {
425       dissect_cleanup();
426       exit(2);
427     }
428     cf_name[0] = '\0';
429   } else {
430     /* No capture file specified, so we're supposed to do a live capture;
431        do we have support for live captures? */
432 #ifdef HAVE_LIBPCAP
433     /* Yes; did the user specify an interface to use? */
434     if (cf.iface == NULL) {
435         /* No - pick the first one from the list of interfaces. */
436         if_list = get_interface_list(&err, err_str);
437         if (if_list == NULL) {
438             switch (err) {
439
440             case CANT_GET_INTERFACE_LIST:
441                 fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
442                         err_str);
443                 break;
444
445             case NO_INTERFACES_FOUND:
446                 fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
447                 break;
448             }
449             exit(2);
450         }
451         cf.iface = g_strdup(if_list->data);     /* first interface */
452         free_interface_list(if_list);
453     }
454     capture(packet_count, out_file_type);
455 #else
456     /* No - complain. */
457     fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
458     exit(2);
459 #endif
460   }
461
462   dissect_cleanup();
463
464   exit(0);
465 }
466
467 #ifdef HAVE_LIBPCAP
468 /* Do the low-level work of a capture.
469    Returns TRUE if it succeeds, FALSE otherwise. */
470 static int
471 capture(int packet_count, int out_file_type)
472 {
473   gchar       err_str[PCAP_ERRBUF_SIZE];
474   bpf_u_int32 netnum, netmask;
475   void        (*oldhandler)(int);
476   int         err, inpkts;
477   char        errmsg[1024+1];
478
479   /* Initialize the table of conversations. */
480   conversation_init();
481
482   /* Initialize protocol-specific variables */
483   init_all_protocols();
484
485   ld.linktype       = WTAP_ENCAP_UNKNOWN;
486   ld.pdh            = NULL;
487
488   /* Open the network interface to capture from it. */
489   ld.pch = pcap_open_live(cf.iface, cf.snap, 1, 1000, err_str);
490
491   if (ld.pch == NULL) {
492     /* Well, we couldn't start the capture.
493        If this is a child process that does the capturing in sync
494        mode or fork mode, it shouldn't do any UI stuff until we pop up the
495        capture-progress window, and, since we couldn't start the
496        capture, we haven't popped it up. */
497     snprintf(errmsg, sizeof errmsg,
498       "The capture session could not be initiated (%s).\n"
499       "Please check to make sure you have sufficient permissions, and that\n"
500       "you have the proper interface specified.", err_str);
501     goto error;
502   }
503
504   if (cf.cfilter) {
505     /* A capture filter was specified; set it up. */
506     if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
507       snprintf(errmsg, sizeof errmsg,
508         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
509       goto error;
510     }
511     if (pcap_compile(ld.pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
512       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
513         pcap_geterr(ld.pch));
514       goto error;
515     }
516     if (pcap_setfilter(ld.pch, &cf.fcode) < 0) {
517       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
518         pcap_geterr(ld.pch));
519       goto error;
520     }
521   }
522
523   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(ld.pch));
524   if (cf.save_file != NULL) {
525     /* Set up to write to the capture file. */
526     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
527       strcpy(errmsg, "The network you're capturing from is of a type"
528                " that Tethereal doesn't support.");
529       goto error;
530     }
531     ld.pdh = wtap_dump_open(cf.save_file, out_file_type,
532                 ld.linktype, pcap_snapshot(ld.pch), &err);
533
534     if (ld.pdh == NULL) {
535       /* We couldn't set up to write to the capture file. */
536       switch (err) {
537
538       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
539         strcpy(errmsg, "Tethereal does not support writing capture files in that format.");
540         break;
541
542       case WTAP_ERR_UNSUPPORTED_ENCAP:
543       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
544         strcpy(errmsg, "Tethereal cannot save this capture in that format.");
545         break;
546
547       case WTAP_ERR_CANT_OPEN:
548         strcpy(errmsg, "The file to which the capture would be written"
549                  " couldn't be created for some unknown reason.");
550         break;
551
552       case WTAP_ERR_SHORT_WRITE:
553         strcpy(errmsg, "A full header couldn't be written to the file"
554                  " to which the capture would be written.");
555         break;
556
557       default:
558         if (err < 0) {
559           sprintf(errmsg, "The file to which the capture would be"
560                        " written (\"%s\") could not be opened: Error %d.",
561                         cf.save_file, err);
562         } else {
563           sprintf(errmsg, "The file to which the capture would be"
564                        " written (\"%s\") could not be opened: %s.",
565                         cf.save_file, strerror(err));
566         }
567         break;
568       }
569       goto error;
570     }
571   }
572
573   /* Catch SIGINT and SIGTERM and, if we get either of them, clean up
574      and exit.
575      XXX - deal with signal semantics on various platforms.  Or just
576      use "sigaction()" and be done with it? */
577   signal(SIGTERM, capture_cleanup);
578   signal(SIGINT, capture_cleanup);
579 #if !defined(WIN32)
580   if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
581     signal(SIGHUP, oldhandler);
582 #endif
583
584   /* Let the user know what interface was chosen. */
585   printf("Capturing on %s\n", cf.iface);
586
587   inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
588   pcap_close(ld.pch);
589
590   return TRUE;
591
592 error:
593   g_free(cf.save_file);
594   cf.save_file = NULL;
595   fprintf(stderr, "tethereal: %s\n", errmsg);
596   if (ld.pch != NULL)
597     pcap_close(ld.pch);
598
599   return FALSE;
600 }
601
602 static void
603 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
604   const u_char *pd)
605 {
606   struct wtap_pkthdr whdr;
607   loop_data *ld = (loop_data *) user;
608   cb_args_t args;
609
610   whdr.ts.tv_sec = phdr->ts.tv_sec;
611   whdr.ts.tv_usec = phdr->ts.tv_usec;
612   whdr.caplen = phdr->caplen;
613   whdr.len = phdr->len;
614   whdr.pkt_encap = ld->linktype;
615
616   args.cf = &cf;
617   args.pdh = ld->pdh;
618   if (ld->pdh) {
619     wtap_dispatch_cb_write((u_char *)&args, &whdr, 0, pd);
620     cf.count++;
621     printf("\r%u ", cf.count);
622     fflush(stdout);
623   } else {
624     wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, pd);
625   }
626 }
627
628 static void
629 capture_cleanup(int signum)
630 {
631   int err;
632
633   printf("\n");
634   pcap_close(ld.pch);
635   if (ld.pdh != NULL)
636     wtap_dump_close(ld.pdh, &err);
637   /* XXX - complain if this fails */
638   exit(0);
639 }
640 #endif /* HAVE_LIBPCAP */
641
642 static int
643 load_cap_file(capture_file *cf, int out_file_type)
644 {
645   gint         linktype;
646   wtap_dumper *pdh;
647   int          err;
648   int          success;
649   cb_args_t    args;
650
651   linktype = wtap_file_encap(cf->wth);
652   if (cf->save_file != NULL) {
653     /* Set up to write to the capture file. */
654     pdh = wtap_dump_open(cf->save_file, out_file_type,
655                 linktype, wtap_snapshot_length(cf->wth), &err);
656
657     if (pdh == NULL) {
658       /* We couldn't set up to write to the capture file. */
659       switch (err) {
660
661       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
662         fprintf(stderr,
663                 "tethereal: Capture files can't be written in that format.\n");
664         break;
665
666       case WTAP_ERR_UNSUPPORTED_ENCAP:
667       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
668         fprintf(stderr,
669 "tethereal: The capture file being read cannot be written in that format.\n");
670         break;
671
672       case WTAP_ERR_CANT_OPEN:
673         fprintf(stderr,
674 "tethereal: The file \"%s\" couldn't be created for some unknown reason.\n",
675                  cf->save_file);
676         break;
677
678       case WTAP_ERR_SHORT_WRITE:
679         fprintf(stderr,
680 "tethereal: A full header couldn't be written to the file \"%s\".\n",
681                 cf->save_file);
682         break;
683
684       default:
685         if (err < 0) {
686           fprintf(stderr,
687                 "tethereal: The file \"%s\" could not be opened: Error %d.\n",
688                 cf->save_file, err);
689         } else {
690           fprintf(stderr,
691                 "tethereal: The file \"%s\" could not be opened: %s\n.",
692                 cf->save_file, strerror(err));
693         }
694         break;
695       }
696       goto out;
697     }
698     args.cf = cf;
699     args.pdh = pdh;
700     success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (u_char *) &args,
701                         &err);
702   } else {
703     args.cf = cf;
704     args.pdh = NULL;
705     success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (u_char *) &args,
706                         &err);
707   }
708   if (!success) {
709     /* Print up a message box noting that the read failed somewhere along
710        the line. */
711     switch (err) {
712
713     case WTAP_ERR_UNSUPPORTED_ENCAP:
714       fprintf(stderr,
715 "tethereal: The capture file is for a network type that Tethereal doesn't support.\n");
716       break;
717
718     case WTAP_ERR_CANT_READ:
719       fprintf(stderr,
720 "tethereal: An attempt to read from the file failed for some unknown reason.\n");
721       break;
722
723     case WTAP_ERR_SHORT_READ:
724       fprintf(stderr,
725 "tethereal: The capture file appears to have been cut short in the middle of a packet.\n");
726       break;
727
728     case WTAP_ERR_BAD_RECORD:
729       fprintf(stderr,
730 "tethereal: The capture file appears to be damaged or corrupt.\n");
731       break;
732
733     default:
734       fprintf(stderr,
735 "tethereal: An error occurred while reading the capture file: %s.\n",
736         wtap_strerror(err));
737       break;
738     }
739   }
740
741 out:
742   wtap_close(cf->wth);
743   cf->wth = NULL;
744
745   return err;
746 }
747
748 static void
749 fill_in_fdata(frame_data *fdata, capture_file *cf,
750         const struct wtap_pkthdr *phdr, int offset)
751 {
752   int i;
753
754   fdata->next = NULL;
755   fdata->prev = NULL;
756   fdata->pkt_len  = phdr->len;
757   fdata->cap_len  = phdr->caplen;
758   fdata->file_off = offset;
759   fdata->lnk_t = phdr->pkt_encap;
760   fdata->abs_secs  = phdr->ts.tv_sec;
761   fdata->abs_usecs = phdr->ts.tv_usec;
762   fdata->flags.encoding = CHAR_ASCII;
763   fdata->flags.visited = 0;
764   fdata->pseudo_header = phdr->pseudo_header;
765   fdata->cinfo = NULL;
766
767   fdata->num = cf->count;
768
769   /* If we don't have the time stamp of the first packet in the
770      capture, it's because this is the first packet.  Save the time
771      stamp of this packet as the time stamp of the first packet. */
772   if (!firstsec && !firstusec) {
773     firstsec  = fdata->abs_secs;
774     firstusec = fdata->abs_usecs;
775   }
776
777   /* Get the time elapsed between the first packet and this packet. */
778   cf->esec = fdata->abs_secs - firstsec;
779   if (firstusec <= fdata->abs_usecs) {
780     cf->eusec = fdata->abs_usecs - firstusec;
781   } else {
782     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
783     cf->esec--;
784   }
785   
786   /* If we don't have the time stamp of the previous displayed packet,
787      it's because this is the first displayed packet.  Save the time
788      stamp of this packet as the time stamp of the previous displayed
789      packet. */
790   if (!prevsec && !prevusec) {
791     prevsec  = fdata->abs_secs;
792     prevusec = fdata->abs_usecs;
793   }
794
795   /* Get the time elapsed between the first packet and this packet. */
796   fdata->rel_secs = cf->esec;
797   fdata->rel_usecs = cf->eusec;
798   
799   /* Get the time elapsed between the previous displayed packet and
800      this packet. */
801   fdata->del_secs = fdata->abs_secs - prevsec;
802   if (prevusec <= fdata->abs_usecs) {
803     fdata->del_usecs = fdata->abs_usecs - prevusec;
804   } else {
805     fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
806     fdata->del_secs--;
807   }
808   prevsec = fdata->abs_secs;
809   prevusec = fdata->abs_usecs;
810
811   fdata->cinfo = &cf->cinfo;
812   for (i = 0; i < fdata->cinfo->num_cols; i++) {
813     fdata->cinfo->col_data[i][0] = '\0';
814   }
815 }
816
817 static void
818 wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
819   const u_char *buf)
820 {
821   cb_args_t    *args = (cb_args_t *) user;
822   capture_file *cf = args->cf;
823   wtap_dumper  *pdh = args->pdh;
824   frame_data    fdata;
825   proto_tree   *protocol_tree;
826   int           err;
827   gboolean      passed;
828
829   cf->count++;
830   if (cf->rfcode) {
831     fill_in_fdata(&fdata, cf, phdr, offset);
832     protocol_tree = proto_tree_create_root();
833     dissect_packet(buf, &fdata, protocol_tree);
834     passed = dfilter_apply(cf->rfcode, protocol_tree, buf);
835   } else {
836     protocol_tree = NULL;
837     passed = TRUE;
838   }
839   if (passed) {
840     /* XXX - do something if this fails */
841     wtap_dump(pdh, phdr, buf, &err);
842   }
843   if (protocol_tree != NULL)
844     proto_tree_free(protocol_tree);
845 }
846
847 static void
848 wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
849   const u_char *buf)
850 {
851   cb_args_t    *args = (cb_args_t *) user;
852   capture_file *cf = args->cf;
853   frame_data    fdata;
854   proto_tree   *protocol_tree;
855   gboolean      passed;
856   print_args_t print_args;
857
858   cf->count++;
859
860   fill_in_fdata(&fdata, cf, phdr, offset);
861
862   passed = TRUE;
863   if (cf->rfcode || verbose)
864     protocol_tree = proto_tree_create_root();
865   else
866     protocol_tree = NULL;
867   dissect_packet(buf, &fdata, protocol_tree);
868   if (cf->rfcode)
869     passed = dfilter_apply(cf->rfcode, protocol_tree, buf);
870   if (passed) {
871     /* The packet passed the read filter. */
872     if (verbose) {
873       /* Print the information in the protocol tree. */
874       print_args.to_file = TRUE;
875       print_args.format = PR_FMT_TEXT;
876       print_args.print_summary = FALSE;
877       print_args.print_hex = print_hex;
878       print_args.expand_all = TRUE;
879       proto_tree_print(FALSE, &print_args, (GNode *)protocol_tree,
880                         buf, &fdata, stdout);
881       if (!print_hex) {
882         /* "print_hex_data()" will put out a leading blank line, as well
883            as a trailing one; print one here, to separate the packets,
884            only if "print_hex_data()" won't be called. */
885         printf("\n");
886       }
887     } else {
888       /* Just fill in the columns. */
889       fill_in_columns(&fdata);
890       if (cf->iface == NULL) {
891          printf("%3s %10s %12s -> %-12s %s %s\n",
892                   col_info(&fdata, COL_NUMBER),
893                   col_info(&fdata, COL_CLS_TIME),
894                   col_info(&fdata, COL_DEF_SRC),
895                   col_info(&fdata, COL_DEF_DST),
896                   col_info(&fdata, COL_PROTOCOL),
897                   col_info(&fdata, COL_INFO));
898       } else {
899         printf("%12s -> %-12s %s %s\n",
900                   col_info(&fdata, COL_DEF_SRC),
901                   col_info(&fdata, COL_DEF_DST),
902                   col_info(&fdata, COL_PROTOCOL),
903                   col_info(&fdata, COL_INFO));
904       }
905     }
906     if (print_hex) {
907       print_hex_data(stdout, print_args.format, buf,
908                         fdata.cap_len, fdata.flags.encoding);
909       printf("\n");
910     }
911     fdata.cinfo = NULL;
912   }
913   if (protocol_tree != NULL)
914     proto_tree_free(protocol_tree);
915 }
916
917 char *
918 file_open_error_message(int err, int for_writing)
919 {
920   char *errmsg;
921   static char errmsg_errno[1024+1];
922
923   switch (err) {
924
925   case WTAP_ERR_NOT_REGULAR_FILE:
926     errmsg = "The file \"%s\" is invalid.";
927     break;
928
929   case WTAP_ERR_FILE_UNKNOWN_FORMAT:
930   case WTAP_ERR_UNSUPPORTED:
931     /* Seen only when opening a capture file for reading. */
932     errmsg = "The file \"%s\" is not a capture file in a format Tethereal understands.";
933     break;
934
935   case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
936     /* Seen only when opening a capture file for writing. */
937     errmsg = "Tethereal does not support writing capture files in that format.";
938     break;
939
940   case WTAP_ERR_UNSUPPORTED_ENCAP:
941   case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
942     if (for_writing)
943       errmsg = "Tethereal cannot save this capture in that format.";
944     else
945       errmsg = "The file \"%s\" is a capture for a network type that Tethereal doesn't support.";
946     break;
947
948   case WTAP_ERR_BAD_RECORD:
949     errmsg = "The file \"%s\" appears to be damaged or corrupt.";
950     break;
951
952   case WTAP_ERR_CANT_OPEN:
953     if (for_writing)
954       errmsg = "The file \"%s\" could not be created for some unknown reason.";
955     else
956       errmsg = "The file \"%s\" could not be opened for some unknown reason.";
957     break;
958
959   case WTAP_ERR_SHORT_READ:
960     errmsg = "The file \"%s\" appears to have been cut short"
961              " in the middle of a packet.";
962     break;
963
964   case WTAP_ERR_SHORT_WRITE:
965     errmsg = "A full header couldn't be written to the file \"%s\".";
966     break;
967
968   case ENOENT:
969     if (for_writing)
970       errmsg = "The path to the file \"%s\" does not exist.";
971     else
972       errmsg = "The file \"%s\" does not exist.";
973     break;
974
975   case EACCES:
976     if (for_writing)
977       errmsg = "You do not have permission to create or write to the file \"%s\".";
978     else
979       errmsg = "You do not have permission to read the file \"%s\".";
980     break;
981
982   default:
983     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
984                                 wtap_strerror(err));
985     errmsg = errmsg_errno;
986     break;
987   }
988   return errmsg;
989 }
990
991 int
992 open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
993 {
994   wtap       *wth;
995   int         err;
996   FILE_T      fh;
997   int         fd;
998   struct stat cf_stat;
999   char        err_msg[2048+1];
1000
1001   wth = wtap_open_offline(fname, &err);
1002   if (wth == NULL)
1003     goto fail;
1004
1005   /* Find the size of the file. */
1006   fh = wtap_file(wth);
1007   fd = wtap_fd(wth);
1008   if (fstat(fd, &cf_stat) < 0) {
1009     err = errno;
1010     wtap_close(wth);
1011     goto fail;
1012   }
1013
1014   /* The open succeeded.  Fill in the information for this file. */
1015
1016   /* Initialize the table of conversations. */
1017   conversation_init();
1018
1019   /* Initialize protocol-specific variables */
1020   init_all_protocols();
1021
1022   cf->wth = wth;
1023   cf->fh = fh;
1024   cf->filed = fd;
1025   cf->f_len = cf_stat.st_size;
1026
1027   /* Set the file name because we need it to set the follow stream filter.
1028      XXX - is that still true?  We need it for other reasons, though,
1029      in any case. */
1030   cf->filename = g_strdup(fname);
1031
1032   /* Indicate whether it's a permanent or temporary file. */
1033   cf->is_tempfile = is_tempfile;
1034
1035   /* If it's a temporary capture buffer file, mark it as not saved. */
1036   cf->user_saved = !is_tempfile;
1037
1038   cf->cd_t      = wtap_file_type(cf->wth);
1039   cf->count     = 0;
1040   cf->drops     = 0;
1041   cf->esec      = 0;
1042   cf->eusec     = 0;
1043   cf->snap      = wtap_snapshot_length(cf->wth);
1044   cf->update_progbar = FALSE;
1045   cf->progbar_quantum = 0;
1046   cf->progbar_nextstep = 0;
1047   firstsec = 0, firstusec = 0;
1048   prevsec = 0, prevusec = 0;
1049  
1050   return (0);
1051
1052 fail:
1053   snprintf(err_msg, sizeof err_msg, file_open_error_message(err, FALSE), fname);
1054   fprintf(stderr, "tethereal: %s\n", err_msg);
1055   return (err);
1056 }
1057
1058 /* Get the text in a given column */
1059 static gchar *
1060 col_info(frame_data *fd, gint el) {
1061   int i;
1062   
1063   if (fd->cinfo) {
1064     for (i = 0; i < fd->cinfo->num_cols; i++) {
1065       if (fd->cinfo->fmt_matx[i][el])
1066         return fd->cinfo->col_data[i];
1067     }
1068   }
1069   return NULL;
1070 }