/*
* Copyright 1994, 1995, 1999, 2000, 2002, 2004 by Paul Mattes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* x3270, c3270, s3270 and tcl3270 are distributed in the hope that they will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file LICENSE
* for more details.
*/
/*
* print.c
* Screen printing functions.
*/
#include "globals.h"
#include "appres.h"
#include "3270ds.h"
#include "ctlr.h"
#include "ctlrc.h"
#include "tablesc.h"
#include <errno.h>
#if defined(X3270_DISPLAY) /*[*/
#include <X11/StringDefs.h>
#include <X11/Xaw/Dialog.h>
#endif /*]*/
#include "objects.h"
#include "resources.h"
#include "actionsc.h"
#include "popupsc.h"
#include "printc.h"
#include "utilc.h"
#if defined(X3270_DBCS) /*[*/
#include "widec.h"
#endif /*]*/
/* Statics */
#if defined(X3270_DISPLAY) /*[*/
static Widget print_text_shell = (Widget)NULL;
static Widget save_text_shell = (Widget)NULL;
static Widget print_window_shell = (Widget)NULL;
static char *print_window_command = CN;
#endif /*]*/
/* Print Text popup */
/*
* Map default 3279 colors. This code is duplicated three times. ;-(
*/
static int
color_from_fa(unsigned char fa)
{
static int field_colors[4] = {
COLOR_GREEN, /* default */
COLOR_RED, /* intensified */
COLOR_BLUE, /* protected */
COLOR_WHITE /* protected, intensified */
# define DEFCOLOR_MAP(f) \
((((f) & FA_PROTECT) >> 4) | (((f) & FA_INT_HIGH_SEL) >> 3))
};
if (appres.m3279)
return field_colors[DEFCOLOR_MAP(fa)];
else
return COLOR_GREEN;
}
/*
* Map 3279 colors onto HTML colors.
*/
static char *
html_color(int color)
{
static char *html_color_map[] = {
"black",
"deepSkyBlue",
"red",
"pink",
"green",
"turquoise",
"yellow",
"white",
"black",
"blue3",
"orange",
"purple",
"paleGreen",
"paleTurquoise2",
"grey",
"white"
};
if (color >= COLOR_NEUTRAL_BLACK && color <= COLOR_WHITE)
return html_color_map[color];
else
return "black";
}
/*
* Print the ASCIIfied contents of the screen onto a stream.
* Returns True if anything printed, False otherwise.
*
* If 'use_html' is True, then HTML is generated, which preserves colors, but
* little else (for now).
*/
Boolean
fprint_screen(FILE *f, Boolean even_if_empty, Boolean use_html)
{
register int i;
char c;
int ns = 0;
int nr = 0;
Boolean any = False;
int fa_addr = find_field_attribute(0);
unsigned char fa = ea_buf[fa_addr].fa;
int fa_color, current_color;
Bool fa_high, current_high;
if (use_html) {
even_if_empty = True;
}
if (ea_buf[fa_addr].fg)
fa_color = ea_buf[fa_addr].fg & 0x0f;
else
fa_color = color_from_fa(fa);
current_color = fa_color;
if (ea_buf[fa_addr].gr & GR_INTENSIFY)
fa_high = True;
else
fa_high = FA_IS_HIGH(fa);
current_high = fa_high;
for (i = 0; i < ROWS*COLS; i++) {
#if defined(X3270_DBCS) /*[*/
char mb[16];
Boolean is_dbcs = False;
#endif /*]*/
if (i && !(i % COLS)) {
nr++;
ns = 0;
}
if (ea_buf[i].fa) {
c = ' ';
fa = ea_buf[i].fa;
if (ea_buf[i].fg)
fa_color = ea_buf[i].fg & 0x0f;
else
fa_color = color_from_fa(fa);
if (ea_buf[i].gr & GR_INTENSIFY)
fa_high = True;
else
fa_high = FA_IS_HIGH(fa);
}
if (FA_IS_ZERO(fa))
c = ' ';
#if defined(X3270_DBCS) /*[*/
else {
/* XXX: DBCS/html interactions are not done */
switch (ctlr_dbcs_state(i)) {
case DBCS_NONE:
case DBCS_SB:
c = ebc2asc[ea_buf[i].cc];
break;
case DBCS_LEFT:
dbcs_to_mb(ea_buf[i].cc, ea_buf[i + 1].cc, mb);
is_dbcs = True;
c = 'x';
break;
default:
c = ' ';
break;
}
}
#else /*][*/
else
c = ebc2asc[ea_buf[i].cc];
#endif /*]*/
if (c == ' ')
ns++;
else {
while (nr) {
(void) fputc('\n', f);
nr--;
}
while (ns) {
(void) fputc(' ', f);
ns--;
}
if (use_html) {
int color;
Bool high;
if (ea_buf[i].fg)
color = ea_buf[i].fg & 0x0f;
else
color = fa_color;
if (color != current_color) {
if (any)
fprintf(f, "</font><font color=%s>",
html_color(color));
current_color = color;
}
if (ea_buf[i].gr & GR_INTENSIFY)
high = True;
else
high = fa_high;
if (high != current_high) {
if (any) {
if (high)
fprintf(f, "<b>");
else
fprintf(f, "</b>");
}
current_high = high;
}
if (!any) {
fprintf(f, "<html>\n "
" <body>\n"
" <table border=0>"
"<tr bgcolor=black><td>"
"<pre><font color=%s>%s",
html_color(current_color),
current_high? "<b>": "");
}
}
any = True;
#if defined(X3270_DBCS) /*[*/
if (is_dbcs) {
(void) fputs(mb, f);
i++;
}
else
#endif /*]*/
{
if (use_html && c == '<')
fprintf(f, "<");
else
(void) fputc(c, f);
}
}
}
nr++;
if (!any && !even_if_empty)
return False;
while (nr) {
(void) fputc('\n', f);
nr--;
}
if (use_html && any) {
fprintf(f, "%s</font></pre></td></tr>\n"
" </table>\n"
" </body>\n"
"</html>\n",
current_high? "</b>": "");
}
return True;
}
/* Termination code for print text process. */
static void
print_text_done(FILE *f, Boolean do_popdown
#if defined(X3270_DISPLAY) /*[*/
unused
#endif /*]*/
)
{
int status;
status = pclose(f);
if (status) {
popup_an_error("Print program exited with status %d.",
(status & 0xff00) > 8);
} else {
#if defined(X3270_DISPLAY) /*[*/
if (do_popdown)
XtPopdown(print_text_shell);
if (appres.do_confirms)
popup_an_info("Screen image printed.");
#endif /*]*/
}
}
#if defined(X3270_DISPLAY) /*[*/
/* Callback for "OK" button on the print text popup. */
static void
print_text_callback(Widget w unused, XtPointer client_data,
XtPointer call_data unused)
{
char *filter;
FILE *f;
filter = XawDialogGetValueString((Widget)client_data);
if (!filter) {
XtPopdown(print_text_shell);
return;
}
if (!(f = popen(filter, "w"))) {
popup_an_errno(errno, "popen(%s)", filter);
return;
}
(void) fprint_screen(f, True, False);
print_text_done(f, True);
}
/* Callback for "Plain Text" button on save text popup. */
static void
save_text_plain_callback(Widget w unused, XtPointer client_data,
XtPointer call_data unused)
{
char *filename;
FILE *f;
filename = XawDialogGetValueString((Widget)client_data);
if (!filename) {
XtPopdown(save_text_shell);
return;
}
if (!(f = fopen(filename, "a"))) {
popup_an_errno(errno, "%s", filename);
return;
}
(void) fprint_screen(f, True, False);
fclose(f);
XtPopdown(save_text_shell);
if (appres.do_confirms)
popup_an_info("Screen image saved.");
}
/* Callback for "HTML" button on save text popup. */
static void
save_text_html_callback(Widget w unused, XtPointer client_data,
XtPointer call_data unused)
{
char *filename;
FILE *f;
filename = XawDialogGetValueString((Widget)client_data);
if (!filename) {
XtPopdown(save_text_shell);
return;
}
if (!(f = fopen(filename, "a"))) {
popup_an_errno(errno, "%s", filename);
return;
}
(void) fprint_screen(f, True, True);
fclose(f);
XtPopdown(save_text_shell);
if (appres.do_confirms)
popup_an_info("Screen image saved.");
}
/* Pop up the Print Text dialog, given a filter. */
static void
popup_print_text(char *filter)
{
if (print_text_shell == NULL) {
print_text_shell = create_form_popup("PrintText",
print_text_callback, (XtCallbackProc)NULL,
FORM_AS_IS);
XtVaSetValues(XtNameToWidget(print_text_shell, ObjDialog),
XtNvalue, filter,
NULL);
}
popup_popup(print_text_shell, XtGrabExclusive);
}
/* Pop up the Save Text dialog. */
static void
popup_save_text(char *filename)
{
if (save_text_shell == NULL) {
save_text_shell = create_form_popup("SaveText",
save_text_plain_callback,
save_text_html_callback,
FORM_AS_IS);
}
if (filename != CN)
XtVaSetValues(XtNameToWidget(save_text_shell, ObjDialog),
XtNvalue, filename,
NULL);
popup_popup(save_text_shell, XtGrabExclusive);
}
#endif /*]*/
/* Print or save the contents of the screen as text. */
void
PrintText_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
int i;
char *filter = CN;
Boolean secure = appres.secure;
Boolean use_html = False;
Boolean use_file = False;
Boolean use_string = False;
action_debug(PrintText_action, event, params, num_params);
/*
* Pick off optional arguments:
* file directs the output to a file instead of a command;
* must be the last keyword
* html generates HTML output instead of ASCII text (and implies
* 'file')
* secure disables the pop-up dialog, if this action is invoked from
* a keymap
* command directs the output to a command (this is the default, but
* allows the command to be one of the other keywords);
* must be the last keyword
* string returns the data as a string, allowed only from scripts
*/
for (i = 0; i < *num_params; i++) {
if (!strcasecmp(params[i], "file")) {
use_file = True;
i++;
break;
} else if (!strcasecmp(params[i], "html")) {
use_html = True;
use_file = True;
} else if (!strcasecmp(params[i], "secure")) {
secure = True;
} else if (!strcasecmp(params[i], "command")) {
if (use_html || use_file) {
popup_an_error("%s: contradictory options",
action_name(PrintText_action));
return;
}
i++;
break;
} else if (!strcasecmp(params[i], "string")) {
if (ia_cause != IA_SCRIPT) {
popup_an_error("%s(string) can only be used "
"from a script",
action_name(PrintText_action));
return;
}
use_string = True;
use_file = True;
} else {
break;
}
}
switch (*num_params - i) {
case 0:
/* Use the default. */
if (!use_file)
filter = get_resource(ResPrintTextCommand);
break;
case 1:
if (use_string) {
popup_an_error("%s: extra arguments or invalid option(s)",
action_name(PrintText_action));
return;
}
filter = params[i];
break;
default:
popup_an_error("%s: extra arguments or invalid option(s)",
action_name(PrintText_action));
return;
}
if (filter != CN && filter[0] == '@') {
/*
* Starting the PrintTextCommand resource value with '@'
* suppresses the pop-up dialog, as does setting the 'secure'
* resource.
*/
secure = True;
filter++;
}
if (!use_file && (filter == CN || !*filter))
filter = "lpr";
#if defined(X3270_DISPLAY) /*[*/
if (secure ||
ia_cause == IA_COMMAND ||
ia_cause == IA_MACRO ||
ia_cause == IA_SCRIPT)
#endif /*]*/
{
FILE *f;
int fd = -1;
/* Invoked non-interactively. */
if (use_file) {
if (use_string) {
char temp_name[15];
strcpy(temp_name, "/tmp/x3hXXXXXX");
fd = mkstemp(temp_name);
if (fd < 0) {
popup_an_errno(errno, "mkstemp");
return;
}
(void) unlink(temp_name);
f = fdopen(fd, "w+");
} else {
if (filter == CN || !*filter) {
popup_an_error("%s: missing filename",
action_name(PrintText_action));
return;
}
f = fopen(filter, "a");
}
} else
f = popen(filter, "w");
if (f == NULL) {
popup_an_errno(errno, "%s: %s",
action_name(PrintText_action),
filter);
if (fd >= 0) {
(void) close(fd);
}
return;
}
(void) fprint_screen(f, True, use_html);
if (use_string) {
char buf[8192];
rewind(f);
while (fgets(buf, sizeof(buf), f) != NULL)
action_output(buf);
}
if (use_file)
fclose(f);
else
print_text_done(f, False);
return;
}
#if defined(X3270_DISPLAY) /*[*/
/* Invoked interactively -- pop up the confirmation dialog. */
if (use_file) {
popup_save_text(filter);
} else {
popup_print_text(filter);
}
#endif /*]*/
}
#if defined(X3270_DISPLAY) /*[*/
#if defined(X3270_MENUS) /*[*/
/* Callback for Print Text menu option. */
void
print_text_option(Widget w, XtPointer client_data unused,
XtPointer call_data unused)
{
char *filter = get_resource(ResPrintTextCommand);
Boolean secure = appres.secure;
Boolean use_html = False;
/* Decode the filter. */
if (filter != CN && *filter == '@') {
secure = True;
filter++;
}
if (filter == CN || !*filter)
filter = "lpr";
if (secure) {
FILE *f;
/* Print the screen without confirming. */
if (!(f = popen(filter, "w"))) {
popup_an_errno(errno, "popen(%s)", filter);
return;
}
(void) fprint_screen(f, True, use_html);
print_text_done(f, False);
} else {
/* Pop up a dialog to confirm or modify their choice. */
popup_print_text(filter);
}
}
/* Callback for Save Text menu option. */
void
save_text_option(Widget w, XtPointer client_data unused,
XtPointer call_data unused)
{
/* Pop up a dialog to confirm or modify their choice. */
popup_save_text(CN);
}
#endif /*]*/
/* Print Window popup */
/*
* Printing the window bitmap is a rather convoluted process:
* The PrintWindow action calls PrintWindow_action(), or a menu option calls
* print_window_option().
* print_window_option() pops up the dialog.
* The OK button on the dialog triggers print_window_callback.
* print_window_callback pops down the dialog, then schedules a timeout
* 1 second away.
* When the timeout expires, it triggers snap_it(), which finally calls
* xwd.
* The timeout indirection is necessary because xwd prints the actual contents
* of the window, including any pop-up dialog in front of it. We pop down the
* dialog, but then it is up to the server and Xt to send us the appropriate
* expose events to repaint our window. Hopefully, one second is enough to do
* that.
*/
/* Termination procedure for window print. */
static void
print_window_done(int status)
{
if (status)
popup_an_error("Print program exited with status %d.",
(status & 0xff00) >> 8);
else if (appres.do_confirms)
popup_an_info("Bitmap printed.");
}
/* Timeout callback for window print. */
static void
snap_it(XtPointer closure unused, XtIntervalId *id unused)
{
if (!print_window_command)
return;
XSync(display, 0);
print_window_done(system(print_window_command));
print_window_command = CN;
}
/* Callback for "OK" button on print window popup. */
static void
print_window_callback(Widget w unused, XtPointer client_data,
XtPointer call_data unused)
{
print_window_command = XawDialogGetValueString((Widget)client_data);
XtPopdown(print_window_shell);
if (print_window_command)
(void) XtAppAddTimeOut(appcontext, 1000, snap_it, 0);
}
/* Print the contents of the screen as a bitmap. */
void
PrintWindow_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
char *filter = get_resource(ResPrintWindowCommand);
char *fb = XtMalloc(strlen(filter) + 16);
char *xfb = fb;
Boolean secure = appres.secure;
action_debug(PrintWindow_action, event, params, num_params);
if (*num_params > 0)
filter = params[0];
if (*num_params > 1)
popup_an_error("%s: extra arguments ignored",
action_name(PrintWindow_action));
if (filter == CN) {
popup_an_error("%s: no %s defined",
action_name(PrintWindow_action), ResPrintWindowCommand);
return;
}
(void) sprintf(fb, filter, XtWindow(toplevel));
if (fb[0] == '@') {
secure = True;
xfb = fb + 1;
}
if (secure) {
print_window_done(system(xfb));
Free(fb);
return;
}
if (print_window_shell == NULL)
print_window_shell = create_form_popup("printWindow",
print_window_callback, (XtCallbackProc)NULL, FORM_AS_IS);
XtVaSetValues(XtNameToWidget(print_window_shell, ObjDialog),
XtNvalue, fb,
NULL);
popup_popup(print_window_shell, XtGrabExclusive);
}
#if defined(X3270_MENUS) /*[*/
/* Callback for menu Print Window option. */
void
print_window_option(Widget w, XtPointer client_data unused,
XtPointer call_data unused)
{
Cardinal zero = 0;
PrintWindow_action(w, (XEvent *)NULL, (String *)NULL, &zero);
}
#endif /*]*/
#endif /*]*/
syntax highlighted by Code2HTML, v. 0.9.1