2 * Dialog boxes for printing and exporting to text files
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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.
34 #include "gtkglobals.h"
37 #include <epan/prefs.h>
38 #include "alert_box.h"
39 #include "simple_dialog.h"
40 #include "capture_file_dlg.h"
41 #include "gui_utils.h"
42 #include "dlg_utils.h"
45 #include <epan/epan_dissect.h>
46 #include <epan/filesystem.h>
48 #include "print_mswin.h"
50 #include "compat_macros.h"
51 #include "range_utils.h"
53 #include "file_util.h"
57 #if GTK_MAJOR_VERSION >= 2 && _WIN32
58 #include <gdk/gdkwin32.h>
60 #include "win32-file-dlg.h"
63 /* dialog output action */
65 output_action_print, /* print text to printer */
66 output_action_export_text, /* export to plain text */
67 output_action_export_ps, /* export to postscript */
68 output_action_export_psml, /* export to packet summary markup language */
69 output_action_export_pdml, /* export to packet data markup language */
70 output_action_export_csv /* export to csv file */
74 /* On Win32, a GUI application apparently can't use "popen()" (it
75 "returns an invalid file handle, if used in a Windows program,
76 that will cause the program to hang indefinitely"), so we can't
77 use a pipe to a print command to print to a printer.
79 Eventually, we should try to use the native Win32 printing API
80 for this (and also use various UNIX printing APIs, when present?).
84 open_print_dialog(const char *title, output_action_e action, print_args_t *args);
85 static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data);
86 static void print_cmd_toggle_detail(GtkWidget *widget, gpointer data);
87 static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
88 static void print_destroy_cb(GtkWidget *win, gpointer user_data);
92 #define PRINT_ARGS_KEY "printer_args"
94 #define PRINT_PS_RB_KEY "printer_ps_radio_button"
95 #define PRINT_PDML_RB_KEY "printer_pdml_radio_button"
96 #define PRINT_PSML_RB_KEY "printer_psml_radio_button"
97 #define PRINT_CSV_RB_KEY "printer_csv_radio_button"
98 #define PRINT_DEST_CB_KEY "printer_destination_check_button"
100 #define PRINT_SUMMARY_CB_KEY "printer_summary_check_button"
101 #define PRINT_DETAILS_CB_KEY "printer_details_check_button"
102 #define PRINT_COLLAPSE_ALL_RB_KEY "printer_collapse_all_radio_button"
103 #define PRINT_AS_DISPLAYED_RB_KEY "printer_as_displayed_radio_button"
104 #define PRINT_EXPAND_ALL_RB_KEY "printer_expand_all_radio_button"
105 #define PRINT_HEX_CB_KEY "printer_hex_check_button"
106 #define PRINT_FORMFEED_CB_KEY "printer_formfeed_check_button"
108 #define PRINT_BT_KEY "printer_button"
110 #define PRINT_TE_PTR_KEY "printer_file_te_ptr"
114 * Keep a static pointer to the current "Print" window, if any, so that if
115 * somebody tries to do "File:Print" while there's already a "Print" window
116 * up, we just pop up the existing one, rather than creating a new one.
118 static GtkWidget *print_win = NULL;
120 static print_args_t print_args;
122 static gboolean print_prefs_init = FALSE;
126 file_print_cmd(gboolean print_selected)
128 print_args_t *args = &print_args;
130 if (print_win != NULL) {
131 /* There's already a "Print" dialog box; reactivate it. */
132 reactivate_window(print_win);
136 /* get settings from preferences (and other initial values) only once */
137 if(print_prefs_init == FALSE) {
138 print_prefs_init = TRUE;
139 args->format = prefs.pr_format;
140 args->to_file = prefs.pr_dest;
141 args->file = g_strdup(prefs.pr_file);
142 args->cmd = g_strdup(prefs.pr_cmd);
143 args->print_summary = TRUE;
144 args->print_dissections = print_dissections_as_displayed;
145 args->print_hex = FALSE;
146 args->print_formfeed = FALSE;
149 /* init the printing range */
150 packet_range_init(&args->range);
153 args->range.process = range_process_selected;
156 print_win = open_print_dialog("Wireshark: Print", output_action_print, args);
157 SIGNAL_CONNECT(print_win, "destroy", print_destroy_cb, &print_win);
161 file_print_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
163 file_print_cmd(FALSE);
167 file_print_selected_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
169 file_print_cmd(TRUE);
173 * Keep a static pointer to the current "Export text" window, if any, so that if
174 * somebody tries to do "File:Export to text" while there's already a "Export text" window
175 * up, we just pop up the existing one, rather than creating a new one.
177 static GtkWidget *export_text_win = NULL;
179 static print_args_t export_text_args;
181 static gboolean export_text_prefs_init = FALSE;
185 export_text_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
187 print_args_t *args = &export_text_args;
189 #if GTK_MAJOR_VERSION >= 2 && _WIN32
190 win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_text);
194 if (export_text_win != NULL) {
195 /* There's already a "Export text" dialog box; reactivate it. */
196 reactivate_window(export_text_win);
200 /* get settings from preferences (and other initial values) only once */
201 if(export_text_prefs_init == FALSE) {
202 export_text_prefs_init = TRUE;
203 args->format = PR_FMT_TEXT;
204 args->to_file = TRUE;
205 args->file = g_strdup("");
206 args->cmd = g_strdup("");
207 args->print_summary = TRUE;
208 args->print_dissections = print_dissections_as_displayed;
209 args->print_hex = FALSE;
210 args->print_formfeed = FALSE;
213 /* init the printing range */
214 packet_range_init(&args->range);
216 export_text_win = open_print_dialog("Wireshark: Export as \"Plain Text\" File", output_action_export_text, args);
217 SIGNAL_CONNECT(export_text_win, "destroy", print_destroy_cb, &export_text_win);
222 * Keep a static pointer to the current "Export ps" window, if any, so that if
223 * somebody tries to do "File:Export to ps" while there's already a "Export ps" window
224 * up, we just pop up the existing one, rather than creating a new one.
226 static GtkWidget *export_ps_win = NULL;
228 static print_args_t export_ps_args;
230 static gboolean export_ps_prefs_init = FALSE;
234 export_ps_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
236 print_args_t *args = &export_ps_args;
238 #if GTK_MAJOR_VERSION >= 2 && _WIN32
239 win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_ps);
243 if (export_ps_win != NULL) {
244 /* There's already a "Export ps" dialog box; reactivate it. */
245 reactivate_window(export_ps_win);
249 /* get settings from preferences (and other initial values) only once */
250 if(export_ps_prefs_init == FALSE) {
251 export_ps_prefs_init = TRUE;
252 args->format = PR_FMT_PS;
253 args->to_file = TRUE;
254 args->file = g_strdup("");
255 args->cmd = g_strdup("");
256 args->print_summary = TRUE;
257 args->print_dissections = print_dissections_as_displayed;
258 args->print_hex = FALSE;
259 args->print_formfeed = FALSE;
262 /* init the printing range */
263 packet_range_init(&args->range);
265 export_ps_win = open_print_dialog("Wireshark: Export as \"PostScript\" file", output_action_export_ps, args);
266 SIGNAL_CONNECT(export_ps_win, "destroy", print_destroy_cb, &export_ps_win);
271 * Keep a static pointer to the current "Export psml" window, if any, so that if
272 * somebody tries to do "File:Export to psml" while there's already a "Export psml" window
273 * up, we just pop up the existing one, rather than creating a new one.
275 static GtkWidget *export_psml_win = NULL;
277 static print_args_t export_psml_args;
279 static gboolean export_psml_prefs_init = FALSE;
283 export_psml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
285 print_args_t *args = &export_psml_args;
287 #if GTK_MAJOR_VERSION >= 2 && _WIN32
288 win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_psml);
292 if (export_psml_win != NULL) {
293 /* There's already a "Export psml" dialog box; reactivate it. */
294 reactivate_window(export_psml_win);
298 /* get settings from preferences (and other initial values) only once */
299 if(export_psml_prefs_init == FALSE) {
300 export_psml_prefs_init = TRUE;
301 args->format = PR_FMT_TEXT; /* XXX */
302 args->to_file = TRUE;
303 args->file = g_strdup("");
304 args->cmd = g_strdup("");
305 args->print_summary = TRUE;
306 args->print_dissections = print_dissections_as_displayed;
307 args->print_hex = FALSE;
308 args->print_formfeed = FALSE;
311 /* init the printing range */
312 packet_range_init(&args->range);
314 export_psml_win = open_print_dialog("Wireshark: Export as \"PSML\" file", output_action_export_psml, args);
315 SIGNAL_CONNECT(export_psml_win, "destroy", print_destroy_cb, &export_psml_win);
320 * Keep a static pointer to the current "Export pdml" window, if any, so that if
321 * somebody tries to do "File:Export to pdml" while there's already a "Export pdml" window
322 * up, we just pop up the existing one, rather than creating a new one.
324 static GtkWidget *export_pdml_win = NULL;
326 static print_args_t export_pdml_args;
328 static gboolean export_pdml_prefs_init = FALSE;
332 export_pdml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
334 print_args_t *args = &export_pdml_args;
336 #if GTK_MAJOR_VERSION >= 2 && _WIN32
337 win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_pdml);
341 if (export_pdml_win != NULL) {
342 /* There's already a "Export pdml" dialog box; reactivate it. */
343 reactivate_window(export_pdml_win);
347 /* get settings from preferences (and other initial values) only once */
348 if(export_pdml_prefs_init == FALSE) {
349 export_pdml_prefs_init = TRUE;
350 args->format = PR_FMT_TEXT; /* XXX */
351 args->to_file = TRUE;
352 args->file = g_strdup("");
353 args->cmd = g_strdup("");
354 args->print_summary = TRUE;
355 args->print_dissections = print_dissections_as_displayed;
356 args->print_hex = FALSE;
357 args->print_formfeed = FALSE;
360 /* init the printing range */
361 packet_range_init(&args->range);
363 export_pdml_win = open_print_dialog("Wireshark: Export as \"PDML\" file", output_action_export_pdml, args);
364 SIGNAL_CONNECT(export_pdml_win, "destroy", print_destroy_cb, &export_pdml_win);
368 * Keep a static pointer to the current "Export csv" window, if any, so that if
369 * somebody tries to do "File:Export to CSV" while there's already a "Export csv" window
370 * up, we just pop up the existing one, rather than creating a new one.
372 static GtkWidget *export_csv_win = NULL;
374 static print_args_t export_csv_args;
376 static gboolean export_csv_prefs_init = FALSE;
379 export_csv_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
381 print_args_t *args = &export_csv_args;
383 #if GTK_MAJOR_VERSION >= 2 && _WIN32
384 win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_csv);
388 if (export_csv_win != NULL) {
389 /* There's already a "Export csv" dialog box; reactivate it. */
390 reactivate_window(export_csv_win);
394 /* get settings from preferences (and other initial values) only once */
395 if(export_csv_prefs_init == FALSE) {
396 export_csv_prefs_init = TRUE;
397 args->format = PR_FMT_TEXT; /* XXX */
398 args->to_file = TRUE;
399 args->file = g_strdup("");
400 args->cmd = g_strdup("");
401 args->print_summary = FALSE;
402 args->print_dissections = print_dissections_none;
403 args->print_hex = FALSE;
404 args->print_formfeed = FALSE;
407 /* init the printing range */
408 packet_range_init(&args->range);
410 export_csv_win = open_print_dialog("Wireshark: Export as \"Comma Separated Values\" File", output_action_export_csv, args);
411 SIGNAL_CONNECT(export_csv_win, "destroy", print_destroy_cb, &export_csv_win);
415 print_browse_file_cb(GtkWidget *file_bt, GtkWidget *file_te)
417 file_selection_browse(file_bt, file_te, "Wireshark: Print to File",
418 FILE_SELECTION_WRITE_BROWSE);
423 /* Open the print dialog */
425 open_print_dialog(const char *title, output_action_e action, print_args_t *args)
427 #if GTK_MAJOR_VERSION < 2
428 GtkAccelGroup *accel_group;
434 GtkWidget *printer_fr, *printer_vb, *export_format_lb;
435 GtkWidget *text_rb, *ps_rb, *pdml_rb, *psml_rb, *csv_rb;
436 GtkWidget *printer_tb, *dest_cb;
438 GtkWidget *cmd_lb, *cmd_te;
440 GtkWidget *file_bt, *file_te;
442 GtkWidget *range_fr, *range_tb;
444 GtkWidget *packet_hb;
446 GtkWidget *format_fr, *format_vb;
447 GtkWidget *summary_cb;
449 GtkWidget *details_cb;
450 GtkWidget *details_hb, *details_vb;
451 GtkWidget *collapse_all_rb, *as_displayed_rb, *expand_all_rb;
453 GtkWidget *sep, *formfeed_cb;
455 GtkWidget *bbox, *ok_bt, *cancel_bt, *help_bt;
457 GtkTooltips *tooltips;
461 main_win = dlg_window_new(title);
463 /* Enable tooltips */
464 tooltips = gtk_tooltips_new();
466 #if GTK_MAJOR_VERSION < 2
467 /* Accelerator group for the accelerators (or, as they're called in
468 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
469 Ctrl+<key> is an accelerator). */
470 accel_group = gtk_accel_group_new();
471 gtk_window_add_accel_group(GTK_WINDOW(main_win), accel_group);
474 /* Vertical enclosing container for each row of widgets */
475 main_vb = gtk_vbox_new(FALSE, 5);
476 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
477 gtk_container_add(GTK_CONTAINER(main_win), main_vb);
478 gtk_widget_show(main_vb);
480 /*****************************************************/
482 /*** printer frame ***/
483 printer_fr = gtk_frame_new(action == output_action_print ? "Printer" : "Export to file:");
484 gtk_box_pack_start(GTK_BOX(main_vb), printer_fr, FALSE, FALSE, 0);
485 gtk_widget_show(printer_fr);
486 printer_vb = gtk_vbox_new(FALSE, 5);
487 gtk_container_border_width(GTK_CONTAINER(printer_vb), 5);
488 gtk_container_add(GTK_CONTAINER(printer_fr), printer_vb);
489 gtk_widget_show(printer_vb);
491 /* "Plain text" / "Postscript" / "PDML", ... radio buttons */
492 text_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Plain _text", accel_group);
493 if (args->format == PR_FMT_TEXT)
494 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(text_rb), TRUE);
495 gtk_tooltips_set_tip (tooltips, text_rb, "Print output in ascii \"plain text\" format. If you're unsure, use this format.", NULL);
496 gtk_box_pack_start(GTK_BOX(printer_vb), text_rb, FALSE, FALSE, 0);
497 if(action == output_action_print)
498 gtk_widget_show(text_rb);
500 ps_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "_PostScript", accel_group);
501 if (args->format == PR_FMT_PS)
502 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ps_rb), TRUE);
503 gtk_tooltips_set_tip (tooltips, ps_rb, "Print output in \"postscript\" format, for postscript capable printers or print servers.", NULL);
504 gtk_box_pack_start(GTK_BOX(printer_vb), ps_rb, FALSE, FALSE, 0);
505 if(action == output_action_print)
506 gtk_widget_show(ps_rb);
508 pdml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PDM_L (XML: Packet Details Markup Language)", accel_group);
509 if (action == output_action_export_pdml)
510 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(pdml_rb), TRUE);
511 gtk_tooltips_set_tip (tooltips, pdml_rb,
512 "Print output in \"PDML\" (Packet Details Markup Language), "
513 "an XML based packet data interchange format. "
514 "Usually used in combination with the \"Output to file\" option to export packet data into an XML file.", NULL);
515 gtk_box_pack_start(GTK_BOX(printer_vb), pdml_rb, FALSE, FALSE, 0);
516 /* gtk_widget_show(pdml_rb); */
518 psml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PSML (XML: Packet Summary Markup Language)", accel_group);
519 if (action == output_action_export_psml)
520 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(psml_rb), TRUE);
521 gtk_tooltips_set_tip (tooltips, psml_rb,
522 "Print output in \"PSML\" (Packet Summary Markup Language), "
523 "an XML based packet summary interchange format. "
524 "Usually used in combination with the \"Output to file\" option to export packet data into an XML file.", NULL);
525 gtk_box_pack_start(GTK_BOX(printer_vb), psml_rb, FALSE, FALSE, 0);
526 /* gtk_widget_show(psml_rb); */
528 csv_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "_CSV", accel_group);
529 if (action == output_action_export_csv)
530 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(csv_rb), TRUE);
531 gtk_tooltips_set_tip (tooltips, csv_rb,
532 "Print output in \"Comma Separated Values\" (CSV) format, "
533 "a text format compatible with OpenOffice and Excel. "
534 "One row for each packet, with its timestamp and size.", NULL);
535 gtk_box_pack_start(GTK_BOX(printer_vb), csv_rb, FALSE, FALSE, 0);
536 /* gtk_widget_show(csv_rb); */
540 printer_tb = gtk_table_new(2, 3, FALSE);
542 printer_tb = gtk_table_new(2, 2, FALSE);
544 gtk_box_pack_start(GTK_BOX(printer_vb), printer_tb, FALSE, FALSE, 0);
545 gtk_table_set_row_spacings(GTK_TABLE(printer_tb), 5);
546 gtk_table_set_col_spacings(GTK_TABLE(printer_tb), 5);
547 gtk_widget_show(printer_tb);
550 /* Output to file button */
551 dest_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Output to _file:", accel_group);
553 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dest_cb), TRUE);
554 gtk_tooltips_set_tip (tooltips, dest_cb, "Output to file instead of printer", NULL);
555 gtk_table_attach_defaults(GTK_TABLE(printer_tb), dest_cb, 0, 1, 0, 1);
556 if(action == output_action_print)
557 gtk_widget_show(dest_cb);
559 /* File text entry */
560 file_te = gtk_entry_new();
561 OBJECT_SET_DATA(dest_cb, PRINT_FILE_TE_KEY, file_te);
562 gtk_tooltips_set_tip (tooltips, file_te, "Enter Output filename", NULL);
563 gtk_entry_set_text(GTK_ENTRY(file_te), args->file);
564 gtk_table_attach_defaults(GTK_TABLE(printer_tb), file_te, 1, 2, 0, 1);
565 gtk_widget_set_sensitive(file_te, args->to_file);
566 gtk_widget_show(file_te);
568 gtk_widget_grab_focus(file_te);
570 /* "Browse" button */
571 file_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_BROWSE);
572 OBJECT_SET_DATA(dest_cb, PRINT_FILE_BT_KEY, file_bt);
573 OBJECT_SET_DATA(file_bt, PRINT_TE_PTR_KEY, file_te);
574 gtk_tooltips_set_tip (tooltips, file_bt, "Browse output filename in filesystem", NULL);
575 gtk_table_attach_defaults(GTK_TABLE(printer_tb), file_bt, 2, 3, 0, 1);
576 gtk_widget_set_sensitive(file_bt, args->to_file);
577 gtk_widget_show(file_bt);
579 /* Command label and text entry */
581 cmd_lb = gtk_label_new("Print command:");
582 OBJECT_SET_DATA(dest_cb, PRINT_CMD_LB_KEY, cmd_lb);
583 gtk_misc_set_alignment(GTK_MISC(cmd_lb), 1.0, 0.5);
584 gtk_table_attach_defaults(GTK_TABLE(printer_tb), cmd_lb, 0, 1, 1, 2);
585 gtk_widget_set_sensitive(cmd_lb, !args->to_file);
586 if(action == output_action_print)
587 gtk_widget_show(cmd_lb);
589 cmd_te = gtk_entry_new();
590 OBJECT_SET_DATA(dest_cb, PRINT_CMD_TE_KEY, cmd_te);
591 gtk_tooltips_set_tip (tooltips, cmd_te, "Enter print command", NULL);
592 gtk_entry_set_text(GTK_ENTRY(cmd_te), args->cmd);
593 gtk_table_attach_defaults(GTK_TABLE(printer_tb), cmd_te, 1, 2, 1, 2);
594 gtk_widget_set_sensitive(cmd_te, !args->to_file);
595 if(action == output_action_print)
596 gtk_widget_show(cmd_te);
599 SIGNAL_CONNECT(dest_cb, "toggled", print_cmd_toggle_dest, NULL);
600 SIGNAL_CONNECT(file_bt, "clicked", print_browse_file_cb, file_te);
602 if(action == output_action_export_ps) {
603 export_format_lb = gtk_label_new("(PostScript files can be easily converted to PDF files using ghostscript's ps2pdf)");
604 gtk_box_pack_start(GTK_BOX(printer_vb), export_format_lb, FALSE, FALSE, 0);
605 gtk_widget_show(export_format_lb);
608 /*****************************************************/
610 /*** hor box for range and format frames ***/
611 packet_hb = gtk_hbox_new(FALSE, 5);
612 gtk_container_add(GTK_CONTAINER(main_vb), packet_hb);
613 gtk_widget_show(packet_hb);
615 /*** packet range frame ***/
616 range_fr = gtk_frame_new("Packet Range");
617 gtk_box_pack_start(GTK_BOX(packet_hb), range_fr, FALSE, FALSE, 0);
618 gtk_widget_show(range_fr);
620 range_tb = range_new(&args->range
621 #if GTK_MAJOR_VERSION < 2
625 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
626 gtk_widget_show(range_tb);
628 /*****************************************************/
630 /*** packet format frame ***/
631 format_fr = gtk_frame_new("Packet Format");
632 gtk_box_pack_start(GTK_BOX(packet_hb), format_fr, TRUE, TRUE, 0);
633 if( action == output_action_print ||
634 action == output_action_export_text ||
635 action == output_action_export_ps)
636 gtk_widget_show(format_fr);
637 format_vb = gtk_vbox_new(FALSE, 5);
638 gtk_container_border_width(GTK_CONTAINER(format_vb), 5);
639 gtk_container_add(GTK_CONTAINER(format_fr), format_vb);
640 gtk_widget_show(format_vb);
642 /* "Print summary line" check button */
643 summary_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet summary line", accel_group);
644 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(summary_cb), args->print_summary);
645 SIGNAL_CONNECT(summary_cb, "clicked", print_cmd_toggle_detail, main_win);
646 gtk_tooltips_set_tip (tooltips, summary_cb, "Output of a packet summary line, like in the packet list", NULL);
647 gtk_container_add(GTK_CONTAINER(format_vb), summary_cb);
648 gtk_widget_show(summary_cb);
651 /* "Details" check button */
652 details_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet details:", accel_group);
653 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(details_cb), args->print_dissections != print_dissections_none);
654 SIGNAL_CONNECT(details_cb, "clicked", print_cmd_toggle_detail, main_win);
655 gtk_tooltips_set_tip (tooltips, details_cb, "Output format of the selected packet details (protocol tree).", NULL);
656 gtk_container_add(GTK_CONTAINER(format_vb), details_cb);
657 gtk_widget_show(details_cb);
659 /*** packet details ***/
660 details_hb = gtk_hbox_new(FALSE, 6);
661 gtk_container_border_width(GTK_CONTAINER(details_hb), 0);
662 gtk_container_add(GTK_CONTAINER(format_vb), details_hb);
663 gtk_widget_show(details_hb);
665 details_vb = gtk_vbox_new(FALSE, 6);
666 gtk_container_border_width(GTK_CONTAINER(details_vb), 0);
667 gtk_container_add(GTK_CONTAINER(details_hb), details_vb);
668 gtk_widget_show(details_vb);
670 details_vb = gtk_vbox_new(FALSE, 6);
671 gtk_container_border_width(GTK_CONTAINER(details_vb), 0);
672 gtk_container_add(GTK_CONTAINER(details_hb), details_vb);
673 gtk_widget_show(details_vb);
675 /* "All collapsed"/"As displayed"/"All Expanded" radio buttons */
676 collapse_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "All co_llapsed", accel_group);
677 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(collapse_all_rb), args->print_dissections == print_dissections_collapsed);
678 gtk_tooltips_set_tip (tooltips, collapse_all_rb, "Output of the packet details tree \"collapsed\"", NULL);
679 gtk_container_add(GTK_CONTAINER(details_vb), collapse_all_rb);
680 gtk_widget_show(collapse_all_rb);
682 as_displayed_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(collapse_all_rb, "As displa_yed", accel_group);
683 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(as_displayed_rb), args->print_dissections == print_dissections_as_displayed);
684 gtk_tooltips_set_tip (tooltips, as_displayed_rb, "Output of the packet details tree \"as displayed\"", NULL);
685 gtk_container_add(GTK_CONTAINER(details_vb), as_displayed_rb);
686 gtk_widget_show(as_displayed_rb);
688 expand_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(collapse_all_rb, "All e_xpanded", accel_group);
689 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(expand_all_rb), args->print_dissections == print_dissections_expanded);
690 gtk_tooltips_set_tip (tooltips, expand_all_rb, "Output of the packet details tree \"expanded\"", NULL);
691 gtk_container_add(GTK_CONTAINER(details_vb), expand_all_rb);
692 gtk_widget_show(expand_all_rb);
694 /* "Print hex" check button. */
695 hex_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet bytes", accel_group);
696 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(hex_cb), args->print_hex);
697 SIGNAL_CONNECT(hex_cb, "clicked", print_cmd_toggle_detail, main_win);
698 gtk_tooltips_set_tip (tooltips, hex_cb, "Add a hexdump of the packet data", NULL);
699 gtk_container_add(GTK_CONTAINER(format_vb), hex_cb);
700 gtk_widget_show(hex_cb);
703 sep = gtk_hseparator_new();
704 gtk_container_add(GTK_CONTAINER(format_vb), sep);
705 gtk_widget_show(sep);
707 /* "Each packet on a new page" check button. */
708 formfeed_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Each packet on a new page", accel_group);
709 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(formfeed_cb), args->print_formfeed);
710 gtk_tooltips_set_tip (tooltips, formfeed_cb, "When checked, a new page will be used for each packet. "
711 "This is done by adding a formfeed (or similar) between the packet outputs.", NULL);
712 gtk_container_add(GTK_CONTAINER(format_vb), formfeed_cb);
713 gtk_widget_show(formfeed_cb);
716 OBJECT_SET_DATA(main_win, PRINT_ARGS_KEY, args);
717 OBJECT_SET_DATA(main_win, PRINT_SUMMARY_CB_KEY, summary_cb);
718 OBJECT_SET_DATA(main_win, PRINT_DETAILS_CB_KEY, details_cb);
719 OBJECT_SET_DATA(main_win, PRINT_COLLAPSE_ALL_RB_KEY, collapse_all_rb);
720 OBJECT_SET_DATA(main_win, PRINT_AS_DISPLAYED_RB_KEY, as_displayed_rb);
721 OBJECT_SET_DATA(main_win, PRINT_EXPAND_ALL_RB_KEY, expand_all_rb);
722 OBJECT_SET_DATA(main_win, PRINT_HEX_CB_KEY, hex_cb);
724 /*****************************************************/
728 if(topic_available(HELP_PRINT_DIALOG)) {
729 bbox = dlg_button_row_new(action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
731 bbox = dlg_button_row_new(action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
733 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
734 gtk_widget_show(bbox);
736 ok_bt = OBJECT_GET_DATA(bbox, action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK);
738 OBJECT_SET_DATA(main_win, PRINT_BT_KEY, ok_bt);
740 OBJECT_SET_DATA(ok_bt, PRINT_PS_RB_KEY, ps_rb);
741 OBJECT_SET_DATA(ok_bt, PRINT_PDML_RB_KEY, pdml_rb);
742 OBJECT_SET_DATA(ok_bt, PRINT_PSML_RB_KEY, psml_rb);
743 OBJECT_SET_DATA(ok_bt, PRINT_CSV_RB_KEY, csv_rb);
744 OBJECT_SET_DATA(ok_bt, PRINT_DEST_CB_KEY, dest_cb);
746 OBJECT_SET_DATA(ok_bt, PRINT_CMD_TE_KEY, cmd_te);
749 OBJECT_SET_DATA(ok_bt, PRINT_ARGS_KEY, args);
750 OBJECT_SET_DATA(ok_bt, PRINT_FILE_TE_KEY, file_te);
751 OBJECT_SET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY, summary_cb);
752 OBJECT_SET_DATA(ok_bt, PRINT_DETAILS_CB_KEY, details_cb);
753 OBJECT_SET_DATA(ok_bt, PRINT_COLLAPSE_ALL_RB_KEY, collapse_all_rb);
754 OBJECT_SET_DATA(ok_bt, PRINT_AS_DISPLAYED_RB_KEY, as_displayed_rb);
755 OBJECT_SET_DATA(ok_bt, PRINT_EXPAND_ALL_RB_KEY, expand_all_rb);
756 OBJECT_SET_DATA(ok_bt, PRINT_HEX_CB_KEY, hex_cb);
757 OBJECT_SET_DATA(ok_bt, PRINT_FORMFEED_CB_KEY, formfeed_cb);
758 SIGNAL_CONNECT(ok_bt, "clicked", print_ok_cb, main_win);
759 gtk_tooltips_set_tip (tooltips, ok_bt, "Start output", NULL);
761 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
762 window_set_cancel_button(main_win, cancel_bt, window_cancel_button_cb);
763 gtk_tooltips_set_tip (tooltips, cancel_bt, "Cancel and exit dialog", NULL);
765 if(action == output_action_print) {
766 if(topic_available(HELP_PRINT_DIALOG)) {
767 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
768 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_PRINT_DIALOG);
771 #if GTK_MAJOR_VERSION >= 2 && _WIN32
772 if(topic_available(HELP_EXPORT_FILE_WIN32_DIALOG)) {
773 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
774 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_EXPORT_FILE_WIN32_DIALOG);
777 if(topic_available(HELP_EXPORT_FILE_DIALOG)) {
778 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
779 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_EXPORT_FILE_DIALOG);
784 gtk_widget_grab_default(ok_bt);
786 /* Catch the "activate" signal on the "Command" and "File" text entries,
787 so that if the user types Return there, we act as if the "OK" button
788 had been selected, as happens if Return is typed if some widget
789 that *doesn't* handle the Return key has the input focus. */
791 dlg_set_activate(cmd_te, ok_bt);
793 if(action != output_action_print)
794 dlg_set_activate(file_te, ok_bt);
796 SIGNAL_CONNECT(main_win, "delete_event", window_delete_event_cb, NULL);
798 gtk_widget_show(main_win);
799 window_present(main_win);
805 /* user changed "print to" destination */
807 print_cmd_toggle_dest(GtkWidget *widget, gpointer data _U_)
810 GtkWidget *cmd_lb, *cmd_te;
812 GtkWidget *file_bt, *file_te;
816 cmd_lb = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_CMD_LB_KEY));
817 cmd_te = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_CMD_TE_KEY));
819 file_bt = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_FILE_BT_KEY));
820 file_te = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_FILE_TE_KEY));
822 to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
824 gtk_widget_set_sensitive(cmd_lb, !to_file);
825 gtk_widget_set_sensitive(cmd_te, !to_file);
827 gtk_widget_set_sensitive(file_bt, to_file);
828 gtk_widget_set_sensitive(file_te, to_file);
832 /* user changed "packet details" */
834 print_cmd_toggle_detail(GtkWidget *widget _U_, gpointer data)
836 GtkWidget *print_bt, *summary_cb, *details_cb, *collapse_all_rb, *expand_all_rb, *as_displayed_rb, *hex_cb;
837 gboolean print_detail;
840 print_bt = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_BT_KEY));
841 summary_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_SUMMARY_CB_KEY));
842 details_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_DETAILS_CB_KEY));
843 collapse_all_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_COLLAPSE_ALL_RB_KEY));
844 as_displayed_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_AS_DISPLAYED_RB_KEY));
845 expand_all_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_EXPAND_ALL_RB_KEY));
846 hex_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_HEX_CB_KEY));
848 /* is user disabled details, disable the corresponding buttons */
849 print_detail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (details_cb));
850 gtk_widget_set_sensitive(collapse_all_rb, print_detail);
851 gtk_widget_set_sensitive(as_displayed_rb, print_detail);
852 gtk_widget_set_sensitive(expand_all_rb, print_detail);
854 /* if user selected nothing to print at all, disable the "ok" button */
855 gtk_widget_set_sensitive(print_bt,
856 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (summary_cb)) ||
857 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (details_cb)) ||
858 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_cb)));
863 print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
870 gboolean export_as_pdml = FALSE, export_as_psml = FALSE;
871 gboolean export_as_csv = FALSE;
873 gboolean win_printer = FALSE;
875 char tmp_namebuf[128+1]; /* XXX - length was used elsewhere too, why? */
878 cf_print_status_t status;
880 args = (print_args_t *)OBJECT_GET_DATA(ok_bt, PRINT_ARGS_KEY);
882 /* Check whether the range is valid. */
883 if (!range_check_validity(&args->range)) {
884 /* The range isn't valid; don't dismiss the print/export dialog box,
885 just leave it around so that the user can, after they
886 dismiss the alert box popped up for the error, try again. */
890 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_DEST_CB_KEY);
891 args->to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
894 g_dest = gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
895 PRINT_FILE_TE_KEY)));
897 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
898 "Output to file, but no file specified.");
902 args->file = g_strdup(g_dest);
903 /* Save the directory name for future file dialogs. */
904 f_name = g_strdup(g_dest);
905 dirname = get_dirname(f_name); /* Overwrites f_name */
906 set_last_open_dir(dirname);
911 /* We currently don't have a function in util.h to create just a tempfile */
912 /* name, so simply create a tempfile using the "official" function, */
913 /* then delete this file again. After this, the name MUST be available. */
915 /* Don't use tmpnam() or such, as this will fail under some ACL */
916 /* circumstances: http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=358 */
918 tmp_fd = create_tempfile(tmp_namebuf, sizeof(tmp_namebuf), "ethprint");
920 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
921 "Couldn't create a temporary file for printing.");
924 /* remember to restore these values later! */
925 tmp_oldfile = args->file;
926 args->file = g_strdup(tmp_namebuf);
927 eth_unlink(args->file);
928 args->to_file = TRUE;
931 args->cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
932 PRINT_CMD_TE_KEY))));
936 args->format = PR_FMT_TEXT;
937 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PS_RB_KEY);
938 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
939 args->format = PR_FMT_PS;
940 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PDML_RB_KEY);
941 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
942 export_as_pdml = TRUE;
943 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PSML_RB_KEY);
944 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
945 export_as_psml = TRUE;
946 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_CSV_RB_KEY);
947 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
948 export_as_csv = TRUE;
950 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY);
951 args->print_summary = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
953 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_COLLAPSE_ALL_RB_KEY);
954 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
955 args->print_dissections = print_dissections_collapsed;
957 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_AS_DISPLAYED_RB_KEY);
958 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
959 args->print_dissections = print_dissections_as_displayed;
961 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_EXPAND_ALL_RB_KEY);
962 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
963 args->print_dissections = print_dissections_expanded;
966 /* the details setting has priority over the radio buttons */
967 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_DETAILS_CB_KEY);
968 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
969 args->print_dissections = print_dissections_none;
972 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_HEX_CB_KEY);
973 args->print_hex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
975 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_FORMFEED_CB_KEY);
976 args->print_formfeed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
979 window_destroy(GTK_WIDGET(parent_w));
981 /* Now print/export the packets */
983 status = cf_write_pdml_packets(&cfile, args);
984 else if (export_as_psml)
985 status = cf_write_psml_packets(&cfile, args);
986 else if (export_as_csv)
987 status = cf_write_csv_packets(&cfile, args);
989 switch (args->format) {
993 args->stream = print_stream_text_new(TRUE, args->file);
994 if (args->stream == NULL) {
995 open_failure_alert_box(args->file, errno, TRUE);
999 args->stream = print_stream_text_new(FALSE, args->cmd);
1000 if (args->stream == NULL) {
1001 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1002 "Couldn't run print command %s.", args->cmd);
1008 if (args->to_file) {
1009 args->stream = print_stream_ps_new(TRUE, args->file);
1010 if (args->stream == NULL) {
1011 open_failure_alert_box(args->file, errno, TRUE);
1015 args->stream = print_stream_ps_new(FALSE, args->cmd);
1016 if (args->stream == NULL) {
1017 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1018 "Couldn't run print command %s.", args->cmd);
1024 g_assert_not_reached();
1027 status = cf_print_packets(&cfile, args);
1034 case CF_PRINT_OPEN_ERROR:
1036 open_failure_alert_box(args->file, errno, TRUE);
1038 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't run print command %s.",
1042 case CF_PRINT_WRITE_ERROR:
1044 write_failure_alert_box(args->file, errno);
1046 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1047 "Error writing to print command: %s", strerror(errno));
1053 print_mswin(args->file);
1055 /* trash temp file */
1056 eth_remove(args->file);
1058 /* restore old settings */
1059 args->to_file = FALSE;
1060 args->file = tmp_oldfile;
1066 print_destroy_cb(GtkWidget *win, gpointer user_data)
1070 /* Is there a file selection dialog associated with this
1071 Print File dialog? */
1072 fs = OBJECT_GET_DATA(win, E_FILE_SEL_DIALOG_PTR_KEY);
1075 /* Yes. Destroy it. */
1079 /* Note that we no longer have a "Print" dialog box. */
1080 *((gpointer *) user_data) = NULL;