Immediately quit routines if fwrite() fails - further writes will
[obnox/wireshark/wip.git] / gtk / print_dlg.c
1 /* print_dlg.c
2  * Dialog boxes for printing and exporting to text files
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <string.h>
30
31 #include <gtk/gtk.h>
32
33 #include "globals.h"
34 #include "gtkglobals.h"
35 #include "keys.h"
36 #include "print.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"
43 #include "file_dlg.h"
44 #include "main.h"
45 #include <epan/epan_dissect.h>
46 #include <epan/filesystem.h>
47 #ifdef _WIN32
48 #include "print_mswin.h"
49 #endif
50 #include "compat_macros.h"
51 #include "range_utils.h"
52 #include "help_dlg.h"
53 #include "file_util.h"
54 #include "tempfile.h"
55 #include "util.h"
56
57 #if GTK_MAJOR_VERSION >= 2 && _WIN32
58 #include <gdk/gdkwin32.h>
59 #include <windows.h>
60 #include "win32-file-dlg.h"
61 #endif
62
63 /* dialog output action */
64 typedef enum {
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 */
71 } output_action_e;
72
73
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.
78
79   Eventually, we should try to use the native Win32 printing API
80   for this (and also use various UNIX printing APIs, when present?).
81 */
82
83 static GtkWidget *
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);
89
90
91
92 #define PRINT_ARGS_KEY            "printer_args"
93
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"
99
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"
107
108 #define PRINT_BT_KEY              "printer_button"
109
110 #define PRINT_TE_PTR_KEY          "printer_file_te_ptr"
111
112
113 /*
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.
117  */
118 static GtkWidget *print_win = NULL;
119
120 static print_args_t  print_args;
121
122 static gboolean print_prefs_init = FALSE;
123
124
125 static void
126 file_print_cmd(gboolean print_selected)
127 {
128   print_args_t *args = &print_args;
129
130   if (print_win != NULL) {
131     /* There's already a "Print" dialog box; reactivate it. */
132     reactivate_window(print_win);
133     return;
134   }
135
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;
147   }
148
149   /* init the printing range */
150   packet_range_init(&args->range);
151
152   if(print_selected) {
153       args->range.process = range_process_selected;
154   }
155
156   print_win = open_print_dialog("Wireshark: Print", output_action_print, args);
157   SIGNAL_CONNECT(print_win, "destroy", print_destroy_cb, &print_win);
158 }
159
160 void
161 file_print_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
162 {
163     file_print_cmd(FALSE);
164 }
165
166 void
167 file_print_selected_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
168 {
169     file_print_cmd(TRUE);
170 }
171
172 /*
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.
176  */
177 static GtkWidget *export_text_win = NULL;
178
179 static print_args_t  export_text_args;
180
181 static gboolean export_text_prefs_init = FALSE;
182
183
184 void
185 export_text_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
186 {
187   print_args_t *args = &export_text_args;
188
189 #if GTK_MAJOR_VERSION >= 2 && _WIN32
190   win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_text);
191   return;
192 #endif
193
194   if (export_text_win != NULL) {
195     /* There's already a "Export text" dialog box; reactivate it. */
196     reactivate_window(export_text_win);
197     return;
198   }
199
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;
211   }
212
213   /* init the printing range */
214   packet_range_init(&args->range);
215
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);
218 }
219
220
221 /*
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.
225  */
226 static GtkWidget *export_ps_win = NULL;
227
228 static print_args_t  export_ps_args;
229
230 static gboolean export_ps_prefs_init = FALSE;
231
232
233 void
234 export_ps_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
235 {
236   print_args_t *args = &export_ps_args;
237
238 #if GTK_MAJOR_VERSION >= 2 && _WIN32
239   win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_ps);
240   return;
241 #endif
242
243   if (export_ps_win != NULL) {
244     /* There's already a "Export ps" dialog box; reactivate it. */
245     reactivate_window(export_ps_win);
246     return;
247   }
248
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;
260   }
261
262   /* init the printing range */
263   packet_range_init(&args->range);
264
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);
267 }
268
269
270 /*
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.
274  */
275 static GtkWidget *export_psml_win = NULL;
276
277 static print_args_t  export_psml_args;
278
279 static gboolean export_psml_prefs_init = FALSE;
280
281
282 void
283 export_psml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
284 {
285   print_args_t *args = &export_psml_args;
286
287 #if GTK_MAJOR_VERSION >= 2 && _WIN32
288   win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_psml);
289   return;
290 #endif
291
292   if (export_psml_win != NULL) {
293     /* There's already a "Export psml" dialog box; reactivate it. */
294     reactivate_window(export_psml_win);
295     return;
296   }
297
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;
309   }
310
311   /* init the printing range */
312   packet_range_init(&args->range);
313
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);
316 }
317
318
319 /*
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.
323  */
324 static GtkWidget *export_pdml_win = NULL;
325
326 static print_args_t  export_pdml_args;
327
328 static gboolean export_pdml_prefs_init = FALSE;
329
330
331 void
332 export_pdml_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
333 {
334   print_args_t *args = &export_pdml_args;
335
336 #if GTK_MAJOR_VERSION >= 2 && _WIN32
337   win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_pdml);
338   return;
339 #endif
340
341   if (export_pdml_win != NULL) {
342     /* There's already a "Export pdml" dialog box; reactivate it. */
343     reactivate_window(export_pdml_win);
344     return;
345   }
346
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;
358   }
359
360   /* init the printing range */
361   packet_range_init(&args->range);
362
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);
365 }
366
367 /*
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.
371  */
372 static GtkWidget *export_csv_win = NULL;
373
374 static print_args_t  export_csv_args;
375
376 static gboolean export_csv_prefs_init = FALSE;
377
378 void
379 export_csv_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
380 {
381   print_args_t *args = &export_csv_args;
382
383 #if GTK_MAJOR_VERSION >= 2 && _WIN32
384   win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_csv);
385   return;
386 #endif
387
388   if (export_csv_win != NULL) {
389     /* There's already a "Export csv" dialog box; reactivate it. */
390     reactivate_window(export_csv_win);
391     return;
392   }
393
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;
405   }
406
407   /* init the printing range */
408   packet_range_init(&args->range);
409
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);
412 }
413
414 static void
415 print_browse_file_cb(GtkWidget *file_bt, GtkWidget *file_te)
416 {
417     file_selection_browse(file_bt, file_te, "Wireshark: Print to File",
418                           FILE_SELECTION_WRITE_BROWSE);
419 }
420
421
422
423 /* Open the print dialog */
424 static GtkWidget *
425 open_print_dialog(const char *title, output_action_e action, print_args_t *args)
426 {
427 #if GTK_MAJOR_VERSION < 2
428   GtkAccelGroup *accel_group;
429 #endif
430
431   GtkWidget     *main_win;
432   GtkWidget     *main_vb;
433
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;
437 #ifndef _WIN32
438   GtkWidget     *cmd_lb, *cmd_te;
439 #endif
440   GtkWidget     *file_bt, *file_te;
441
442   GtkWidget     *range_fr, *range_tb;
443
444   GtkWidget     *packet_hb;
445
446   GtkWidget     *format_fr, *format_vb;
447   GtkWidget     *summary_cb;
448
449   GtkWidget     *details_cb;
450   GtkWidget     *details_hb, *details_vb;
451   GtkWidget     *collapse_all_rb, *as_displayed_rb, *expand_all_rb;
452   GtkWidget     *hex_cb;
453   GtkWidget     *sep, *formfeed_cb;
454
455   GtkWidget     *bbox, *ok_bt, *cancel_bt, *help_bt;
456
457   GtkTooltips   *tooltips;
458
459
460   /* dialog window */
461   main_win = dlg_window_new(title);
462
463   /* Enable tooltips */
464   tooltips = gtk_tooltips_new();
465
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);
472 #endif
473
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);
479
480 /*****************************************************/
481
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);
490
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);
499
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);
507
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); */
517
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); */
527
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); */
537
538   /* printer table */
539 #ifndef _WIN32
540   printer_tb = gtk_table_new(2, 3, FALSE);
541 #else
542   printer_tb = gtk_table_new(2, 2, FALSE);
543 #endif
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);
548
549
550   /* Output to file button */
551   dest_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Output to _file:", accel_group);
552   if (args->to_file)
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);
558
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);
567   if (args->to_file)
568     gtk_widget_grab_focus(file_te);
569
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);
578
579   /* Command label and text entry */
580 #ifndef _WIN32
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);
588
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);
597 #endif
598
599   SIGNAL_CONNECT(dest_cb, "toggled", print_cmd_toggle_dest, NULL);
600   SIGNAL_CONNECT(file_bt, "clicked", print_browse_file_cb, file_te);
601
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);
606   }
607
608 /*****************************************************/
609
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);
614
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);
619
620   range_tb = range_new(&args->range
621 #if GTK_MAJOR_VERSION < 2
622   , accel_group
623 #endif
624   );
625   gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
626   gtk_widget_show(range_tb);
627
628 /*****************************************************/
629
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);
641
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);
649
650
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);
658
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);
664
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);
669
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);
674
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);
681
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);
687
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);
693
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);
701
702   /* seperator */
703   sep = gtk_hseparator_new();
704   gtk_container_add(GTK_CONTAINER(format_vb), sep);
705   gtk_widget_show(sep);
706
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);
714
715
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);
723
724 /*****************************************************/
725
726
727   /* Button row */
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);
730   } else {
731     bbox = dlg_button_row_new(action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
732   }
733   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
734   gtk_widget_show(bbox);
735
736   ok_bt = OBJECT_GET_DATA(bbox, action == output_action_print ? GTK_STOCK_PRINT : GTK_STOCK_OK);
737
738   OBJECT_SET_DATA(main_win, PRINT_BT_KEY, ok_bt);
739
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);
745 #ifndef _WIN32
746   OBJECT_SET_DATA(ok_bt, PRINT_CMD_TE_KEY, cmd_te);
747 #endif
748
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);
760
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);
764
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);
769     }
770   } else {
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);
775     }
776 #else
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);
780     }
781 #endif
782   }
783
784   gtk_widget_grab_default(ok_bt);
785
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. */
790 #ifndef _WIN32
791   dlg_set_activate(cmd_te, ok_bt);
792 #endif
793   if(action != output_action_print)
794     dlg_set_activate(file_te, ok_bt);
795
796   SIGNAL_CONNECT(main_win, "delete_event", window_delete_event_cb, NULL);
797
798   gtk_widget_show(main_win);
799   window_present(main_win);
800
801   return main_win;
802 }
803
804
805 /* user changed "print to" destination */
806 static void
807 print_cmd_toggle_dest(GtkWidget *widget, gpointer data _U_)
808 {
809 #ifndef _WIN32
810   GtkWidget     *cmd_lb, *cmd_te;
811 #endif
812   GtkWidget     *file_bt, *file_te;
813   int            to_file;
814
815 #ifndef _WIN32
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));
818 #endif
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));
821
822   to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
823 #ifndef _WIN32
824   gtk_widget_set_sensitive(cmd_lb, !to_file);
825   gtk_widget_set_sensitive(cmd_te, !to_file);
826 #endif
827   gtk_widget_set_sensitive(file_bt, to_file);
828   gtk_widget_set_sensitive(file_te, to_file);
829 }
830
831
832 /* user changed "packet details" */
833 static void
834 print_cmd_toggle_detail(GtkWidget *widget _U_, gpointer data)
835 {
836   GtkWidget     *print_bt, *summary_cb, *details_cb, *collapse_all_rb, *expand_all_rb, *as_displayed_rb, *hex_cb;
837   gboolean      print_detail;
838
839
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));
847
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);
853
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)));
859 }
860
861
862 static void
863 print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
864 {
865   GtkWidget         *button;
866   print_args_t      *args;
867   const gchar       *g_dest;
868   gchar             *f_name;
869   gchar             *dirname;
870   gboolean          export_as_pdml = FALSE, export_as_psml = FALSE;
871   gboolean          export_as_csv = FALSE;
872 #ifdef _WIN32
873   gboolean          win_printer = FALSE;
874   int               tmp_fd;
875   char              tmp_namebuf[128+1];    /* XXX - length was used elsewhere too, why? */
876   char              *tmp_oldfile;
877 #endif
878   cf_print_status_t status;
879
880   args = (print_args_t *)OBJECT_GET_DATA(ok_bt, PRINT_ARGS_KEY);
881
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. */
887     return;
888   }
889
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));
892
893   if (args->to_file) {
894     g_dest = gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
895                                                           PRINT_FILE_TE_KEY)));
896     if (!g_dest[0]) {
897       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
898         "Output to file, but no file specified.");
899       return;
900     }
901     g_free(args->file);
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);
907     g_free(f_name);
908   } else {
909 #ifdef _WIN32
910     win_printer = TRUE;
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. */
914     /* */
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 */
917
918     tmp_fd = create_tempfile(tmp_namebuf, sizeof(tmp_namebuf), "ethprint");
919     if(tmp_fd == -1) {
920         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
921             "Couldn't create a temporary file for printing.");
922         return;
923     }
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;
929 #else
930     g_free(args->cmd);
931     args->cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
932       PRINT_CMD_TE_KEY))));
933 #endif
934   }
935
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;
949
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));
952
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;
956   }
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;
960   }
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;
964   }
965
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;
970   }
971
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));
974
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));
977
978
979   window_destroy(GTK_WIDGET(parent_w));
980
981   /* Now print/export the packets */
982   if (export_as_pdml)
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);
988   else {
989     switch (args->format) {
990
991     case PR_FMT_TEXT:
992       if (args->to_file) {
993         args->stream = print_stream_text_new(TRUE, args->file);
994         if (args->stream == NULL) {
995           open_failure_alert_box(args->file, errno, TRUE);
996           return;
997         }
998       } else {
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);
1003         }
1004       }
1005       break;
1006
1007     case PR_FMT_PS:
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);
1012           return;
1013         }
1014       } else {
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);
1019         }
1020       }
1021       break;
1022
1023     default:
1024       g_assert_not_reached();
1025       return;
1026     }
1027     status = cf_print_packets(&cfile, args);
1028   }
1029   switch (status) {
1030
1031   case CF_PRINT_OK:
1032     break;
1033
1034   case CF_PRINT_OPEN_ERROR:
1035     if (args->to_file)
1036       open_failure_alert_box(args->file, errno, TRUE);
1037     else
1038       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't run print command %s.",
1039         args->cmd);
1040     break;
1041
1042   case CF_PRINT_WRITE_ERROR:
1043     if (args->to_file)
1044       write_failure_alert_box(args->file, errno);
1045     else
1046       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1047         "Error writing to print command: %s", strerror(errno));
1048     break;
1049   }
1050
1051 #ifdef _WIN32
1052   if (win_printer) {
1053     print_mswin(args->file);
1054
1055     /* trash temp file */
1056     eth_remove(args->file);
1057
1058     /* restore old settings */
1059     args->to_file = FALSE;
1060     args->file = tmp_oldfile;
1061   }
1062 #endif
1063 }
1064
1065 static void
1066 print_destroy_cb(GtkWidget *win, gpointer user_data)
1067 {
1068   GtkWidget     *fs;
1069
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);
1073
1074   if (fs != NULL) {
1075     /* Yes.  Destroy it. */
1076     window_destroy(fs);
1077   }
1078
1079   /* Note that we no longer have a "Print" dialog box. */
1080   *((gpointer *) user_data) = NULL;
1081 }