Put into the "Capture Preferences" dialog box a check box to control
[obnox/wireshark/wip.git] / gtk / capture_dlg.c
1 /* capture_dlg.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture_dlg.c,v 1.18 2000/01/18 09:24:57 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
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_LIBPCAP
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <gtk/gtk.h>
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #include <time.h>
43
44 #ifdef NEED_SNPRINTF_H
45 # ifdef HAVE_STDARG_H
46 #  include <stdarg.h>
47 # else
48 #  include <varargs.h>
49 # endif
50 # include "snprintf.h"
51 #endif
52
53 #include "capture.h"
54 #include "globals.h"
55 #include "main.h"
56 #include "capture_dlg.h"
57 #include "prefs_dlg.h"
58 #include "simple_dialog.h"
59 #include "util.h"
60
61 /* Capture callback data keys */
62 #define E_CAP_IFACE_KEY       "cap_iface"
63 #define E_CAP_FILT_KEY        "cap_filter_te"
64 #define E_CAP_FILE_TE_KEY     "cap_file_te"
65 #define E_CAP_COUNT_KEY       "cap_count"
66 #define E_CAP_SNAP_KEY        "cap_snap"
67 #define E_CAP_SYNC_KEY        "cap_sync"
68 #define E_CAP_AUTO_SCROLL_KEY "cap_auto_scroll"
69 #define E_CAP_RESOLVE_KEY     "cap_resolve"
70
71 static void
72 capture_prep_file_cb(GtkWidget *w, gpointer te);
73
74 static void
75 cap_prep_fs_ok_cb(GtkWidget *w, gpointer data);
76
77 static void
78 cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data);
79
80 static void
81 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
82
83 static void
84 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w);
85
86 void
87 capture_prep_cb(GtkWidget *w, gpointer d)
88 {
89   GtkWidget     *cap_open_w, *if_cb, *if_lb,
90                 *count_lb, *count_cb, *main_vb, *if_hb, *count_hb,
91                 *filter_hb, *filter_bt, *filter_te,
92                 *file_hb, *file_bt, *file_te,
93                 *caplen_hb,
94                 *bbox, *ok_bt, *cancel_bt, *snap_lb,
95                 *snap_sb, *sync_cb, *auto_scroll_cb, *resolv_cb;
96   GtkAdjustment *adj;
97   GList         *if_list, *count_list = NULL;
98   gchar         *count_item1 = "0 (Infinite)", count_item2[16];
99   int           err;
100   char          err_str[PCAP_ERRBUF_SIZE];
101
102   if_list = get_interface_list(&err, err_str);
103   if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
104     simple_dialog(ESD_TYPE_WARN, NULL, "Can't get list of interfaces: %s",
105                         err_str);
106   }
107   
108   cap_open_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
109   gtk_window_set_title(GTK_WINDOW(cap_open_w), "Ethereal: Capture Preferences");
110   
111   /* Container for each row of widgets */
112   main_vb = gtk_vbox_new(FALSE, 3);
113   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
114   gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb);
115   gtk_widget_show(main_vb);
116   
117   /* Interface row */
118   if_hb = gtk_hbox_new(FALSE, 3);
119   gtk_container_add(GTK_CONTAINER(main_vb), if_hb);
120   gtk_widget_show(if_hb);
121   
122   if_lb = gtk_label_new("Interface:");
123   gtk_box_pack_start(GTK_BOX(if_hb), if_lb, FALSE, FALSE, 0);
124   gtk_widget_show(if_lb);
125   
126   if_cb = gtk_combo_new();
127   if (if_list != NULL)
128     gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
129   if (cf.iface)
130     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), cf.iface);
131   else if (if_list)
132     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), if_list->data);
133   gtk_box_pack_start(GTK_BOX(if_hb), if_cb, FALSE, FALSE, 0);
134   gtk_widget_show(if_cb);
135   
136   free_interface_list(if_list);
137
138   /* Count row */
139   count_hb = gtk_hbox_new(FALSE, 3);
140   gtk_container_add(GTK_CONTAINER(main_vb), count_hb);
141   gtk_widget_show(count_hb);
142   
143   count_lb = gtk_label_new("Count:");
144   gtk_box_pack_start(GTK_BOX(count_hb), count_lb, FALSE, FALSE, 0);
145   gtk_widget_show(count_lb);
146   
147   count_list = g_list_append(count_list, count_item1);
148   if (cf.count) {
149     snprintf(count_item2, 15, "%d", cf.count);
150     count_list = g_list_append(count_list, count_item2);
151   }
152
153   count_cb = gtk_combo_new();
154   gtk_combo_set_popdown_strings(GTK_COMBO(count_cb), count_list);
155   gtk_box_pack_start(GTK_BOX(count_hb), count_cb, FALSE, FALSE, 0);
156   gtk_widget_show(count_cb);
157
158   while (count_list)
159     count_list = g_list_remove_link(count_list, count_list);
160
161   /* Filter row */
162   filter_hb = gtk_hbox_new(FALSE, 3);
163   gtk_container_add(GTK_CONTAINER(main_vb), filter_hb);
164   gtk_widget_show(filter_hb);
165   
166   filter_bt = gtk_button_new_with_label("Filter:");
167   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
168     GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
169   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
170   gtk_widget_show(filter_bt);
171   
172   filter_te = gtk_entry_new();
173   if (cf.cfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.cfilter);
174   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
175   gtk_box_pack_start(GTK_BOX(filter_hb), filter_te, TRUE, TRUE, 0);
176   gtk_widget_show(filter_te);
177   
178   /* File row */
179   file_hb = gtk_hbox_new(FALSE, 1);
180   gtk_container_add(GTK_CONTAINER(main_vb), file_hb);
181   gtk_widget_show(file_hb);
182   
183   file_bt = gtk_button_new_with_label("File:");
184   gtk_box_pack_start(GTK_BOX(file_hb), file_bt, FALSE, FALSE, 3);
185   gtk_widget_show(file_bt);
186   
187   file_te = gtk_entry_new();
188   gtk_box_pack_start(GTK_BOX(file_hb), file_te, TRUE, TRUE, 3);
189   gtk_widget_show(file_te);
190
191   gtk_signal_connect(GTK_OBJECT(file_bt), "clicked",
192     GTK_SIGNAL_FUNC(capture_prep_file_cb), GTK_OBJECT(file_te));
193
194   /* Misc row: Capture file checkbox and snap spinbutton */
195   caplen_hb = gtk_hbox_new(FALSE, 3);
196   gtk_container_add(GTK_CONTAINER(main_vb), caplen_hb);
197   gtk_widget_show(caplen_hb);
198
199   snap_lb = gtk_label_new("Capture length");
200   gtk_misc_set_alignment(GTK_MISC(snap_lb), 0, 0.5);
201   gtk_box_pack_start(GTK_BOX(caplen_hb), snap_lb, FALSE, FALSE, 6);
202   gtk_widget_show(snap_lb);
203
204   adj = (GtkAdjustment *) gtk_adjustment_new((float) cf.snap,
205     MIN_PACKET_SIZE, WTAP_MAX_PACKET_SIZE, 1.0, 10.0, 0.0);
206   snap_sb = gtk_spin_button_new (adj, 0, 0);
207   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE);
208   gtk_widget_set_usize (snap_sb, 80, 0);
209   gtk_box_pack_start (GTK_BOX(caplen_hb), snap_sb, FALSE, FALSE, 3); 
210   gtk_widget_show(snap_sb);
211   
212   sync_cb = gtk_check_button_new_with_label("Update list of packets in real time");
213   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(sync_cb), sync_mode);
214   gtk_container_add(GTK_CONTAINER(main_vb), sync_cb);
215   gtk_widget_show(sync_cb);
216
217   auto_scroll_cb = gtk_check_button_new_with_label("Automatic scrolling in live capture");
218   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(auto_scroll_cb), auto_scroll_live);
219   gtk_container_add(GTK_CONTAINER(main_vb), auto_scroll_cb);
220   gtk_widget_show(auto_scroll_cb);
221
222   resolv_cb = gtk_check_button_new_with_label("Enable name resolution");
223   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(resolv_cb), g_resolving_actif);
224   gtk_container_add(GTK_CONTAINER(main_vb), resolv_cb);
225   gtk_widget_show(resolv_cb);
226   
227   /* Button row: OK and cancel buttons */
228   bbox = gtk_hbutton_box_new();
229   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
230   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
231   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
232   gtk_widget_show(bbox);
233
234   ok_bt = gtk_button_new_with_label ("OK");
235   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
236     GTK_SIGNAL_FUNC(capture_prep_ok_cb), GTK_OBJECT(cap_open_w));
237   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
238   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
239   gtk_widget_grab_default(ok_bt);
240   gtk_widget_show(ok_bt);
241
242   cancel_bt = gtk_button_new_with_label ("Cancel");
243   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
244     GTK_SIGNAL_FUNC(capture_prep_close_cb), GTK_OBJECT(cap_open_w));
245   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
246   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
247   gtk_widget_show(cancel_bt);
248
249   /* Attach pointers to needed widgets to the capture prefs window/object */
250   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_IFACE_KEY, if_cb);
251   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILT_KEY,  filter_te);
252   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILE_TE_KEY,  file_te);
253   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_COUNT_KEY, count_cb);
254   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SNAP_KEY,  snap_sb);
255   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SYNC_KEY,  sync_cb);
256   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_AUTO_SCROLL_KEY, auto_scroll_cb);
257   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_RESOLVE_KEY,  resolv_cb);
258
259   gtk_widget_show(cap_open_w);
260 }
261
262 static void
263 capture_prep_file_cb(GtkWidget *w, gpointer file_te)
264 {
265   GtkWidget *fs;
266
267   fs = gtk_file_selection_new ("Ethereal: Capture File");
268
269   gtk_object_set_data(GTK_OBJECT(fs), E_CAP_FILE_TE_KEY, file_te);
270
271   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
272     "clicked", (GtkSignalFunc) cap_prep_fs_ok_cb, fs);
273
274   /* Connect the cancel_button to destroy the widget */
275   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
276     "clicked", (GtkSignalFunc) cap_prep_fs_cancel_cb, fs);
277   
278   gtk_widget_show(fs);
279 }
280
281 static void
282 cap_prep_fs_ok_cb(GtkWidget *w, gpointer data)
283 {
284   gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(data),
285       E_CAP_FILE_TE_KEY)),
286       gtk_file_selection_get_filename (GTK_FILE_SELECTION(data)));
287   gtk_widget_destroy(GTK_WIDGET(data));
288 }
289
290 static void
291 cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data)
292 {
293   gtk_widget_destroy(GTK_WIDGET(data));
294 }  
295
296 static void
297 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
298   GtkWidget *if_cb, *filter_te, *file_te, *count_cb, *snap_sb, *sync_cb,
299             *auto_scroll_cb, *resolv_cb;
300   gchar *if_text;
301   gchar *if_name;
302   gchar *filter_text;
303   gchar *save_file;
304
305   if_cb     = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_IFACE_KEY);
306   filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILT_KEY);
307   file_te   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILE_TE_KEY);
308   count_cb  = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_COUNT_KEY);
309   snap_sb   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SNAP_KEY);
310   sync_cb   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SYNC_KEY);
311   auto_scroll_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_AUTO_SCROLL_KEY);
312   resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RESOLVE_KEY);
313
314   if_text =
315     g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
316   if_name = strtok(if_text, " \t");
317   if (if_name == NULL) {
318     simple_dialog(ESD_TYPE_WARN, NULL,
319       "You didn't specify an interface on which to capture packets.");
320     g_free(if_name);
321     return;
322   }
323   if (cf.iface)
324     g_free(cf.iface);
325   cf.iface = g_strdup(if_name);
326   g_free(if_text);
327
328   /* XXX - don't try to get clever and set "cf.filter" to NULL if the
329      filter string is empty, as an indication that we don't have a filter
330      and thus don't have to set a filter when capturing - the version of
331      libpcap in Red Hat Linux 6.1, and versions based on later patches
332      in that series, don't bind the AF_PACKET socket to an interface
333      until a filter is set, which means they aren't bound at all if
334      no filter is set, which means no packets arrive as input on that
335      socket, which means Ethereal never sees any packets. */
336   filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
337   if (cf.cfilter)
338     g_free(cf.cfilter);
339   g_assert(filter_text != NULL);
340   cf.cfilter = g_strdup(filter_text); 
341
342   save_file = gtk_entry_get_text(GTK_ENTRY(file_te));
343   if (save_file && save_file[0]) {
344     /* User specified a file to which the capture should be written. */
345     save_file = g_strdup(save_file);
346   } else {
347     /* User didn't specify a file; save to a temporary file. */
348     save_file = NULL;
349   }
350
351   cf.count = atoi(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry)));
352
353   cf.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
354   if (cf.snap < 1)
355     cf.snap = WTAP_MAX_PACKET_SIZE;
356   else if (cf.snap < MIN_PACKET_SIZE)
357     cf.snap = MIN_PACKET_SIZE;
358
359   sync_mode = GTK_TOGGLE_BUTTON (sync_cb)->active;
360
361   auto_scroll_live = GTK_TOGGLE_BUTTON (auto_scroll_cb)->active;
362
363   g_resolving_actif = GTK_TOGGLE_BUTTON (resolv_cb)->active;
364
365   gtk_widget_destroy(GTK_WIDGET(parent_w));
366
367   do_capture(save_file);
368 }
369
370 static void
371 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w)
372 {
373   gtk_grab_remove(GTK_WIDGET(parent_w));
374   gtk_widget_destroy(GTK_WIDGET(parent_w));
375 }
376
377 #endif /* HAVE_LIBPCAP */