Added and extended Santeri Paavolainen's <santtu@ssh.fi> patch
[obnox/wireshark/wip.git] / file.c
1 /* file.c
2  * File I/O routines
3  *
4  * $Id: file.c,v 1.99 1999/09/29 14:41:34 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31
32 #include <stdio.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <time.h>
39
40 #ifdef HAVE_IO_H
41 #include <io.h>
42 #endif
43
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/stat.h>
47 #include <errno.h>
48 #include <fcntl.h>
49
50 #ifdef NEED_SNPRINTF_H
51 # ifdef HAVE_STDARG_H
52 #  include <stdarg.h>
53 # else
54 #  include <varargs.h>
55 # endif
56 # include "snprintf.h"
57 #endif
58
59 #ifdef NEED_STRERROR_H
60 #include "strerror.h"
61 #endif
62
63 #ifdef HAVE_SYS_TYPES_H
64 # include <sys/types.h>
65 #endif
66
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
69 #endif
70
71 #include "gtk/main.h"
72 #include "column.h"
73 #include "gtk/menu.h"
74 #include "packet.h"
75 #include "print.h"
76 #include "file.h"
77 #include "util.h"
78 #include "gtk/proto_draw.h"
79 #include "dfilter.h"
80 #include "timestamp.h"
81
82 #include "packet-ncp.h"
83
84 extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
85 extern guint      file_ctx;
86 extern int        sync_pipe[];
87
88 guint cap_input_id;
89 gboolean auto_scroll_live = FALSE;
90
91 static guint32 firstsec, firstusec;
92 static guint32 prevsec, prevusec;
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 /* Update the progress bar this many times when reading a file. */
101 #define N_PROGBAR_UPDATES       100
102
103 int
104 open_cap_file(char *fname, capture_file *cf) {
105   wtap       *wth;
106   int         err;
107   FILE_T      fh;
108   int         fd;
109   struct stat cf_stat;
110
111   wth = wtap_open_offline(fname, &err);
112   if (wth == NULL)
113     goto fail;
114
115   /* Find the size of the file. */
116   fh = wtap_file(wth);
117   fd = wtap_fd(wth);
118   if (fstat(fd, &cf_stat) < 0) {
119     err = errno;
120     wtap_close(wth);
121     goto fail;
122   }
123
124   /* The open succeeded.  Close whatever capture file we had open,
125      and fill in the information for this file. */
126   close_cap_file(cf, info_bar, file_ctx);
127
128   /* Initialize protocol-specific variables */
129   ncp_init_protocol();
130
131   cf->wth = wth;
132   cf->fh = fh;
133   cf->filed = fd;
134   cf->f_len = cf_stat.st_size;
135
136   /* set the file name because we need it to set the follow stream filter */
137   cf->filename = g_strdup(fname);
138
139   cf->cd_t      = wtap_file_type(cf->wth);
140   cf->cd_t_desc = wtap_file_type_string(cf->wth);
141   cf->count     = 0;
142   cf->drops     = 0;
143   cf->esec      = 0;
144   cf->eusec     = 0;
145   cf->snap      = wtap_snapshot_length(cf->wth);
146   cf->update_progbar = FALSE;
147   cf->progbar_quantum = 0;
148   cf->progbar_nextstep = 0;
149   firstsec = 0, firstusec = 0;
150   prevsec = 0, prevusec = 0;
151  
152   return (0);
153
154 fail:
155   simple_dialog(ESD_TYPE_WARN, NULL,
156                         file_open_error_message(err, FALSE), fname);
157   return (err);
158 }
159
160 /* Reset everything to a pristine state */
161 void
162 close_cap_file(capture_file *cf, void *w, guint context) {
163   frame_data *fd, *fd_next;
164
165   if (cf->fh) {
166     file_close(cf->fh);
167     cf->fh = NULL;
168   }
169   if (cf->wth) {
170     wtap_close(cf->wth);
171     cf->wth = NULL;
172   }
173   for (fd = cf->plist; fd != NULL; fd = fd_next) {
174     fd_next = fd->next;
175     g_free(fd);
176   }
177   if (cf->rfcode != NULL) {
178     dfilter_destroy(cf->rfcode);
179     cf->rfcode = NULL;
180   }
181   cf->plist = NULL;
182   cf->plist_end = NULL;
183   unselect_packet(cf);  /* nothing to select */
184
185   gtk_clist_freeze(GTK_CLIST(packet_list));
186   gtk_clist_clear(GTK_CLIST(packet_list));
187   gtk_clist_thaw(GTK_CLIST(packet_list));
188   gtk_statusbar_pop(GTK_STATUSBAR(w), context);
189
190   /* Disable all menu items that make sense only if you have a capture. */
191   set_menu_sensitivity("/File/Save", FALSE);
192   set_menu_sensitivity("/File/Save As...", FALSE);
193   set_menu_sensitivity("/File/Close", FALSE);
194   set_menu_sensitivity("/File/Reload", FALSE);
195   set_menu_sensitivity("/File/Print...", FALSE);
196   set_menu_sensitivity("/Display/Options...", FALSE);
197   set_menu_sensitivity("/Tools/Summary", FALSE);
198 }
199
200 int
201 read_cap_file(capture_file *cf) {
202   gchar  *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
203   gchar  *done_fmt = " File: %s  Drops: %d";
204   int     success;
205   int     err;
206   size_t  msg_len;
207   char   *errmsg;
208   char    errmsg_errno[1024+1];
209   gchar   err_str[2048+1];
210
211   if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
212     name_ptr = cf->filename;
213   else
214     name_ptr++;
215
216   load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
217   sprintf(load_msg, load_fmt, name_ptr);
218   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
219
220   cf->update_progbar = TRUE;
221   /* Update the progress bar when it gets to this value. */
222   cf->progbar_nextstep = 0;
223   /* When we reach the value that triggers a progress bar update,
224      bump that value by this amount. */
225   cf->progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
226
227   freeze_clist(cf);
228   proto_tree_is_visible = FALSE;
229   success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
230   wtap_close(cf->wth);
231   cf->wth = NULL;
232   cf->filed = open(cf->filename, O_RDONLY);
233   cf->fh = filed_open(cf->filed, "r");
234   cf->unfiltered_count = cf->count;
235   thaw_clist(cf);
236
237   gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
238   gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
239
240   gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
241
242   msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
243   load_msg = g_realloc(load_msg, msg_len);
244
245   if (cf->user_saved || !cf->save_file)
246     snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
247   else
248     snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
249
250   gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
251   g_free(load_msg);
252
253   /* Enable menu items that make sense if you have a capture. */
254   set_menu_sensitivity("/File/Close", TRUE);
255   set_menu_sensitivity("/File/Reload", TRUE);
256   set_menu_sensitivity("/File/Print...", TRUE);
257   set_menu_sensitivity("/Display/Options...", TRUE);
258   set_menu_sensitivity("/Tools/Summary", TRUE);
259
260   if (!success) {
261     /* Put up a message box noting that the read failed somewhere along
262        the line.  Don't throw out the stuff we managed to read, though,
263        if any. */
264     switch (err) {
265
266     case WTAP_ERR_CANT_READ:
267       errmsg = "An attempt to read from the file failed for"
268                " some unknown reason.";
269       break;
270
271     case WTAP_ERR_SHORT_READ:
272       errmsg = "The capture file appears to have been cut short"
273                " in the middle of a packet.";
274       break;
275
276     case WTAP_ERR_BAD_RECORD:
277       errmsg = "The capture file appears to be damaged or corrupt.";
278       break;
279
280     default:
281       sprintf(errmsg_errno, "An error occurred while reading the"
282                               " capture file: %s.", wtap_strerror(err));
283       errmsg = errmsg_errno;
284       break;
285     }
286     snprintf(err_str, sizeof err_str, errmsg);
287     simple_dialog(ESD_TYPE_WARN, NULL, err_str);
288     return (err);
289   } else
290     return (0);
291 }
292
293 #ifdef HAVE_LIBPCAP
294 void 
295 cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
296   
297   capture_file *cf = (capture_file *)data;
298   char buffer[256+1], *p = buffer, *q = buffer;
299   int  nread;
300   int  to_read = 0;
301   gboolean exit_loop = FALSE;
302   int  err;
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     /* XXX - do something if this fails? */
315     wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
316
317     thaw_clist(cf);
318     if (auto_scroll_live)
319       gtk_clist_moveto(GTK_CLIST(packet_list), 
320                        cf->plist_end->row, -1, 1.0, 1.0);
321
322     wtap_close(cf->wth);
323     cf->wth = NULL;
324     set_menu_sensitivity("/File/Open...", TRUE);
325     set_menu_sensitivity("/File/Close", TRUE);
326     set_menu_sensitivity("/File/Save As...", TRUE);
327     set_menu_sensitivity("/File/Print...", TRUE);
328     set_menu_sensitivity("/File/Reload", TRUE);
329     set_menu_sensitivity("/Capture/Start...", TRUE);
330     set_menu_sensitivity("/Tools/Summary", TRUE);
331     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
332     return;
333   }
334
335   buffer[nread] = '\0';
336
337   while(!exit_loop) {
338     /* look for (possibly multiple) '*' */
339     switch (*q) {
340     case '*' :
341       to_read += atoi(p);
342       p = q + 1; 
343       q++;
344       break;
345     case '\0' :
346       /* XXX should handle the case of a pipe full (i.e. no star found) */
347       exit_loop = TRUE;
348       break;
349     default :
350       q++;
351       break;
352     } 
353   }
354
355   gtk_clist_freeze(GTK_CLIST(packet_list));
356   /* XXX - do something if this fails? */
357   wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
358   gtk_clist_thaw(GTK_CLIST(packet_list));
359   if (auto_scroll_live)
360     gtk_clist_moveto(GTK_CLIST(packet_list), cf->plist_end->row, -1, 1.0, 1.0);
361
362   /* restore pipe handler */
363   cap_input_id = gtk_input_add_full (sync_pipe[0],
364                                      GDK_INPUT_READ,
365                                      cap_file_input_cb,
366                                      NULL,
367                                      (gpointer) cf,
368                                      NULL);
369 }
370
371 int
372 tail_cap_file(char *fname, capture_file *cf) {
373   int     err;
374   int     i;
375
376   err = open_cap_file(fname, cf);
377   if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
378
379     set_menu_sensitivity("/File/Open...", FALSE);
380     set_menu_sensitivity("/Display/Options...", TRUE);
381     set_menu_sensitivity("/Capture/Start...", FALSE);
382
383     for (i = 0; i < cf->cinfo.num_cols; i++) {
384       if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
385         gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
386       else {
387         gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
388         gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
389                                 cf->cinfo.col_width[i]);
390         gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
391       }
392     }
393
394     cf->fh = file_open(fname, "r");
395
396     cap_input_id = gtk_input_add_full (sync_pipe[0],
397                                        GDK_INPUT_READ,
398                                        cap_file_input_cb,
399                                        NULL,
400                                        (gpointer) cf,
401                                        NULL);
402     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, 
403                        " <live capture in progress>");
404   }
405   else {
406     close(sync_pipe[0]);
407   }
408   return err;
409 }
410 #endif /* HAVE_LIBPCAP */
411
412 /* To do: Add check_col checks to the col_add* routines */
413
414 static void
415 col_add_abs_time(frame_data *fd, gint el)
416 {
417   struct tm *tmp;
418   time_t then;
419
420   then = fd->abs_secs;
421   tmp = localtime(&then);
422   col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
423     tmp->tm_hour,
424     tmp->tm_min,
425     tmp->tm_sec,
426     (long)fd->abs_usecs/100);
427 }
428
429 static void
430 col_add_rel_time(frame_data *fd, gint el)
431 {
432   col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
433 }
434
435 static void
436 col_add_delta_time(frame_data *fd, gint el)
437 {
438   col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
439 }
440
441 /* Add "command-line-specified" time. */
442 static void
443 col_add_cls_time(frame_data *fd)
444 {
445   switch (timestamp_type) {
446     case ABSOLUTE:
447       col_add_abs_time(fd, COL_CLS_TIME);
448       break;
449
450     case RELATIVE:
451       col_add_rel_time(fd, COL_CLS_TIME);
452       break;
453
454     case DELTA:
455       col_add_delta_time(fd, COL_CLS_TIME);
456       break;
457   }
458 }
459
460 static void
461 fill_in_columns(frame_data *fd)
462 {
463   if (check_col(fd, COL_NUMBER))
464     col_add_fstr(fd, COL_NUMBER, "%u", fd->num);
465
466   /* Set any time stamp columns. */
467   if (check_col(fd, COL_CLS_TIME))
468     col_add_cls_time(fd);
469   if (check_col(fd, COL_ABS_TIME))
470     col_add_abs_time(fd, COL_ABS_TIME);
471   if (check_col(fd, COL_REL_TIME))
472     col_add_rel_time(fd, COL_REL_TIME);
473   if (check_col(fd, COL_DELTA_TIME))
474     col_add_delta_time(fd, COL_DELTA_TIME);
475
476   if (check_col(fd, COL_PACKET_LENGTH))
477     col_add_fstr(fd, COL_PACKET_LENGTH, "%d", fd->pkt_len);
478 }
479
480 static void
481 add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf)
482 {
483   gint          i, row;
484   gint          crow;
485   gint          color;
486   proto_tree   *protocol_tree;
487
488   fdata->num = cf->count;
489
490   /* If we don't have the time stamp of the first packet in the
491      capture, it's because this is the first packet.  Save the time
492      stamp of this packet as the time stamp of the first packet. */
493   if (!firstsec && !firstusec) {
494     firstsec  = fdata->abs_secs;
495     firstusec = fdata->abs_usecs;
496   }
497
498   /* Get the time elapsed between the first packet and this packet. */
499   cf->esec = fdata->abs_secs - firstsec;
500   if (firstusec <= fdata->abs_usecs) {
501     cf->eusec = fdata->abs_usecs - firstusec;
502   } else {
503     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
504     cf->esec--;
505   }
506
507   fdata->cinfo = &cf->cinfo;
508   for (i = 0; i < fdata->cinfo->num_cols; i++) {
509     fdata->cinfo->col_data[i][0] = '\0';
510   }
511
512   /* Apply the filters */
513   if (DFILTER_CONTAINS_FILTER(cf->dfcode) ||
514       CFILTERS_CONTAINS_FILTER(cf)) {
515         protocol_tree = proto_tree_create_root();
516         dissect_packet(buf, fdata, protocol_tree);
517         if( DFILTER_CONTAINS_FILTER(cf->dfcode) )
518                 fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
519         else
520                 fdata->passed_dfilter = TRUE;
521         /* Apply color filters. */
522         color = -1;
523         for(crow = 0; cf->colors->num_of_filters && 
524               crow < cf->colors->num_of_filters; crow++) {
525
526             if(color_filter(cf,crow)->c_colorfilter == NULL) {
527                 continue;
528             }
529             if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
530                  cf->pd)){
531                 color = crow;
532                 break;
533             }
534         }
535
536         proto_tree_free(protocol_tree);
537   }
538   else {
539         dissect_packet(buf, fdata, NULL);
540         fdata->passed_dfilter = TRUE;
541         color = -1;
542   }
543   if (fdata->passed_dfilter) {
544     /* If we don't have the time stamp of the previous displayed packet,
545        it's because this is the first displayed packet.  Save the time
546        stamp of this packet as the time stamp of the previous displayed
547        packet. */
548     if (!prevsec && !prevusec) {
549       prevsec  = fdata->abs_secs;
550       prevusec = fdata->abs_usecs;
551     }
552
553     /* Get the time elapsed between the first packet and this packet. */
554     fdata->rel_secs = cf->esec;
555     fdata->rel_usecs = cf->eusec;
556   
557     /* Get the time elapsed between the previous displayed packet and
558        this packet. */
559     fdata->del_secs = fdata->abs_secs - prevsec;
560     if (prevusec <= fdata->abs_usecs) {
561       fdata->del_usecs = fdata->abs_usecs - prevusec;
562     } else {
563       fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
564       fdata->del_secs--;
565     }
566     prevsec = fdata->abs_secs;
567     prevusec = fdata->abs_usecs;
568
569     fill_in_columns(fdata);
570
571     row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
572     fdata->row = row;
573
574     if (cf->colors->color_filters && (color != -1)){
575         gtk_clist_set_background(GTK_CLIST(packet_list), row,
576                    &(color_filter(cf,color)->bg_color));
577         gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
578                    &(color_filter(cf,color)->fg_color));
579     } else {
580         gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
581         gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
582     }
583
584     /* If this was the selected packet, remember the row it's in, so
585        we can re-select it.  ("selected_packet" is 0-origin, as it's
586        a GList index; "num", however, is 1-origin.) */
587     if (cf->selected_packet == fdata->num - 1)
588       cf->selected_row = row;
589   } else
590     fdata->row = -1;    /* not in the display */
591   fdata->cinfo = NULL;
592 }
593
594 static void
595 wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
596   const u_char *buf) {
597   frame_data   *fdata;
598   capture_file *cf = (capture_file *) user;
599   int           passed;
600   proto_tree   *protocol_tree;
601   frame_data   *plist_end;
602   int file_pos;
603   float prog_val;
604
605   /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
606      when we update it, we have to run the GTK+ main loop to get it
607      to repaint what's pending, and doing so may involve an "ioctl()"
608      to see if there's any pending input from an X server, and doing
609      that for every packet can be costly, especially on a big file.
610      
611      Do so only if we were told to do so; when reading a capture file
612      being updated by a live capture, we don't do so (as we're not
613      "done" until the capture stops, so we don't know how close to
614      "done" we are. */
615
616   if (cf->update_progbar && offset >= cf->progbar_nextstep) {
617       file_pos = lseek(cf->filed, 0, SEEK_CUR);
618       prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
619       gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), prog_val);
620       cf->progbar_nextstep += cf->progbar_quantum;
621       while (gtk_events_pending())
622       gtk_main_iteration();
623   }
624
625   /* Allocate the next list entry, and add it to the list. */
626   fdata = (frame_data *) g_malloc(sizeof(frame_data));
627
628   fdata->next = NULL;
629   fdata->pkt_len  = phdr->len;
630   fdata->cap_len  = phdr->caplen;
631   fdata->file_off = offset;
632   fdata->lnk_t = phdr->pkt_encap;
633   fdata->abs_secs  = phdr->ts.tv_sec;
634   fdata->abs_usecs = phdr->ts.tv_usec;
635   fdata->pseudo_header = phdr->pseudo_header;
636   fdata->cinfo = NULL;
637
638   passed = TRUE;
639   if (cf->rfcode) {
640           if (DFILTER_CONTAINS_FILTER(cf->rfcode)) {
641             protocol_tree = proto_tree_create_root();
642             dissect_packet(buf, fdata, protocol_tree);
643             passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
644             proto_tree_free(protocol_tree);
645           }
646   }   
647   if (passed) {
648     plist_end = cf->plist_end;
649     if (plist_end != NULL)
650       plist_end->next = fdata;
651     else
652       cf->plist = fdata;
653     cf->plist_end = fdata;
654
655     cf->count++;
656     add_packet_to_packet_list(fdata, cf, buf);
657   } else
658     g_free(fdata);
659 }
660
661 void
662 filter_packets(capture_file *cf)
663 {
664   frame_data *fd;
665   guint32 progbar_quantum;
666   guint32 progbar_nextstep;
667
668   if (cf->dfilter == NULL) {
669         dfilter_clear_filter(cf->dfcode);
670   }
671   else {
672     /*
673      * Compile the filter.
674      */
675     if (dfilter_compile(cf->dfcode, cf->dfilter) != 0) {
676       simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
677       return;
678     }
679   }
680
681   gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
682
683   /* Freeze the packet list while we redo it, so we don't get any
684      screen updates while it happens. */
685   gtk_clist_freeze(GTK_CLIST(packet_list));
686
687   /* Clear it out. */
688   gtk_clist_clear(GTK_CLIST(packet_list));
689
690   /* If a packet was selected, we don't know yet what row, if any, it'll
691      get. */
692   cf->selected_row = -1;
693
694   /* Iterate through the list of packets, calling a routine
695      to run the filter on the packet, see if it matches, and
696      put it in the display list if so.  */
697   firstsec = 0;
698   firstusec = 0;
699   prevsec = 0;
700   prevusec = 0;
701   cf->unfiltered_count = cf->count;
702   cf->count = 0;
703
704   proto_tree_is_visible = FALSE;
705
706   /* Update the progress bar when it gets to this value. */
707   progbar_nextstep = 0;
708   /* When we reach the value that triggers a progress bar update,
709      bump that value by this amount. */
710   progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
711   gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
712
713   for (fd = cf->plist; fd != NULL; fd = fd->next) {
714     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
715        when we update it, we have to run the GTK+ main loop to get it
716        to repaint what's pending, and doing so may involve an "ioctl()"
717        to see if there's any pending input from an X server, and doing
718        that for every packet can be costly, especially on a big file. */
719     if (cf->count >= progbar_nextstep) {
720       /* let's not divide by zero. I should never be started
721        * with unfiltered_count == 0, so let's assert that
722        */
723       g_assert(cf->unfiltered_count > 0);
724
725         gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
726                 (gfloat) cf->count / cf->unfiltered_count);
727
728       progbar_nextstep += progbar_quantum;
729       while (gtk_events_pending())
730         gtk_main_iteration();
731     }
732
733     cf->count++;
734
735     wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
736
737     add_packet_to_packet_list(fd, cf, cf->pd);
738   }
739  
740   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
741
742   if (cf->selected_row != -1) {
743     /* We had a selected packet and it passed the filter. */
744     gtk_clist_select_row(GTK_CLIST(packet_list), cf->selected_row, -1);
745   } else {
746     /* If we had one, it didn't pass the filter. */
747     unselect_packet(cf);
748   }
749
750   /* Unfreeze the packet list. */
751   gtk_clist_thaw(GTK_CLIST(packet_list));
752 }
753
754 int
755 print_packets(capture_file *cf, print_args_t *print_args)
756 {
757   int         i;
758   frame_data *fd;
759   guint32     progbar_quantum;
760   guint32     progbar_nextstep;
761   guint32     count;
762   proto_tree *protocol_tree;
763   gint       *col_widths = NULL;
764   gint        data_width;
765   gboolean    print_separator;
766
767   cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
768   if (cf->print_fh == NULL)
769     return FALSE;       /* attempt to open destination failed */
770
771   /* XXX - printing multiple frames in PostScript looks as if it's
772      tricky - you have to deal with page boundaries, I think -
773      and I'll have to spend some time learning enough about
774      PostScript to figure it out, so, for now, we only print
775      multiple frames as text. */
776 #if 0
777   print_preamble(cf->print_fh);
778 #endif
779
780   if (print_args->print_summary) {
781     /* We're printing packet summaries.
782
783        Find the widths for each of the columns - maximum of the
784        width of the title and the width of the data - and print
785        the column titles. */
786     col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
787     for (i = 0; i < cf->cinfo.num_cols; i++) {
788       /* Don't pad the last column. */
789       if (i == cf->cinfo.num_cols - 1)
790         col_widths[i] = 0;
791       else {
792         col_widths[i] = strlen(cf->cinfo.col_title[i]);
793         data_width = get_column_char_width(get_column_format(i));
794         if (data_width > col_widths[i])
795           col_widths[i] = data_width;
796       }
797
798       /* Right-justify the packet number column. */
799       if (cf->cinfo.col_fmt[i] == COL_NUMBER)
800         fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_title[i]);
801       else
802         fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_title[i]);
803       if (i == cf->cinfo.num_cols - 1)
804         fputc('\n', cf->print_fh);
805       else
806         fputc(' ', cf->print_fh);
807     }
808   }
809
810   print_separator = FALSE;
811   proto_tree_is_visible = TRUE;
812
813   /* Update the progress bar when it gets to this value. */
814   progbar_nextstep = 0;
815   /* When we reach the value that triggers a progress bar update,
816      bump that value by this amount. */
817   progbar_quantum = cf->unfiltered_count/N_PROGBAR_UPDATES;
818   /* Count of packets we've looked at. */
819   count = 0;
820
821   /* Iterate through the list of packets, printing the packets that
822      were selected by the current display filter.  */
823   for (fd = cf->plist; fd != NULL; fd = fd->next) {
824     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
825        when we update it, we have to run the GTK+ main loop to get it
826        to repaint what's pending, and doing so may involve an "ioctl()"
827        to see if there's any pending input from an X server, and doing
828        that for every packet can be costly, especially on a big file. */
829     if (count >= progbar_nextstep) {
830       /* let's not divide by zero. I should never be started
831        * with unfiltered_count == 0, so let's assert that
832        */
833       g_assert(cf->unfiltered_count > 0);
834
835       gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
836         (gfloat) count / cf->unfiltered_count);
837       progbar_nextstep += progbar_quantum;
838       while (gtk_events_pending())
839         gtk_main_iteration();
840     }
841     count++;
842
843     if (fd->passed_dfilter) {
844       wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
845       if (print_args->print_summary) {
846         /* Fill in the column information, but don't bother creating
847            the logical protocol tree. */
848         fd->cinfo = &cf->cinfo;
849         for (i = 0; i < fd->cinfo->num_cols; i++) {
850           fd->cinfo->col_data[i][0] = '\0';
851         }
852         dissect_packet(cf->pd, fd, NULL);
853         fill_in_columns(fd);
854         for (i = 0; i < cf->cinfo.num_cols; i++) {
855           /* Right-justify the packet number column. */
856           if (cf->cinfo.col_fmt[i] == COL_NUMBER)
857             fprintf(cf->print_fh, "%*s", col_widths[i], cf->cinfo.col_data[i]);
858           else
859             fprintf(cf->print_fh, "%-*s", col_widths[i], cf->cinfo.col_data[i]);
860           if (i == cf->cinfo.num_cols - 1)
861             fputc('\n', cf->print_fh);
862           else
863             fputc(' ', cf->print_fh);
864         }
865       } else {
866         if (print_separator)
867           fputc('\n', cf->print_fh);
868
869         /* Create the logical protocol tree. */
870         protocol_tree = proto_tree_create_root();
871         dissect_packet(cf->pd, fd, protocol_tree);
872
873         /* Print the information in that tree. */
874         proto_tree_print(FALSE, print_args->expand_all, (GNode *)protocol_tree,
875                         cf->pd, fd, cf->print_fh);
876
877         proto_tree_free(protocol_tree);
878
879         /* Print a blank line if we print anything after this. */
880         print_separator = TRUE;
881       }
882     }
883   }
884
885   if (col_widths != NULL)
886     g_free(col_widths);
887
888 #if 0
889   print_finale(cf->print_fh);
890 #endif
891
892   close_print_dest(print_args->to_file, cf->print_fh);
893  
894   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
895
896   cf->print_fh = NULL;
897   return TRUE;
898 }
899
900 /* Scan through the packet list and change all columns that use the
901    "command-line-specified" time stamp format to use the current
902    value of that format. */
903 void
904 change_time_formats(capture_file *cf)
905 {
906   frame_data *fd;
907   int i;
908   GtkStyle  *pl_style;
909
910   /* Freeze the packet list while we redo it, so we don't get any
911      screen updates while it happens. */
912   freeze_clist(cf);
913
914   /* Iterate through the list of packets, checking whether the packet
915      is in a row of the summary list and, if so, whether there are
916      any columns that show the time in the "command-line-specified"
917      format and, if so, update that row. */
918   for (fd = cf->plist; fd != NULL; fd = fd->next) {
919     if (fd->row != -1) {
920       /* This packet is in the summary list, on row "fd->row". */
921
922       /* XXX - there really should be a way of checking "cf->cinfo" for this;
923          the answer isn't going to change from packet to packet, so we should
924          simply skip all the "change_time_formats()" work if we're not
925          changing anything. */
926       fd->cinfo = &cf->cinfo;
927       if (check_col(fd, COL_CLS_TIME)) {
928         /* There are columns that show the time in the "command-line-specified"
929            format; update them. */
930         for (i = 0; i < cf->cinfo.num_cols; i++) {
931           cf->cinfo.col_data[i][0] = '\0';
932         }
933         col_add_cls_time(fd);
934         for (i = 0; i < cf->cinfo.num_cols; i++) {
935           if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
936             /* This is one of the columns that shows the time in
937                "command-line-specified" format; update it. */
938             gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
939                           cf->cinfo.col_data[i]);
940           }
941         }
942       }
943     }
944   }
945
946   /* Set the column widths of those columns that show the time in
947      "command-line-specified" format. */
948   pl_style = gtk_widget_get_style(packet_list);
949   for (i = 0; i < cf->cinfo.num_cols; i++) {
950     if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
951       gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
952         get_column_width(COL_CLS_TIME, pl_style->font));
953     }
954   }
955
956   /* Unfreeze the packet list. */
957   thaw_clist(cf);
958 }
959
960 static void
961 clear_tree_and_hex_views(void)
962 {
963   GList *selection;
964   GtkWidget *tmp_item;
965
966   /* Clear the hex dump. */
967   gtk_text_freeze(GTK_TEXT(byte_view));
968   gtk_text_set_point(GTK_TEXT(byte_view), 0);
969   gtk_text_forward_delete(GTK_TEXT(byte_view),
970     gtk_text_get_length(GTK_TEXT(byte_view)));
971   gtk_text_thaw(GTK_TEXT(byte_view));
972
973   /* Deselect any selected tree item. gtktree.c should
974    * do this when we clear_items, but it doesn't. I copied
975    * this while() loop from gtktree.c, gtk_real_tree_select_child()
976    */
977   if (GTK_TREE(tree_view)->root_tree) {
978           selection = GTK_TREE(tree_view)->root_tree->selection;
979           while (selection) {
980                   tmp_item = selection->data;
981                   gtk_tree_item_deselect(GTK_TREE_ITEM(tmp_item));
982                   gtk_widget_unref(tmp_item);
983                   selection = selection->next;
984           }
985           g_list_free(GTK_TREE(tree_view)->root_tree->selection);
986           GTK_TREE(tree_view)->root_tree->selection = NULL;
987   }
988
989   /* Clear the protocol tree view. The length arg of -1
990    * means to clear all items up to the end. */
991   gtk_tree_clear_items(GTK_TREE(tree_view), 0, -1);
992 }
993
994
995 /* Select the packet on a given row. */
996 void
997 select_packet(capture_file *cf, int row)
998 {
999   frame_data *fd;
1000   int i;
1001
1002   /* Clear out whatever's currently in the hex dump. */
1003   gtk_text_freeze(GTK_TEXT(byte_view));
1004   gtk_text_set_point(GTK_TEXT(byte_view), 0);
1005   gtk_text_forward_delete(GTK_TEXT(byte_view),
1006     gtk_text_get_length(GTK_TEXT(byte_view)));
1007
1008   /* Search through the list of frames to see which one is in
1009      this row. */
1010   for (fd = cf->plist, i = 0; fd != NULL; fd = fd->next, i++) {
1011     if (fd->row == row)
1012       break;
1013   }
1014   cf->fd = fd;
1015
1016   /* Remember the ordinal number of that frame. */
1017   cf->selected_packet = i;
1018
1019   /* Get the data in that frame. */
1020   wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
1021
1022   /* Create the logical protocol tree. */
1023   if (cf->protocol_tree)
1024       proto_tree_free(cf->protocol_tree);
1025   cf->protocol_tree = proto_tree_create_root();
1026   proto_tree_is_visible = TRUE;
1027   dissect_packet(cf->pd, cf->fd, cf->protocol_tree);
1028
1029   /* Display the GUI protocol tree and hex dump. */
1030   clear_tree_and_hex_views();
1031   proto_tree_draw(cf->protocol_tree, tree_view);
1032   packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->fd->cap_len, -1, -1);
1033   gtk_text_thaw(GTK_TEXT(byte_view));
1034
1035   /* A packet is selected, so "File/Print Packet" has something to print. */
1036   set_menu_sensitivity("/File/Print Packet", TRUE);
1037   set_menu_sensitivity("/Display/Collapse All", TRUE);
1038   set_menu_sensitivity("/Display/Expand All", TRUE);
1039 }
1040
1041 /* Unselect the selected packet, if any. */
1042 void
1043 unselect_packet(capture_file *cf)
1044 {
1045   cf->selected_packet = -1;     /* nothing there to be selected */
1046   cf->selected_row = -1;
1047
1048   /* Destroy the protocol tree for that packet. */
1049   if (cf->protocol_tree != NULL) {
1050     proto_tree_free(cf->protocol_tree);
1051     cf->protocol_tree = NULL;
1052   }
1053
1054   /* Clear out the display of that packet. */
1055   clear_tree_and_hex_views();
1056
1057   /* No packet is selected, so "File/Print Packet" has nothing to print. */
1058   set_menu_sensitivity("/File/Print Packet", FALSE);
1059   set_menu_sensitivity("/Display/Collapse All", FALSE);
1060   set_menu_sensitivity("/Display/Expand All", FALSE);
1061 }
1062
1063 static void
1064 freeze_clist(capture_file *cf)
1065 {
1066   int i;
1067
1068   /* Make the column sizes static, so they don't adjust while
1069      we're reading the capture file (freezing the clist doesn't
1070      seem to suffice). */
1071   for (i = 0; i < cf->cinfo.num_cols; i++)
1072     gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
1073   gtk_clist_freeze(GTK_CLIST(packet_list));
1074 }
1075
1076 static void
1077 thaw_clist(capture_file *cf)
1078 {
1079   int i;
1080
1081   for (i = 0; i < cf->cinfo.num_cols; i++) {
1082     if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_MANUAL) {
1083       /* Set this column's width to the appropriate value. */
1084       gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
1085                                 cf->cinfo.col_width[i]);
1086     } else {
1087       /* Make this column's size dynamic, so that it adjusts to the
1088          appropriate size. */
1089       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1090     }
1091   }
1092   gtk_clist_thaw(GTK_CLIST(packet_list));
1093
1094   /* Hopefully, the columns have now gotten their appropriate sizes;
1095      make them resizeable - a column that auto-resizes cannot be
1096      resized by the user, and *vice versa*. */
1097   for (i = 0; i < cf->cinfo.num_cols; i++)
1098     gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
1099 }
1100
1101 /* Tries to mv a file. If unsuccessful, tries to cp the file.
1102  * Returns 0 on failure to do either, 1 on success of either
1103  */
1104 int
1105 file_mv(char *from, char *to)
1106 {
1107
1108 #define COPY_BUFFER_SIZE        8192
1109
1110         int retval;
1111
1112 #ifndef WIN32
1113         /* try a hard link */
1114         retval = link(from, to);
1115
1116         /* or try a copy */
1117         if (retval < 0) {
1118 #endif
1119                 retval = file_cp(from, to);
1120                 if (!retval) {
1121                         return 0;
1122                 }
1123 #ifndef WIN32
1124         }
1125 #endif
1126
1127         unlink(from);
1128         return 1;
1129 }
1130
1131 /* Copies a file.
1132  * Returns 0 on failure to do either, 1 on success of either
1133  */
1134 int
1135 file_cp(char *from, char *to)
1136 {
1137
1138 #define COPY_BUFFER_SIZE        8192
1139
1140         int from_fd, to_fd, nread, nwritten;
1141         char *buffer;
1142
1143         buffer = g_malloc(COPY_BUFFER_SIZE);
1144
1145         from_fd = open(from, O_RDONLY);
1146         if (from_fd < 0) {
1147                 simple_dialog(ESD_TYPE_WARN, NULL,
1148                         file_open_error_message(errno, TRUE), from);
1149                 return 0;
1150         }
1151
1152         to_fd = creat(to, 0644);
1153         if (to_fd < 0) {
1154                 simple_dialog(ESD_TYPE_WARN, NULL,
1155                         file_open_error_message(errno, TRUE), to);
1156                 close(from_fd);
1157                 return 0;
1158         }
1159
1160         while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
1161                 nwritten = write(to_fd, buffer, nread);
1162                 if (nwritten < nread) {
1163                         if (nwritten < 0) {
1164                                 simple_dialog(ESD_TYPE_WARN, NULL,
1165                                         file_write_error_message(errno), to);
1166                         } else {
1167                                 simple_dialog(ESD_TYPE_WARN, NULL,
1168 "The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
1169                                         to, nread, nwritten);
1170                         }
1171                         close(from_fd);
1172                         close(to_fd);
1173                         return 0;
1174                 }
1175         }
1176         if (nread < 0) {
1177                 simple_dialog(ESD_TYPE_WARN, NULL,
1178                         file_read_error_message(errno), from);
1179                 close(from_fd);
1180                 close(to_fd);
1181                 return 0;
1182         }
1183         close(from_fd);
1184         close(to_fd);
1185
1186         return 1;
1187 }
1188
1189 char *
1190 file_open_error_message(int err, int for_writing)
1191 {
1192   char *errmsg;
1193   static char errmsg_errno[1024+1];
1194
1195   switch (err) {
1196
1197   case WTAP_ERR_NOT_REGULAR_FILE:
1198     errmsg = "The file \"%s\" is invalid.";
1199     break;
1200
1201   case WTAP_ERR_FILE_UNKNOWN_FORMAT:
1202   case WTAP_ERR_UNSUPPORTED:
1203     errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
1204     break;
1205
1206   case WTAP_ERR_BAD_RECORD:
1207     errmsg = "The file \"%s\" appears to be damaged or corrupt.";
1208     break;
1209
1210   case WTAP_ERR_CANT_OPEN:
1211     if (for_writing)
1212       errmsg = "The file \"%s\" could not be created for some unknown reason.";
1213     else
1214       errmsg = "The file \"%s\" could not be opened for some unknown reason.";
1215     break;
1216
1217   case WTAP_ERR_SHORT_READ:
1218     errmsg = "The file \"%s\" appears to have been cut short"
1219              " in the middle of a packet.";
1220     break;
1221
1222   case ENOENT:
1223     if (for_writing)
1224       errmsg = "The path to the file \"%s\" does not exist.";
1225     else
1226       errmsg = "The file \"%s\" does not exist.";
1227     break;
1228
1229   case EACCES:
1230     if (for_writing)
1231       errmsg = "You do not have permission to create or write to the file \"%s\".";
1232     else
1233       errmsg = "You do not have permission to read the file \"%s\".";
1234     break;
1235
1236   default:
1237     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1238                                 wtap_strerror(err));
1239     errmsg = errmsg_errno;
1240     break;
1241   }
1242   return errmsg;
1243 }
1244
1245 char *
1246 file_read_error_message(int err)
1247 {
1248   static char errmsg_errno[1024+1];
1249
1250   sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
1251                                 wtap_strerror(err));
1252   return errmsg_errno;
1253 }
1254
1255 char *
1256 file_write_error_message(int err)
1257 {
1258   char *errmsg;
1259   static char errmsg_errno[1024+1];
1260
1261   switch (err) {
1262
1263   case ENOSPC:
1264     errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1265     break;
1266
1267 #ifdef EDQUOT
1268   case EDQUOT:
1269     errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1270     break;
1271 #endif
1272
1273   default:
1274     sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
1275                                 wtap_strerror(err));
1276     errmsg = errmsg_errno;
1277     break;
1278   }
1279   return errmsg;
1280 }