2 * Routines for packet capture windows
4 * $Id: capture_dlg.c,v 1.57 2002/01/21 07:37:41 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
50 #include <epan/resolv.h>
53 #include "capture_dlg.h"
54 #include "filter_prefs.h"
55 #include "simple_dialog.h"
56 #include "dlg_utils.h"
57 #include "pcap-util.h"
59 #include "ringbuffer.h"
62 #include "capture-wpcap.h"
65 /* Capture callback data keys */
66 #define E_CAP_IFACE_KEY "cap_iface"
67 #define E_CAP_FILT_KEY "cap_filter_te"
68 #define E_CAP_FILE_TE_KEY "cap_file_te"
69 #define E_CAP_COUNT_KEY "cap_count"
70 #define E_CAP_SNAP_KEY "cap_snap"
71 #define E_CAP_PROMISC_KEY "cap_promisc"
72 #define E_CAP_SYNC_KEY "cap_sync"
73 #define E_CAP_AUTO_SCROLL_KEY "cap_auto_scroll"
74 #define E_CAP_M_RESOLVE_KEY "cap_m_resolve"
75 #define E_CAP_N_RESOLVE_KEY "cap_n_resolve"
76 #define E_CAP_T_RESOLVE_KEY "cap_t_resolve"
77 #define E_CAP_FILESIZE_KEY "cap_filesize"
78 #define E_CAP_DURATION_KEY "cap_duration"
79 #define E_CAP_RING_ON_TB_KEY "cap_ringbuffer_on_tb"
80 #define E_CAP_RING_NBF_LB_KEY "cap_ringbuffer_nbf_lb"
81 #define E_CAP_RING_NBF_SB_KEY "cap_ringbuffer_nbf_sb"
83 #define E_FS_CALLER_PTR_KEY "fs_caller_ptr"
84 #define E_FILE_SEL_DIALOG_PTR_KEY "file_sel_dialog_ptr"
87 capture_prep_file_cb(GtkWidget *w, gpointer te);
90 cap_prep_fs_ok_cb(GtkWidget *w, gpointer data);
93 cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data);
96 cap_prep_fs_destroy_cb(GtkWidget *win, gpointer data);
99 capture_prep_adjust_sensitivity(GtkWidget *tb, gpointer parent_w);
102 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
105 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w);
108 capture_prep_destroy_cb(GtkWidget *win, gpointer user_data);
111 capture_stop_cb(GtkWidget *w, gpointer d)
117 * Keep a static pointer to the current "Capture Options" window, if
118 * any, so that if somebody tries to do "Capture:Start" while there's
119 * already a "Capture Options" window up, we just pop up the existing
120 * one, rather than creating a new one.
122 static GtkWidget *cap_open_w;
125 capture_prep_cb(GtkWidget *w, gpointer d)
127 GtkWidget *if_cb, *if_lb,
128 *count_lb, *count_cb, *main_vb,
129 *filter_bt, *filter_te,
131 *filesize_lb, *filesize_cb,
132 *duration_lb, *duration_cb,
134 *bbox, *ok_bt, *cancel_bt, *snap_lb,
135 *snap_sb, *promisc_cb, *sync_cb, *auto_scroll_cb,
136 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb,
137 *ringbuffer_hb, *ringbuffer_on_tb, *ringbuffer_nbf_lb, *ringbuffer_nbf_sb;
138 GtkAccelGroup *accel_group;
139 GtkAdjustment *snap_adj, *ringbuffer_nbf_adj;
140 GList *if_list, *count_list = NULL, *filesize_list = NULL, *duration_list = NULL;
141 gchar *count_item1 = "0 (Infinite)", count_item2[16],
142 *filesize_item1 = "0 (Infinite)", filesize_item2[16],
143 *duration_item1 = "0 (Infinite)", duration_item2[16];
145 char err_str[PCAP_ERRBUF_SIZE];
147 if (cap_open_w != NULL) {
148 /* There's already a "Capture Options" dialog box; reactivate it. */
149 reactivate_window(cap_open_w);
154 /* Is WPcap loaded? */
156 simple_dialog(ESD_TYPE_CRIT, NULL,
157 "Unable to load WinPcap (wpcap.dll); Ethereal will not be able\n"
158 "to capture packets.\n\n"
159 "In order to capture packets, WinPcap must be installed; see\n"
161 " http://netgroup-serv.polito.it/winpcap/\n"
165 " http://netgroup-mirror.ethereal.com/winpcap/\n"
169 " http://www.wiretapped.net/security/packet-capture/winpcap/default.htm\n"
171 "for a downloadable version of WinPcap and for instructions\n"
172 "on how to install WinPcap.");
177 if_list = get_interface_list(&err, err_str);
178 if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
179 simple_dialog(ESD_TYPE_WARN, NULL, "Can't get list of interfaces: %s",
183 cap_open_w = dlg_window_new("Ethereal: Capture Options");
184 gtk_signal_connect(GTK_OBJECT(cap_open_w), "destroy",
185 GTK_SIGNAL_FUNC(capture_prep_destroy_cb), NULL);
187 /* Accelerator group for the accelerators (or, as they're called in
188 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
189 Ctrl+<key> is an accelerator). */
190 accel_group = gtk_accel_group_new();
191 gtk_window_add_accel_group(GTK_WINDOW(cap_open_w), accel_group);
193 main_vb = gtk_vbox_new(FALSE, 3);
194 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
195 gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb);
196 gtk_widget_show(main_vb);
198 /* Table : container of the first 6 rows */
199 table = gtk_table_new (6, 2, FALSE);
200 gtk_table_set_row_spacings(GTK_TABLE (table), 5);
201 gtk_table_set_col_spacings(GTK_TABLE (table), 5);
202 gtk_container_add(GTK_CONTAINER(main_vb), table);
203 gtk_widget_show(table);
207 if_lb = gtk_label_new("Interface:");
208 gtk_table_attach_defaults(GTK_TABLE(table), if_lb, 0, 1, 0, 1);
209 gtk_widget_show(if_lb);
211 if_cb = gtk_combo_new();
213 gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
214 if (cfile.iface == NULL && prefs.capture_device != NULL) {
215 /* No interface was specified on the command line or in a previous
216 capture, but there is one specified in the preferences file;
217 make the one from the preferences file the default */
218 cfile.iface = g_strdup(prefs.capture_device);
220 if (cfile.iface != NULL)
221 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), cfile.iface);
222 else if (if_list != NULL)
223 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), if_list->data);
224 gtk_table_attach_defaults(GTK_TABLE(table), if_cb, 1, 2, 0, 1);
225 gtk_widget_show(if_cb);
227 free_interface_list(if_list);
231 count_lb = gtk_label_new("Count:");
232 gtk_table_attach_defaults(GTK_TABLE(table), count_lb, 0, 1, 1, 2);
233 gtk_widget_show(count_lb);
235 count_list = g_list_append(count_list, count_item1);
237 snprintf(count_item2, 15, "%d", cfile.count);
238 count_list = g_list_append(count_list, count_item2);
241 count_cb = gtk_combo_new();
242 gtk_combo_set_popdown_strings(GTK_COMBO(count_cb), count_list);
243 gtk_table_attach_defaults(GTK_TABLE(table), count_cb, 1, 2, 1, 2);
244 gtk_widget_show(count_cb);
247 count_list = g_list_remove_link(count_list, count_list);
251 filesize_lb = gtk_label_new("File size:");
252 gtk_table_attach_defaults(GTK_TABLE(table), filesize_lb, 0, 1, 2, 3);
253 gtk_widget_show(filesize_lb);
255 filesize_list = g_list_append(filesize_list, filesize_item1);
256 if (cfile.autostop_filesize) {
257 snprintf(filesize_item2, 15, "%d", cfile.autostop_filesize);
258 filesize_list = g_list_append(filesize_list, filesize_item2);
261 filesize_cb = gtk_combo_new();
262 gtk_combo_set_popdown_strings(GTK_COMBO(filesize_cb), filesize_list);
263 gtk_table_attach_defaults(GTK_TABLE(table), filesize_cb, 1, 2, 2, 3);
264 gtk_widget_show(filesize_cb);
266 while (filesize_list)
267 filesize_list = g_list_remove_link(filesize_list, filesize_list);
271 duration_lb = gtk_label_new("Duration:");
272 gtk_table_attach_defaults(GTK_TABLE(table), duration_lb, 0, 1, 3, 4);
273 gtk_widget_show(duration_lb);
275 duration_list = g_list_append(duration_list, duration_item1);
276 if (cfile.autostop_duration) {
277 snprintf(duration_item2, 15, "%d", cfile.autostop_duration);
278 duration_list = g_list_append(duration_list, duration_item2);
281 duration_cb = gtk_combo_new();
282 gtk_combo_set_popdown_strings(GTK_COMBO(duration_cb), duration_list);
283 gtk_table_attach_defaults(GTK_TABLE(table), duration_cb, 1, 2, 3, 4);
284 gtk_widget_show(duration_cb);
286 while (duration_list)
287 duration_list = g_list_remove_link(duration_list, duration_list);
291 filter_bt = gtk_button_new_with_label("Filter:");
292 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
293 GTK_SIGNAL_FUNC(capture_filter_construct_cb), NULL);
294 gtk_table_attach_defaults(GTK_TABLE(table), filter_bt, 0, 1, 4, 5);
295 gtk_widget_show(filter_bt);
297 filter_te = gtk_entry_new();
298 if (cfile.cfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cfile.cfilter);
299 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
300 gtk_table_attach_defaults(GTK_TABLE(table), filter_te, 1, 2, 4, 5);
301 gtk_widget_show(filter_te);
305 file_bt = gtk_button_new_with_label("File:");
306 gtk_table_attach_defaults(GTK_TABLE(table), file_bt, 0, 1, 5, 6);
307 gtk_widget_show(file_bt);
309 file_te = gtk_entry_new();
310 gtk_table_attach_defaults(GTK_TABLE(table), file_te, 1, 2, 5, 6);
311 gtk_widget_show(file_te);
313 gtk_signal_connect(GTK_OBJECT(file_bt), "clicked",
314 GTK_SIGNAL_FUNC(capture_prep_file_cb), GTK_OBJECT(file_te));
316 /* Misc row: Snap spinbutton */
317 caplen_hb = gtk_hbox_new(FALSE, 3);
318 gtk_container_add(GTK_CONTAINER(main_vb), caplen_hb);
319 gtk_widget_show(caplen_hb);
321 snap_lb = gtk_label_new("Capture length");
322 gtk_misc_set_alignment(GTK_MISC(snap_lb), 0, 0.5);
323 gtk_box_pack_start(GTK_BOX(caplen_hb), snap_lb, FALSE, FALSE, 6);
324 gtk_widget_show(snap_lb);
326 snap_adj = (GtkAdjustment *) gtk_adjustment_new((float) cfile.snap,
327 MIN_PACKET_SIZE, WTAP_MAX_PACKET_SIZE, 1.0, 10.0, 0.0);
328 snap_sb = gtk_spin_button_new (snap_adj, 0, 0);
329 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE);
330 gtk_widget_set_usize (snap_sb, 80, 0);
331 gtk_box_pack_start (GTK_BOX(caplen_hb), snap_sb, FALSE, FALSE, 3);
332 gtk_widget_show(snap_sb);
334 promisc_cb = dlg_check_button_new_with_label_with_mnemonic(
335 "Capture packets in _promiscuous mode", accel_group);
336 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(promisc_cb), promisc_mode);
337 gtk_container_add(GTK_CONTAINER(main_vb), promisc_cb);
338 gtk_widget_show(promisc_cb);
340 /* Misc row: Ring buffer toggle button and Ring buffer spinbutton */
341 ringbuffer_hb = gtk_hbox_new(FALSE, 3);
342 gtk_container_add(GTK_CONTAINER(main_vb), ringbuffer_hb);
343 gtk_widget_show(ringbuffer_hb);
345 ringbuffer_on_tb = dlg_check_button_new_with_label_with_mnemonic(
346 "Use _ring buffer", accel_group);
347 /* Ring buffer mode is allowed only if we're not doing an "Update list of
348 packets in real time" capture, so force it off if we're doing such
351 cfile.ringbuffer_on = FALSE;
352 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ringbuffer_on_tb),cfile.ringbuffer_on);
353 gtk_signal_connect(GTK_OBJECT(ringbuffer_on_tb), "toggled",
354 GTK_SIGNAL_FUNC(capture_prep_adjust_sensitivity), GTK_OBJECT(cap_open_w));
355 gtk_box_pack_start(GTK_BOX(ringbuffer_hb), ringbuffer_on_tb, FALSE, FALSE, 0);
356 gtk_widget_show(ringbuffer_on_tb);
358 ringbuffer_nbf_lb = gtk_label_new("Number of files");
359 gtk_misc_set_alignment(GTK_MISC(ringbuffer_nbf_lb), 1, 0.5);
360 gtk_box_pack_start(GTK_BOX(ringbuffer_hb), ringbuffer_nbf_lb, FALSE, FALSE, 6);
361 gtk_widget_show(ringbuffer_nbf_lb);
363 ringbuffer_nbf_adj = (GtkAdjustment *) gtk_adjustment_new((float) cfile.ringbuffer_num_files,
364 RINGBUFFER_MIN_NUM_FILES, RINGBUFFER_MAX_NUM_FILES, 1.0, 10.0, 0.0);
365 ringbuffer_nbf_sb = gtk_spin_button_new (ringbuffer_nbf_adj, 0, 0);
366 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (ringbuffer_nbf_sb), TRUE);
367 gtk_widget_set_usize (ringbuffer_nbf_sb, 40, 0);
368 gtk_box_pack_start (GTK_BOX(ringbuffer_hb), ringbuffer_nbf_sb, TRUE, TRUE, 0);
369 gtk_widget_show(ringbuffer_nbf_sb);
371 /* Misc row: Capture file checkboxes */
372 sync_cb = dlg_check_button_new_with_label_with_mnemonic(
373 "_Update list of packets in real time", accel_group);
374 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(sync_cb), sync_mode);
375 gtk_signal_connect(GTK_OBJECT(sync_cb), "toggled",
376 GTK_SIGNAL_FUNC(capture_prep_adjust_sensitivity), GTK_OBJECT(cap_open_w));
377 gtk_container_add(GTK_CONTAINER(main_vb), sync_cb);
378 gtk_widget_show(sync_cb);
380 auto_scroll_cb = dlg_check_button_new_with_label_with_mnemonic(
381 "_Automatic scrolling in live capture", accel_group);
382 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(auto_scroll_cb), auto_scroll_live);
383 gtk_container_add(GTK_CONTAINER(main_vb), auto_scroll_cb);
384 gtk_widget_show(auto_scroll_cb);
386 m_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
387 "Enable _MAC name resolution", accel_group);
388 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(m_resolv_cb),
389 g_resolv_flags & RESOLV_MAC);
390 gtk_container_add(GTK_CONTAINER(main_vb), m_resolv_cb);
391 gtk_widget_show(m_resolv_cb);
393 n_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
394 "Enable _network name resolution", accel_group);
395 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(n_resolv_cb),
396 g_resolv_flags & RESOLV_NETWORK);
397 gtk_container_add(GTK_CONTAINER(main_vb), n_resolv_cb);
398 gtk_widget_show(n_resolv_cb);
400 t_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
401 "Enable _transport name resolution", accel_group);
402 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(t_resolv_cb),
403 g_resolv_flags & RESOLV_TRANSPORT);
404 gtk_container_add(GTK_CONTAINER(main_vb), t_resolv_cb);
405 gtk_widget_show(t_resolv_cb);
407 /* Button row: OK and cancel buttons */
408 bbox = gtk_hbutton_box_new();
409 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
410 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
411 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
412 gtk_widget_show(bbox);
414 ok_bt = gtk_button_new_with_label ("OK");
415 gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
416 GTK_SIGNAL_FUNC(capture_prep_ok_cb), GTK_OBJECT(cap_open_w));
417 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
418 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
419 gtk_widget_grab_default(ok_bt);
420 gtk_widget_show(ok_bt);
422 cancel_bt = gtk_button_new_with_label ("Cancel");
423 gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
424 GTK_SIGNAL_FUNC(capture_prep_close_cb), GTK_OBJECT(cap_open_w));
425 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
426 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
427 gtk_widget_show(cancel_bt);
429 /* Attach pointers to needed widgets to the capture prefs window/object */
430 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_IFACE_KEY, if_cb);
431 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILT_KEY, filter_te);
432 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILE_TE_KEY, file_te);
433 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_COUNT_KEY, count_cb);
434 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SNAP_KEY, snap_sb);
435 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_PROMISC_KEY, promisc_cb);
436 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SYNC_KEY, sync_cb);
437 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_AUTO_SCROLL_KEY, auto_scroll_cb);
438 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_M_RESOLVE_KEY, m_resolv_cb);
439 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_N_RESOLVE_KEY, n_resolv_cb);
440 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_T_RESOLVE_KEY, t_resolv_cb);
441 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILESIZE_KEY, filesize_cb);
442 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_DURATION_KEY, duration_cb);
443 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_RING_ON_TB_KEY, ringbuffer_on_tb);
444 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_RING_NBF_LB_KEY, ringbuffer_nbf_lb);
445 gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_RING_NBF_SB_KEY, ringbuffer_nbf_sb);
447 /* Set the sensitivity of various widgets as per the settings of other
449 capture_prep_adjust_sensitivity(NULL, cap_open_w);
451 /* Catch the "activate" signal on the frame number and file name text
452 entries, so that if the user types Return there, we act as if the
453 "OK" button had been selected, as happens if Return is typed if some
454 widget that *doesn't* handle the Return key has the input focus. */
455 dlg_set_activate(filter_te, ok_bt);
456 dlg_set_activate(file_te, ok_bt);
458 /* Catch the "key_press_event" signal in the window, so that we can catch
459 the ESC key being pressed and act as if the "Cancel" button had
461 dlg_set_cancel(cap_open_w, cancel_bt);
463 /* XXX - why does not
465 gtk_widget_grab_focus(if_cb);
467 give the initial focus to the "Interface" combo box?
469 Or should I phrase that as "why does GTK+ continually frustrate
470 attempts to make GUIs driveable from the keyboard?" We have to
471 go catch the activate signal on every single GtkEntry widget
472 (rather than having widgets whose activate signal is *not*
473 caught not catch the Return keystroke, so that it passes on,
474 ultimately, to the window, which can activate the default
475 widget, i.e. the "OK" button); we have to catch the "key_press_event"
476 signal and have the handler check for ESC, so that we can have ESC
477 activate the "Cancel" button; in order to support Alt+<key> mnemonics
478 for buttons and the like, we may have to construct an accelerator
479 group by hand and set up the accelerators by hand (if that even
480 works - I've not tried it yet); we have to do a "gtk_widget_grab_focus()"
481 to keep some container widget from getting the initial focus, so that
482 you don't have to tab into the first widget in order to start typing
483 in it; and it now appears that you simply *can't* make a combo box
484 get the initial focus, at least not in the obvious fashion. Sigh.... */
486 gtk_widget_show(cap_open_w);
490 capture_prep_file_cb(GtkWidget *w, gpointer file_te)
492 GtkWidget *caller = gtk_widget_get_toplevel(w);
495 /* Has a file selection dialog box already been opened for that top-level
497 fs = gtk_object_get_data(GTK_OBJECT(caller), E_FILE_SEL_DIALOG_PTR_KEY);
500 /* Yes. Just re-activate that dialog box. */
501 reactivate_window(fs);
505 fs = gtk_file_selection_new ("Ethereal: Capture File");
507 gtk_object_set_data(GTK_OBJECT(fs), E_CAP_FILE_TE_KEY, file_te);
509 /* Set the E_FS_CALLER_PTR_KEY for the new dialog to point to our caller. */
510 gtk_object_set_data(GTK_OBJECT(fs), E_FS_CALLER_PTR_KEY, caller);
512 /* Set the E_FILE_SEL_DIALOG_PTR_KEY for the caller to point to us */
513 gtk_object_set_data(GTK_OBJECT(caller), E_FILE_SEL_DIALOG_PTR_KEY, fs);
515 /* Call a handler when the file selection box is destroyed, so we can inform
516 our caller, if any, that it's been destroyed. */
517 gtk_signal_connect(GTK_OBJECT(fs), "destroy",
518 GTK_SIGNAL_FUNC(cap_prep_fs_destroy_cb), NULL);
520 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button),
521 "clicked", (GtkSignalFunc) cap_prep_fs_ok_cb, fs);
523 /* Connect the cancel_button to destroy the widget */
524 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button),
525 "clicked", (GtkSignalFunc) cap_prep_fs_cancel_cb, fs);
527 /* Catch the "key_press_event" signal in the window, so that we can catch
528 the ESC key being pressed and act as if the "Cancel" button had
530 dlg_set_cancel(fs, GTK_FILE_SELECTION(fs)->cancel_button);
536 cap_prep_fs_ok_cb(GtkWidget *w, gpointer data)
538 gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(data),
540 gtk_file_selection_get_filename (GTK_FILE_SELECTION(data)));
541 gtk_widget_destroy(GTK_WIDGET(data));
545 cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data)
547 gtk_widget_destroy(GTK_WIDGET(data));
551 cap_prep_fs_destroy_cb(GtkWidget *win, gpointer data)
555 /* Get the widget that requested that we be popped up.
556 (It should arrange to destroy us if it's destroyed, so
557 that we don't get a pointer to a non-existent window here.) */
558 caller = gtk_object_get_data(GTK_OBJECT(win), E_FS_CALLER_PTR_KEY);
560 /* Tell it we no longer exist. */
561 gtk_object_set_data(GTK_OBJECT(caller), E_FILE_SEL_DIALOG_PTR_KEY, NULL);
563 /* Now nuke this window. */
564 gtk_grab_remove(GTK_WIDGET(win));
565 gtk_widget_destroy(GTK_WIDGET(win));
569 get_positive_int(const char *string, const char *name)
574 number = strtol(string, &p, 10);
576 * XXX - we allow extra stuff after 0, so that we don't have
577 * problems with the "(Infinite)" value.
579 if (p == string || (*p != '\0' && number != 0)) {
580 simple_dialog(ESD_TYPE_CRIT, NULL,
581 "The specified %s is not a decimal number.", name);
585 simple_dialog(ESD_TYPE_CRIT, NULL,
586 "The specified %s is a negative number.", name);
589 if (number > INT_MAX) {
590 simple_dialog(ESD_TYPE_CRIT, NULL,
591 "The specified %s is too large (greater than %d).", name, INT_MAX);
598 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
599 GtkWidget *if_cb, *filter_te, *file_te, *count_cb, *snap_sb, *promisc_cb,
600 *sync_cb, *auto_scroll_cb, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb,
601 *filesize_cb, *duration_cb, *ringbuffer_on_tb, *ringbuffer_nbf_sb;
608 if_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_IFACE_KEY);
609 filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILT_KEY);
610 file_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILE_TE_KEY);
611 count_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_COUNT_KEY);
612 snap_sb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SNAP_KEY);
613 promisc_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_PROMISC_KEY);
614 sync_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SYNC_KEY);
615 auto_scroll_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_AUTO_SCROLL_KEY);
616 m_resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_M_RESOLVE_KEY);
617 n_resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_N_RESOLVE_KEY);
618 t_resolv_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_T_RESOLVE_KEY);
619 filesize_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILESIZE_KEY);
620 duration_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_DURATION_KEY);
621 ringbuffer_on_tb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RING_ON_TB_KEY);
622 ringbuffer_nbf_sb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RING_NBF_SB_KEY);
625 g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
626 if_name = strtok(if_text, " \t");
627 if (if_name == NULL) {
628 simple_dialog(ESD_TYPE_CRIT, NULL,
629 "You didn't specify an interface on which to capture packets.");
635 cfile.iface = g_strdup(if_name);
638 /* XXX - don't try to get clever and set "cfile.filter" to NULL if the
639 filter string is empty, as an indication that we don't have a filter
640 and thus don't have to set a filter when capturing - the version of
641 libpcap in Red Hat Linux 6.1, and versions based on later patches
642 in that series, don't bind the AF_PACKET socket to an interface
643 until a filter is set, which means they aren't bound at all if
644 no filter is set, which means no packets arrive as input on that
645 socket, which means Ethereal never sees any packets. */
646 filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
648 g_free(cfile.cfilter);
649 g_assert(filter_text != NULL);
650 cfile.cfilter = g_strdup(filter_text);
652 save_file = gtk_entry_get_text(GTK_ENTRY(file_te));
653 if (save_file && save_file[0]) {
654 /* User specified a file to which the capture should be written. */
655 save_file = g_strdup(save_file);
657 /* User didn't specify a file; save to a temporary file. */
661 value = get_positive_int(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry)),
662 "maximum packet count");
667 value = get_positive_int(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(filesize_cb)->entry)),
668 "maximum capture file size");
671 cfile.autostop_filesize = value;
673 value = get_positive_int(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(duration_cb)->entry)),
677 cfile.autostop_duration = value;
679 cfile.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
681 cfile.snap = WTAP_MAX_PACKET_SIZE;
682 else if (cfile.snap < MIN_PACKET_SIZE)
683 cfile.snap = MIN_PACKET_SIZE;
685 promisc_mode = GTK_TOGGLE_BUTTON (promisc_cb)->active;
687 sync_mode = GTK_TOGGLE_BUTTON (sync_cb)->active;
689 auto_scroll_live = GTK_TOGGLE_BUTTON (auto_scroll_cb)->active;
691 g_resolv_flags = RESOLV_NONE;
692 g_resolv_flags |= (GTK_TOGGLE_BUTTON (m_resolv_cb)->active ? RESOLV_MAC : RESOLV_NONE);
693 g_resolv_flags |= (GTK_TOGGLE_BUTTON (n_resolv_cb)->active ? RESOLV_NETWORK : RESOLV_NONE);
694 g_resolv_flags |= (GTK_TOGGLE_BUTTON (t_resolv_cb)->active ? RESOLV_TRANSPORT : RESOLV_NONE);
696 cfile.ringbuffer_on = GTK_TOGGLE_BUTTON (ringbuffer_on_tb)->active && !(sync_mode);
697 if (cfile.ringbuffer_on == TRUE) {
698 if (save_file == NULL) {
699 simple_dialog(ESD_TYPE_CRIT, NULL,
700 "You must specify a save file if you want to use the ring buffer.");
702 } else if (cfile.autostop_filesize == 0) {
703 simple_dialog(ESD_TYPE_CRIT, NULL,
704 "You must specify a maximum save file size other \nthan 0 (infinite) if you want to use the ring buffer.");
709 cfile.ringbuffer_num_files = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ringbuffer_nbf_sb));
710 if (cfile.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
711 cfile.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
712 else if (cfile.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
713 cfile.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
715 gtk_widget_destroy(GTK_WIDGET(parent_w));
717 do_capture(save_file);
721 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w)
723 gtk_grab_remove(GTK_WIDGET(parent_w));
724 gtk_widget_destroy(GTK_WIDGET(parent_w));
728 capture_prep_destroy_cb(GtkWidget *win, gpointer user_data)
730 GtkWidget *capture_prep_filter_w;
733 /* Is there a filter edit/selection dialog associated with this
734 Capture Options dialog? */
735 capture_prep_filter_w = gtk_object_get_data(GTK_OBJECT(win), E_FILT_DIALOG_PTR_KEY);
737 if (capture_prep_filter_w != NULL) {
738 /* Yes. Destroy it. */
739 gtk_widget_destroy(capture_prep_filter_w);
742 /* Is there a file selection dialog associated with this
743 Print File dialog? */
744 fs = gtk_object_get_data(GTK_OBJECT(win), E_FILE_SEL_DIALOG_PTR_KEY);
747 /* Yes. Destroy it. */
748 gtk_widget_destroy(fs);
751 /* Note that we no longer have a "Capture Options" dialog box. */
756 * Adjust the sensitivity of various widgets as per the current setting
760 capture_prep_adjust_sensitivity(GtkWidget *tb, gpointer parent_w)
762 GtkWidget *sync_cb, *auto_scroll_cb, *ringbuffer_on_tb;
763 GtkWidget *ringbuffer_nbf_lb, *ringbuffer_nbf_sb;
765 sync_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SYNC_KEY);
766 auto_scroll_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_AUTO_SCROLL_KEY);
767 ringbuffer_on_tb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RING_ON_TB_KEY);
768 ringbuffer_nbf_lb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RING_NBF_LB_KEY);
769 ringbuffer_nbf_sb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_RING_NBF_SB_KEY);
771 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sync_cb))) {
772 /* "Update list of packets in real time" captures enabled; we don't
773 support ring buffer mode for those captures, so turn ring buffer
774 mode off if it's on, and make its toggle button, and the spin
775 button for the number of ring buffer files (and the spin button's
776 label), insensitive. */
777 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ringbuffer_on_tb))) {
778 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ringbuffer_on_tb), FALSE);
780 gtk_widget_set_sensitive(GTK_WIDGET(ringbuffer_on_tb), FALSE);
782 /* Auto-scroll mode is meaningful only in "Update list of packets
783 in real time" captures, so make its toggle button sensitive. */
784 gtk_widget_set_sensitive(GTK_WIDGET(auto_scroll_cb), TRUE);
786 /* "Update list of packets in real time" captures disabled; that
787 means ring buffer mode is OK, so make its toggle button
789 gtk_widget_set_sensitive(GTK_WIDGET(ringbuffer_on_tb), TRUE);
791 /* Auto-scroll mode is meaningful only in "Update list of packets
792 in real time" captures, so make its toggle button insensitive. */
793 gtk_widget_set_sensitive(GTK_WIDGET(auto_scroll_cb), FALSE);
796 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ringbuffer_on_tb))) {
797 /* Ring buffer mode enabled. Make the spin button for the number
798 of ring buffer files, and its label, sensitive. */
799 gtk_widget_set_sensitive(GTK_WIDGET(ringbuffer_nbf_lb), TRUE);
800 gtk_widget_set_sensitive(GTK_WIDGET(ringbuffer_nbf_sb), TRUE);
802 /* Ring buffer mode disabled. Make the spin button for the number
803 of ring buffer files, and its label insensitive. */
804 gtk_widget_set_sensitive(GTK_WIDGET(ringbuffer_nbf_lb), FALSE);
805 gtk_widget_set_sensitive(GTK_WIDGET(ringbuffer_nbf_sb), FALSE);
809 #endif /* HAVE_LIBPCAP */