2 * Dialog boxes for printing and exporting to text files
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.
36 #include <epan/prefs.h>
37 #include "alert_box.h"
38 #include "simple_dialog.h"
41 #include "dlg_utils.h"
43 #include <epan/epan_dissect.h>
44 #include <epan/filesystem.h>
47 #include "print_mswin.h"
49 #include "compat_macros.h"
50 #include "range_utils.h"
54 /* dialog output action */
56 output_action_print, /* print text to printer */
57 output_action_export_text, /* export to plain text */
58 output_action_export_ps, /* export to postscript */
59 output_action_export_psml, /* export to packet summary markup language */
60 output_action_export_pdml /* export to packet data markup language */
64 /* On Win32, a GUI application apparently can't use "popen()" (it
65 "returns an invalid file handle, if used in a Windows program,
66 that will cause the program to hang indefinitely"), so we can't
67 use a pipe to a print command to print to a printer.
69 Eventually, we should try to use the native Win32 printing API
70 for this (and also use various UNIX printing APIs, when present?).
74 open_print_dialog(char *title, output_action_e action, print_args_t *args);
75 static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data);
76 static void print_cmd_toggle_detail(GtkWidget *widget, gpointer data);
77 static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
78 static void print_destroy_cb(GtkWidget *win, gpointer user_data);
82 #define PRINT_ARGS_KEY "printer_args"
84 #define PRINT_PS_RB_KEY "printer_ps_radio_button"
85 #define PRINT_PDML_RB_KEY "printer_pdml_radio_button"
86 #define PRINT_PSML_RB_KEY "printer_psml_radio_button"
87 #define PRINT_DEST_CB_KEY "printer_destination_check_button"
89 #define PRINT_SUMMARY_CB_KEY "printer_summary_check_button"
90 #define PRINT_DETAILS_CB_KEY "printer_details_check_button"
91 #define PRINT_COLLAPSE_ALL_RB_KEY "printer_collapse_all_radio_button"
92 #define PRINT_AS_DISPLAYED_RB_KEY "printer_as_displayed_radio_button"
93 #define PRINT_EXPAND_ALL_RB_KEY "printer_expand_all_radio_button"
94 #define PRINT_HEX_CB_KEY "printer_hex_check_button"
95 #define PRINT_FORMFEED_CB_KEY "printer_formfeed_check_button"
97 #define PRINT_BT_KEY "printer_button"
99 #define PRINT_TE_PTR_KEY "printer_file_te_ptr"
103 * Keep a static pointer to the current "Print" window, if any, so that if
104 * somebody tries to do "File:Print" while there's already a "Print" window
105 * up, we just pop up the existing one, rather than creating a new one.
107 static GtkWidget *print_win = NULL;
109 static print_args_t print_args;
111 static gboolean print_prefs_init = FALSE;
115 file_print_cmd(gboolean print_selected)
117 print_args_t *args = &print_args;
119 if (print_win != NULL) {
120 /* There's already a "Print" dialog box; reactivate it. */
121 reactivate_window(print_win);
125 /* get settings from preferences (and other initial values) only once */
126 if(print_prefs_init == FALSE) {
127 print_prefs_init = TRUE;
128 args->format = prefs.pr_format;
129 args->to_file = prefs.pr_dest;
130 args->file = g_strdup(prefs.pr_file);
131 args->cmd = g_strdup(prefs.pr_cmd);
132 args->print_summary = TRUE;
133 args->print_dissections = print_dissections_as_displayed;
134 args->print_hex = FALSE;
135 args->print_formfeed = FALSE;
138 /* init the printing range */
139 packet_range_init(&args->range);
142 args->range.process = range_process_selected;
145 print_win = open_print_dialog("Ethereal: Print", output_action_print, args);
146 SIGNAL_CONNECT(print_win, "destroy", print_destroy_cb, &print_win);
150 file_print_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
152 file_print_cmd(FALSE);
156 file_print_selected_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
158 file_print_cmd(TRUE);
162 * Keep a static pointer to the current "Export text" window, if any, so that if
163 * somebody tries to do "File:Export to text" while there's already a "Export text" window
164 * up, we just pop up the existing one, rather than creating a new one.
166 static GtkWidget *export_text_win = NULL;
168 static print_args_t export_text_args;
170 static gboolean export_text_prefs_init = FALSE;
174 export_text_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
176 print_args_t *args = &export_text_args;
178 if (export_text_win != NULL) {
179 /* There's already a "Export text" dialog box; reactivate it. */
180 reactivate_window(export_text_win);
184 /* get settings from preferences (and other initial values) only once */
185 if(export_text_prefs_init == FALSE) {
186 export_text_prefs_init = TRUE;
187 args->format = PR_FMT_TEXT;
188 args->to_file = TRUE;
189 args->file = g_strdup("");
190 args->cmd = g_strdup("");
191 args->print_summary = TRUE;
192 args->print_dissections = print_dissections_as_displayed;
193 args->print_hex = FALSE;
194 args->print_formfeed = FALSE;
197 /* init the printing range */
198 packet_range_init(&args->range);
200 export_text_win = open_print_dialog("Ethereal: Export as \"Plain Text\" File", output_action_export_text, args);
201 SIGNAL_CONNECT(export_text_win, "destroy", print_destroy_cb, &export_text_win);
206 * Keep a static pointer to the current "Export ps" window, if any, so that if
207 * somebody tries to do "File:Export to ps" while there's already a "Export ps" window
208 * up, we just pop up the existing one, rather than creating a new one.
210 static GtkWidget *export_ps_win = NULL;
212 static print_args_t export_ps_args;
214 static gboolean export_ps_prefs_init = FALSE;
218 export_ps_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
220 print_args_t *args = &export_ps_args;
222 if (export_ps_win != NULL) {
223 /* There's already a "Export ps" dialog box; reactivate it. */
224 reactivate_window(export_ps_win);
228 /* get settings from preferences (and other initial values) only once */
229 if(export_ps_prefs_init == FALSE) {
230 export_ps_prefs_init = TRUE;
231 args->format = PR_FMT_PS;
232 args->to_file = TRUE;
233 args->file = g_strdup("");
234 args->cmd = g_strdup("");
235 args->print_summary = TRUE;
236 args->print_dissections = print_dissections_as_displayed;
237 args->print_hex = FALSE;
238 args->print_formfeed = FALSE;
241 /* init the printing range */
242 packet_range_init(&args->range);
244 export_ps_win = open_print_dialog("Ethereal: Export as \"PostScript\" file", output_action_export_ps, args);
245 SIGNAL_CONNECT(export_ps_win, "destroy", print_destroy_cb, &export_ps_win);
250 * Keep a static pointer to the current "Export psml" window, if any, so that if
251 * somebody tries to do "File:Export to psml" while there's already a "Export psml" window
252 * up, we just pop up the existing one, rather than creating a new one.
254 static GtkWidget *export_psml_win = NULL;
256 static print_args_t export_psml_args;
258 static gboolean export_psml_prefs_init = FALSE;
262 export_psml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
264 print_args_t *args = &export_psml_args;
266 if (export_psml_win != NULL) {
267 /* There's already a "Export psml" dialog box; reactivate it. */
268 reactivate_window(export_psml_win);
272 /* get settings from preferences (and other initial values) only once */
273 if(export_psml_prefs_init == FALSE) {
274 export_psml_prefs_init = TRUE;
275 args->format = PR_FMT_TEXT; /* XXX */
276 args->to_file = TRUE;
277 args->file = g_strdup("");
278 args->cmd = g_strdup("");
279 args->print_summary = TRUE;
280 args->print_dissections = print_dissections_as_displayed;
281 args->print_hex = FALSE;
282 args->print_formfeed = FALSE;
285 /* init the printing range */
286 packet_range_init(&args->range);
288 export_psml_win = open_print_dialog("Ethereal: Export as \"PSML\" file", output_action_export_psml, args);
289 SIGNAL_CONNECT(export_psml_win, "destroy", print_destroy_cb, &export_psml_win);
294 * Keep a static pointer to the current "Export pdml" window, if any, so that if
295 * somebody tries to do "File:Export to pdml" while there's already a "Export pdml" window
296 * up, we just pop up the existing one, rather than creating a new one.
298 static GtkWidget *export_pdml_win = NULL;
300 static print_args_t export_pdml_args;
302 static gboolean export_pdml_prefs_init = FALSE;
306 export_pdml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
308 print_args_t *args = &export_pdml_args;
310 if (export_pdml_win != NULL) {
311 /* There's already a "Export pdml" dialog box; reactivate it. */
312 reactivate_window(export_pdml_win);
316 /* get settings from preferences (and other initial values) only once */
317 if(export_pdml_prefs_init == FALSE) {
318 export_pdml_prefs_init = TRUE;
319 args->format = PR_FMT_TEXT; /* XXX */
320 args->to_file = TRUE;
321 args->file = g_strdup("");
322 args->cmd = g_strdup("");
323 args->print_summary = TRUE;
324 args->print_dissections = print_dissections_as_displayed;
325 args->print_hex = FALSE;
326 args->print_formfeed = FALSE;
329 /* init the printing range */
330 packet_range_init(&args->range);
332 export_pdml_win = open_print_dialog("Ethereal: Export as \"PDML\" file", output_action_export_pdml, args);
333 SIGNAL_CONNECT(export_pdml_win, "destroy", print_destroy_cb, &export_pdml_win);
338 print_browse_file_cb(GtkWidget *file_bt, GtkWidget *file_te)
340 file_selection_browse(file_bt, file_te, "Ethereal: Print to File",
341 FILE_SELECTION_WRITE_BROWSE);
346 /* Open the print dialog */
348 open_print_dialog(char *title, output_action_e action, print_args_t *args)
350 #if GTK_MAJOR_VERSION < 2
351 GtkAccelGroup *accel_group;
357 GtkWidget *printer_fr, *printer_vb, *export_format_lb;
358 GtkWidget *text_rb, *ps_rb, *pdml_rb, *psml_rb;
359 GtkWidget *printer_tb, *dest_cb;
361 GtkWidget *cmd_lb, *cmd_te;
363 GtkWidget *file_bt, *file_te;
365 GtkWidget *range_fr, *range_tb;
367 GtkWidget *packet_hb;
369 GtkWidget *format_fr, *format_vb;
370 GtkWidget *summary_cb;
372 GtkWidget *details_cb;
373 GtkWidget *details_hb, *details_vb;
374 GtkWidget *collapse_all_rb, *as_displayed_rb, *expand_all_rb;
376 GtkWidget *sep, *formfeed_cb;
378 GtkWidget *bbox, *ok_bt, *cancel_bt, *help_bt;
380 GtkTooltips *tooltips;
384 main_win = dlg_window_new(title);
386 /* Enable tooltips */
387 tooltips = gtk_tooltips_new();
389 #if GTK_MAJOR_VERSION < 2
390 /* Accelerator group for the accelerators (or, as they're called in
391 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
392 Ctrl+<key> is an accelerator). */
393 accel_group = gtk_accel_group_new();
394 gtk_window_add_accel_group(GTK_WINDOW(main_win), accel_group);
397 /* Vertical enclosing container for each row of widgets */
398 main_vb = gtk_vbox_new(FALSE, 5);
399 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
400 gtk_container_add(GTK_CONTAINER(main_win), main_vb);
401 gtk_widget_show(main_vb);
403 /*****************************************************/
405 /*** printer frame ***/
406 printer_fr = gtk_frame_new(action == output_action_print ? "Printer" : "Export to file:");
407 gtk_box_pack_start(GTK_BOX(main_vb), printer_fr, FALSE, FALSE, 0);
408 gtk_widget_show(printer_fr);
409 printer_vb = gtk_vbox_new(FALSE, 5);
410 gtk_container_border_width(GTK_CONTAINER(printer_vb), 5);
411 gtk_container_add(GTK_CONTAINER(printer_fr), printer_vb);
412 gtk_widget_show(printer_vb);
414 /* "Plain text" / "Postscript" / "PDML", ... radio buttons */
415 text_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Plain _text", accel_group);
416 if (args->format == PR_FMT_TEXT)
417 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(text_rb), TRUE);
418 gtk_tooltips_set_tip (tooltips, text_rb, "Print output in ascii \"plain text\" format. If you're unsure, use this format.", NULL);
419 gtk_box_pack_start(GTK_BOX(printer_vb), text_rb, FALSE, FALSE, 0);
420 if(action == output_action_print)
421 gtk_widget_show(text_rb);
423 ps_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "_PostScript", accel_group);
424 if (args->format == PR_FMT_PS)
425 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ps_rb), TRUE);
426 gtk_tooltips_set_tip (tooltips, ps_rb, "Print output in \"postscript\" format, for postscript capable printers or print servers.", NULL);
427 gtk_box_pack_start(GTK_BOX(printer_vb), ps_rb, FALSE, FALSE, 0);
428 if(action == output_action_print)
429 gtk_widget_show(ps_rb);
431 pdml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PDM_L (XML: Packet Details Markup Language)", accel_group);
432 if (action == output_action_export_pdml)
433 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(pdml_rb), TRUE);
434 gtk_tooltips_set_tip (tooltips, pdml_rb,
435 "Print output in \"PDML\" (Packet Details Markup Language), "
436 "an XML based packet data interchange format. "
437 "Usually used in combination with the \"Output to file\" option to export packet data into an XML file.", NULL);
438 gtk_box_pack_start(GTK_BOX(printer_vb), pdml_rb, FALSE, FALSE, 0);
439 /* gtk_widget_show(pdml_rb); */
441 psml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PSML (XML: Packet Summary Markup Language)", accel_group);
442 if (action == output_action_export_psml)
443 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(psml_rb), TRUE);
444 gtk_tooltips_set_tip (tooltips, psml_rb,
445 "Print output in \"PSML\" (Packet Summary Markup Language), "
446 "an XML based packet summary interchange format. "
447 "Usually used in combination with the \"Output to file\" option to export packet data into an XML file.", NULL);
448 gtk_box_pack_start(GTK_BOX(printer_vb), psml_rb, FALSE, FALSE, 0);
449 /* gtk_widget_show(psml_rb); */
453 printer_tb = gtk_table_new(2, 3, FALSE);
455 printer_tb = gtk_table_new(2, 2, FALSE);
457 gtk_box_pack_start(GTK_BOX(printer_vb), printer_tb, FALSE, FALSE, 0);
458 gtk_table_set_row_spacings(GTK_TABLE(printer_tb), 5);
459 gtk_table_set_col_spacings(GTK_TABLE(printer_tb), 5);
460 gtk_widget_show(printer_tb);
463 /* Output to file button */
464 dest_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Output to _file:", accel_group);
466 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dest_cb), TRUE);
467 gtk_tooltips_set_tip (tooltips, dest_cb, "Output to file instead of printer", NULL);
468 gtk_table_attach_defaults(GTK_TABLE(printer_tb), dest_cb, 0, 1, 0, 1);
469 if(action == output_action_print)
470 gtk_widget_show(dest_cb);
472 /* File text entry */
473 file_te = gtk_entry_new();
474 OBJECT_SET_DATA(dest_cb, PRINT_FILE_TE_KEY, file_te);
475 gtk_tooltips_set_tip (tooltips, file_te, "Enter Output filename", NULL);
476 gtk_entry_set_text(GTK_ENTRY(file_te), args->file);
477 gtk_table_attach_defaults(GTK_TABLE(printer_tb), file_te, 1, 2, 0, 1);
478 gtk_widget_set_sensitive(file_te, args->to_file);
479 gtk_widget_show(file_te);
481 gtk_widget_grab_focus(file_te);
483 /* "Browse" button */
484 file_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_BROWSE);
485 OBJECT_SET_DATA(dest_cb, PRINT_FILE_BT_KEY, file_bt);
486 OBJECT_SET_DATA(file_bt, PRINT_TE_PTR_KEY, file_te);
487 gtk_tooltips_set_tip (tooltips, file_bt, "Browse output filename in filesystem", NULL);
488 gtk_table_attach_defaults(GTK_TABLE(printer_tb), file_bt, 2, 3, 0, 1);
489 gtk_widget_set_sensitive(file_bt, args->to_file);
490 gtk_widget_show(file_bt);
492 /* Command label and text entry */
494 cmd_lb = gtk_label_new("Print command:");
495 OBJECT_SET_DATA(dest_cb, PRINT_CMD_LB_KEY, cmd_lb);
496 gtk_misc_set_alignment(GTK_MISC(cmd_lb), 1.0, 0.5);
497 gtk_table_attach_defaults(GTK_TABLE(printer_tb), cmd_lb, 0, 1, 1, 2);
498 gtk_widget_set_sensitive(cmd_lb, !args->to_file);
499 if(action == output_action_print)
500 gtk_widget_show(cmd_lb);
502 cmd_te = gtk_entry_new();
503 OBJECT_SET_DATA(dest_cb, PRINT_CMD_TE_KEY, cmd_te);
504 gtk_tooltips_set_tip (tooltips, cmd_te, "Enter print command", NULL);
505 gtk_entry_set_text(GTK_ENTRY(cmd_te), args->cmd);
506 gtk_table_attach_defaults(GTK_TABLE(printer_tb), cmd_te, 1, 2, 1, 2);
507 gtk_widget_set_sensitive(cmd_te, !args->to_file);
508 if(action == output_action_print)
509 gtk_widget_show(cmd_te);
512 SIGNAL_CONNECT(dest_cb, "toggled", print_cmd_toggle_dest, NULL);
513 SIGNAL_CONNECT(file_bt, "clicked", print_browse_file_cb, file_te);
515 if(action == output_action_export_ps) {
516 export_format_lb = gtk_label_new("(PostScript files can be easily converted to PDF files using ghostscript's ps2pdf)");
517 gtk_box_pack_start(GTK_BOX(printer_vb), export_format_lb, FALSE, FALSE, 0);
518 gtk_widget_show(export_format_lb);
521 /*****************************************************/
523 /*** hor box for range and format frames ***/
524 packet_hb = gtk_hbox_new(FALSE, 5);
525 gtk_container_add(GTK_CONTAINER(main_vb), packet_hb);
526 gtk_widget_show(packet_hb);
528 /*** packet range frame ***/
529 range_fr = gtk_frame_new("Packet Range");
530 gtk_box_pack_start(GTK_BOX(packet_hb), range_fr, FALSE, FALSE, 0);
531 gtk_widget_show(range_fr);
533 range_tb = range_new(&args->range
534 #if GTK_MAJOR_VERSION < 2
538 gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
539 gtk_widget_show(range_tb);
541 /*****************************************************/
543 /*** packet format frame ***/
544 format_fr = gtk_frame_new("Packet Format");
545 gtk_box_pack_start(GTK_BOX(packet_hb), format_fr, TRUE, TRUE, 0);
546 if( action == output_action_print ||
547 action == output_action_export_text ||
548 action == output_action_export_ps)
549 gtk_widget_show(format_fr);
550 format_vb = gtk_vbox_new(FALSE, 5);
551 gtk_container_border_width(GTK_CONTAINER(format_vb), 5);
552 gtk_container_add(GTK_CONTAINER(format_fr), format_vb);
553 gtk_widget_show(format_vb);
555 /* "Print summary line" check button */
556 summary_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet summary line", accel_group);
557 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(summary_cb), args->print_summary);
558 SIGNAL_CONNECT(summary_cb, "clicked", print_cmd_toggle_detail, main_win);
559 gtk_tooltips_set_tip (tooltips, summary_cb, "Output of a packet summary line, like in the packet list", NULL);
560 gtk_container_add(GTK_CONTAINER(format_vb), summary_cb);
561 gtk_widget_show(summary_cb);
564 /* "Details" check button */
565 details_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet details:", accel_group);
566 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(details_cb), args->print_dissections != print_dissections_none);
567 SIGNAL_CONNECT(details_cb, "clicked", print_cmd_toggle_detail, main_win);
568 gtk_tooltips_set_tip (tooltips, details_cb, "Output format of the selected packet details (protocol tree).", NULL);
569 gtk_container_add(GTK_CONTAINER(format_vb), details_cb);
570 gtk_widget_show(details_cb);
572 /*** packet details ***/
573 details_hb = gtk_hbox_new(FALSE, 6);
574 gtk_container_border_width(GTK_CONTAINER(details_hb), 0);
575 gtk_container_add(GTK_CONTAINER(format_vb), details_hb);
576 gtk_widget_show(details_hb);
578 details_vb = gtk_vbox_new(FALSE, 6);
579 gtk_container_border_width(GTK_CONTAINER(details_vb), 0);
580 gtk_container_add(GTK_CONTAINER(details_hb), details_vb);
581 gtk_widget_show(details_vb);
583 details_vb = gtk_vbox_new(FALSE, 6);
584 gtk_container_border_width(GTK_CONTAINER(details_vb), 0);
585 gtk_container_add(GTK_CONTAINER(details_hb), details_vb);
586 gtk_widget_show(details_vb);
588 /* "All collapsed"/"As displayed"/"All Expanded" radio buttons */
589 collapse_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "All co_llapsed", accel_group);
590 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(collapse_all_rb), args->print_dissections == print_dissections_collapsed);
591 gtk_tooltips_set_tip (tooltips, collapse_all_rb, "Output of the packet details tree \"collapsed\"", NULL);
592 gtk_container_add(GTK_CONTAINER(details_vb), collapse_all_rb);
593 gtk_widget_show(collapse_all_rb);
595 as_displayed_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(collapse_all_rb, "As displa_yed", accel_group);
596 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(as_displayed_rb), args->print_dissections == print_dissections_as_displayed);
597 gtk_tooltips_set_tip (tooltips, as_displayed_rb, "Output of the packet details tree \"as displayed\"", NULL);
598 gtk_container_add(GTK_CONTAINER(details_vb), as_displayed_rb);
599 gtk_widget_show(as_displayed_rb);
601 expand_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(collapse_all_rb, "All e_xpanded", accel_group);
602 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(expand_all_rb), args->print_dissections == print_dissections_expanded);
603 gtk_tooltips_set_tip (tooltips, expand_all_rb, "Output of the packet details tree \"expanded\"", NULL);
604 gtk_container_add(GTK_CONTAINER(details_vb), expand_all_rb);
605 gtk_widget_show(expand_all_rb);
607 /* "Print hex" check button. */
608 hex_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet bytes", accel_group);
609 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(hex_cb), args->print_hex);
610 SIGNAL_CONNECT(hex_cb, "clicked", print_cmd_toggle_detail, main_win);
611 gtk_tooltips_set_tip (tooltips, hex_cb, "Add a hexdump of the packet data", NULL);
612 gtk_container_add(GTK_CONTAINER(format_vb), hex_cb);
613 gtk_widget_show(hex_cb);
616 sep = gtk_hseparator_new();
617 gtk_container_add(GTK_CONTAINER(format_vb), sep);
618 gtk_widget_show(sep);
620 /* "Each packet on a new page" check button. */
621 formfeed_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Each packet on a new page", accel_group);
622 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(formfeed_cb), args->print_formfeed);
623 gtk_tooltips_set_tip (tooltips, formfeed_cb, "When checked, a new page will be used for each packet. "
624 "This is done by adding a formfeed (or similar) between the packet outputs.", NULL);
625 gtk_container_add(GTK_CONTAINER(format_vb), formfeed_cb);
626 gtk_widget_show(formfeed_cb);
629 OBJECT_SET_DATA(main_win, PRINT_ARGS_KEY, args);
630 OBJECT_SET_DATA(main_win, PRINT_SUMMARY_CB_KEY, summary_cb);
631 OBJECT_SET_DATA(main_win, PRINT_DETAILS_CB_KEY, details_cb);
632 OBJECT_SET_DATA(main_win, PRINT_COLLAPSE_ALL_RB_KEY, collapse_all_rb);
633 OBJECT_SET_DATA(main_win, PRINT_AS_DISPLAYED_RB_KEY, as_displayed_rb);
634 OBJECT_SET_DATA(main_win, PRINT_EXPAND_ALL_RB_KEY, expand_all_rb);
635 OBJECT_SET_DATA(main_win, PRINT_HEX_CB_KEY, hex_cb);
637 /*****************************************************/
641 if(topic_available(HELP_PRINT_DIALOG)) {
642 bbox = dlg_button_row_new(action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
644 bbox = dlg_button_row_new(action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
646 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
647 gtk_widget_show(bbox);
649 ok_bt = OBJECT_GET_DATA(bbox, action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK);
651 OBJECT_SET_DATA(main_win, PRINT_BT_KEY, ok_bt);
653 OBJECT_SET_DATA(ok_bt, PRINT_PS_RB_KEY, ps_rb);
654 OBJECT_SET_DATA(ok_bt, PRINT_PDML_RB_KEY, pdml_rb);
655 OBJECT_SET_DATA(ok_bt, PRINT_PSML_RB_KEY, psml_rb);
656 OBJECT_SET_DATA(ok_bt, PRINT_DEST_CB_KEY, dest_cb);
658 OBJECT_SET_DATA(ok_bt, PRINT_CMD_TE_KEY, cmd_te);
661 OBJECT_SET_DATA(ok_bt, PRINT_ARGS_KEY, args);
662 OBJECT_SET_DATA(ok_bt, PRINT_FILE_TE_KEY, file_te);
663 OBJECT_SET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY, summary_cb);
664 OBJECT_SET_DATA(ok_bt, PRINT_DETAILS_CB_KEY, details_cb);
665 OBJECT_SET_DATA(ok_bt, PRINT_COLLAPSE_ALL_RB_KEY, collapse_all_rb);
666 OBJECT_SET_DATA(ok_bt, PRINT_AS_DISPLAYED_RB_KEY, as_displayed_rb);
667 OBJECT_SET_DATA(ok_bt, PRINT_EXPAND_ALL_RB_KEY, expand_all_rb);
668 OBJECT_SET_DATA(ok_bt, PRINT_HEX_CB_KEY, hex_cb);
669 OBJECT_SET_DATA(ok_bt, PRINT_FORMFEED_CB_KEY, formfeed_cb);
670 SIGNAL_CONNECT(ok_bt, "clicked", print_ok_cb, main_win);
671 gtk_tooltips_set_tip (tooltips, ok_bt, "Start output", NULL);
673 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
674 window_set_cancel_button(main_win, cancel_bt, window_cancel_button_cb);
675 gtk_tooltips_set_tip (tooltips, cancel_bt, "Cancel and exit dialog", NULL);
677 if(topic_available(HELP_PRINT_DIALOG)) {
678 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
679 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_PRINT_DIALOG);
682 gtk_widget_grab_default(ok_bt);
684 /* Catch the "activate" signal on the "Command" and "File" text entries,
685 so that if the user types Return there, we act as if the "OK" button
686 had been selected, as happens if Return is typed if some widget
687 that *doesn't* handle the Return key has the input focus. */
689 dlg_set_activate(cmd_te, ok_bt);
691 if(action != output_action_print)
692 dlg_set_activate(file_te, ok_bt);
694 SIGNAL_CONNECT(main_win, "delete_event", window_delete_event_cb, NULL);
696 gtk_widget_show(main_win);
697 window_present(main_win);
703 /* user changed "print to" destination */
705 print_cmd_toggle_dest(GtkWidget *widget, gpointer data _U_)
708 GtkWidget *cmd_lb, *cmd_te;
710 GtkWidget *file_bt, *file_te;
714 cmd_lb = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_CMD_LB_KEY));
715 cmd_te = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_CMD_TE_KEY));
717 file_bt = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_FILE_BT_KEY));
718 file_te = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_FILE_TE_KEY));
720 to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
722 gtk_widget_set_sensitive(cmd_lb, !to_file);
723 gtk_widget_set_sensitive(cmd_te, !to_file);
725 gtk_widget_set_sensitive(file_bt, to_file);
726 gtk_widget_set_sensitive(file_te, to_file);
730 /* user changed "packet details" */
732 print_cmd_toggle_detail(GtkWidget *widget _U_, gpointer data)
734 GtkWidget *print_bt, *summary_cb, *details_cb, *collapse_all_rb, *expand_all_rb, *as_displayed_rb, *hex_cb;
735 gboolean print_detail;
738 print_bt = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_BT_KEY));
739 summary_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_SUMMARY_CB_KEY));
740 details_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_DETAILS_CB_KEY));
741 collapse_all_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_COLLAPSE_ALL_RB_KEY));
742 as_displayed_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_AS_DISPLAYED_RB_KEY));
743 expand_all_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_EXPAND_ALL_RB_KEY));
744 hex_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_HEX_CB_KEY));
746 /* is user disabled details, disable the corresponding buttons */
747 print_detail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (details_cb));
748 gtk_widget_set_sensitive(collapse_all_rb, print_detail);
749 gtk_widget_set_sensitive(as_displayed_rb, print_detail);
750 gtk_widget_set_sensitive(expand_all_rb, print_detail);
752 /* if user selected nothing to print at all, disable the "ok" button */
753 gtk_widget_set_sensitive(print_bt,
754 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (summary_cb)) ||
755 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (details_cb)) ||
756 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_cb)));
761 print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
768 gboolean export_as_pdml = FALSE, export_as_psml = FALSE;
770 gboolean win_printer = FALSE;
772 cf_print_status_t status;
774 args = (print_args_t *)OBJECT_GET_DATA(ok_bt, PRINT_ARGS_KEY);
776 /* Check whether the range is valid. */
777 if (!range_check_validity(&args->range)) {
778 /* The range isn't valid; don't dismiss the print/export dialog box,
779 just leave it around so that the user can, after they
780 dismiss the alert box popped up for the error, try again. */
784 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_DEST_CB_KEY);
785 args->to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
788 g_dest = gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
789 PRINT_FILE_TE_KEY)));
791 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
792 "Output to file, but no file specified.");
796 args->file = g_strdup(g_dest);
797 /* Save the directory name for future file dialogs. */
798 f_name = g_strdup(g_dest);
799 dirname = get_dirname(f_name); /* Overwrites f_name */
800 set_last_open_dir(dirname);
805 /*XXX should use temp file stuff in util routines */
807 args->file = g_strdup(tmpnam(NULL));
808 args->to_file = TRUE;
811 args->cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
812 PRINT_CMD_TE_KEY))));
816 args->format = PR_FMT_TEXT;
817 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PS_RB_KEY);
818 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
819 args->format = PR_FMT_PS;
820 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PDML_RB_KEY);
821 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
822 export_as_pdml = TRUE;
823 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PSML_RB_KEY);
824 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
825 export_as_psml = TRUE;
827 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY);
828 args->print_summary = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
830 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_COLLAPSE_ALL_RB_KEY);
831 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
832 args->print_dissections = print_dissections_collapsed;
834 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_AS_DISPLAYED_RB_KEY);
835 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
836 args->print_dissections = print_dissections_as_displayed;
838 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_EXPAND_ALL_RB_KEY);
839 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
840 args->print_dissections = print_dissections_expanded;
843 /* the details setting has priority over the radio buttons */
844 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_DETAILS_CB_KEY);
845 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
846 args->print_dissections = print_dissections_none;
849 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_HEX_CB_KEY);
850 args->print_hex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
852 button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_FORMFEED_CB_KEY);
853 args->print_formfeed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
856 window_destroy(GTK_WIDGET(parent_w));
858 /* Now print/export the packets */
860 status = cf_write_pdml_packets(&cfile, args);
861 else if (export_as_psml)
862 status = cf_write_psml_packets(&cfile, args);
864 switch (args->format) {
868 args->stream = print_stream_text_new(TRUE, args->file);
869 if (args->stream == NULL) {
870 open_failure_alert_box(args->file, errno, TRUE);
874 args->stream = print_stream_text_new(FALSE, args->cmd);
875 if (args->stream == NULL) {
876 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
877 "Couldn't run print command %s.", args->cmd);
884 args->stream = print_stream_ps_new(TRUE, args->file);
885 if (args->stream == NULL) {
886 open_failure_alert_box(args->file, errno, TRUE);
890 args->stream = print_stream_ps_new(FALSE, args->cmd);
891 if (args->stream == NULL) {
892 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
893 "Couldn't run print command %s.", args->cmd);
899 g_assert_not_reached();
902 status = cf_print_packets(&cfile, args);
909 case CF_PRINT_OPEN_ERROR:
911 open_failure_alert_box(args->file, errno, TRUE);
913 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't run print command %s.",
917 case CF_PRINT_WRITE_ERROR:
919 write_failure_alert_box(args->file, errno);
921 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
922 "Error writing to print command: %s", strerror(errno));
928 print_mswin(args->file);
930 /* trash temp file */
937 print_destroy_cb(GtkWidget *win, gpointer user_data)
941 /* Is there a file selection dialog associated with this
942 Print File dialog? */
943 fs = OBJECT_GET_DATA(win, E_FILE_SEL_DIALOG_PTR_KEY);
946 /* Yes. Destroy it. */
950 /* Note that we no longer have a "Print" dialog box. */
951 *((gpointer *) user_data) = NULL;