/* TN5250 - An implementation of the 5250 telnet protocol.
* Copyright (C) 1997 Michael Madore
*
* This file is part of TN5250.
*
* TN5250 is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1, or (at your option)
* any later version.
*
* TN5250 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
*/
#include "tn5250-private.h"
#ifndef WIN32
static const struct response_code {
const char * code;
int retval;
const char * text;
} response_codes[] = {
{ "I901", 1, "Virtual device has less function than source device." },
{ "I902", 1, "Session successfully started." },
{ "I906", 1, "Automatic sign-on requested, but not allowed. A sign-on screen will follow." },
{ "2702", 0, "Device description not found." },
{ "2703", 0, "Controller description not found." },
{ "2777", 0, "Damaged device description." },
{ "8901", 0, "Device not varied on." },
{ "8902", 0, "Device not available." },
{ "8903", 0, "Device not valid for session." },
{ "8906", 0, "Session initiation failed." },
{ "8907", 0, "Session failure." },
{ "8910", 0, "Controller not valid for session." },
{ "8916", 0, "No matching device found." },
{ "8917", 0, "Not authorized to object." },
{ "8918", 0, "Job cancelled." },
{ "8920", 0, "Object partially damaged." }, /* As opposed to fully damaged? */
{ "8921", 0, "Communications error." },
{ "8922", 0, "Negative response received." }, /* From what?!? */
{ "8923", 0, "Start-up record built incorrectly." },
{ "8925", 0, "Creation of device failed." },
{ "8928", 0, "Change of device failed." },
{ "8929", 0, "Vary on or vary off failed." },
{ "8930", 0, "Message queue does not exist." },
{ "8934", 0, "Start up for S/36 WSF received." },
{ "8935", 0, "Session rejected." },
{ "8936", 0, "Security failure on session attempt." },
{ "8937", 0, "Automatic sign-on rejected." },
{ "8940", 0, "Automatic configuration failed or not allowed." },
{ "I904", 0, "Source system at incompatible release." },
{ NULL, 0, NULL }
};
static int tn5250_print_session_waitevent(Tn5250PrintSession * This);
/****f* lib5250/tn5250_print_session_new
* NAME
* tn5250_print_session_new
* SYNOPSIS
* ret = tn5250_print_session_new ();
* INPUTS
* None
* DESCRIPTION
* DOCUMENT ME!!!
*****/
Tn5250PrintSession *tn5250_print_session_new()
{
Tn5250PrintSession *This;
This = tn5250_new(Tn5250PrintSession, 1);
if (This == NULL)
return NULL;
This->rec = tn5250_record_new();
if (This->rec == NULL) {
free (This);
return NULL;
}
This->stream = NULL;
This->printfile = NULL;
This->output_cmd = NULL;
This->conn_fd = -1;
This->map = NULL;
This->script_slot = NULL;
return This;
}
/****f* lib5250/tn5250_print_session_destroy
* NAME
* tn5250_print_session_destroy
* SYNOPSIS
* tn5250_print_session_destroy (This);
* INPUTS
* Tn5250PrintSession * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void tn5250_print_session_destroy(Tn5250PrintSession * This)
{
if (This->stream != NULL)
tn5250_stream_destroy(This->stream);
if (This->rec != NULL)
tn5250_record_destroy(This->rec);
if (This->output_cmd != NULL)
free(This->output_cmd);
if (This->map != NULL)
tn5250_char_map_destroy (This->map);
free (This);
}
/****f* lib5250/tn5250_print_session_set_fd
* NAME
* tn5250_print_session_set_fd
* SYNOPSIS
* tn5250_print_session_set_fd (This, fd);
* INPUTS
* Tn5250PrintSession * This -
* SOCKET_TYPE fd -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void tn5250_print_session_set_fd(Tn5250PrintSession * This, SOCKET_TYPE fd)
{
This->conn_fd = fd;
}
/****f* lib5250/tn5250_print_session_set_stream
* NAME
* tn5250_print_session_set_stream
* SYNOPSIS
* tn5250_print_session_set_stream (This, newstream);
* INPUTS
* Tn5250PrintSession * This -
* Tn5250Stream * newstream -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void tn5250_print_session_set_stream(Tn5250PrintSession * This, Tn5250Stream * newstream)
{
if (This->stream != NULL)
tn5250_stream_destroy (This->stream);
This->stream = newstream;
}
/****f* lib5250/tn5250_print_session_set_char_map
* NAME
* tn5250_print_session_set_char_map
* SYNOPSIS
* tn5250_print_session_set_char_map (This, map);
* INPUTS
* Tn5250PrintSession * This -
* const char * map -
* DESCRIPTION
* Sets the current translation map for this print session. This is
* used to translate response codes to something we can use.
*****/
void tn5250_print_session_set_char_map (Tn5250PrintSession *This, const char *map)
{
if (This->map != NULL)
tn5250_char_map_destroy (This->map);
This->map = tn5250_char_map_new (map);
}
/****f* lib5250/tn5250_print_session_set_output_command
* NAME
* tn5250_print_session_set_output_command
* SYNOPSIS
* tn5250_print_session_set_output_command (This, output_cmd);
* INPUTS
* Tn5250PrintSession * This -
* const char * output_cmd -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void tn5250_print_session_set_output_command(Tn5250PrintSession * This, const char *output_cmd)
{
if (This->output_cmd != NULL)
free(This->output_cmd);
This->output_cmd = (char *) malloc(strlen(output_cmd) + 1);
strcpy(This->output_cmd, output_cmd);
}
/****f* lib5250/tn5250_print_session_get_response_code
* NAME
* tn5250_print_session_get_response_code
* SYNOPSIS
* rc = tn5250_print_session_get_response_code (This, code);
* INPUTS
* Tn5250PrintSession * This -
* char * code -
* DESCRIPTION
* Retrieves the response code from the startup response record. The
* function returns 1 for a successful startup, and 0 otherwise. On return,
* code contains the 5 character response code.
*****/
int tn5250_print_session_get_response_code(Tn5250PrintSession * This, char *code)
{
/* Offset of first byte of data after record variable-length header. */
int o = 6 + tn5250_record_data(This->rec)[6];
int i;
for (i = 0; i < 4; i++) {
if (This->map == NULL)
code[i] = tn5250_record_data(This->rec)[o+i+5];
else {
code[i] = tn5250_char_map_to_local (This->map,
tn5250_record_data(This->rec)[o+i+5]
);
}
}
code[4] = '\0';
for (i = 0; i < sizeof (response_codes)/sizeof (struct response_code); i++) {
if (!strcmp (response_codes[i].code, code)) {
syslog(LOG_INFO, "%s : %s", response_codes[i].code, response_codes[i].text);
return response_codes[i].retval;
}
}
return 0;
}
/****f* lib5250/tn5250_print_session_main_loop
* NAME
* tn5250_print_session_main_loop
* SYNOPSIS
* tn5250_print_session_main_loop (This);
* INPUTS
* Tn5250PrintSession * This -
* DESCRIPTION
* This function continually loops, waiting for print jobs from the AS/400.
* When it gets one, it sends it to the output command which was specified
* on the command line. If the host closes the socket, we exit.
*****/
void tn5250_print_session_main_loop(Tn5250PrintSession * This)
{
int pcount;
int newjob;
char responsecode[5];
StreamHeader header;
while (1) {
if (tn5250_print_session_waitevent(This)) {
if( tn5250_stream_handle_receive(This->stream) ) {
pcount = tn5250_stream_record_count(This->stream);
if (pcount > 0) {
if (This->rec != NULL)
tn5250_record_destroy(This->rec);
This->rec = tn5250_stream_get_record(This->stream);
if (!tn5250_print_session_get_response_code(This, responsecode))
exit (1);
break;
}
}
else {
syslog(LOG_INFO, "Socket closed by host.");
exit(-1);
}
}
}
newjob = 1;
while (1) {
if (tn5250_print_session_waitevent(This)) {
if( tn5250_stream_handle_receive(This->stream) ) {
pcount = tn5250_stream_record_count(This->stream);
if (pcount > 0) {
if (newjob) {
char *output_cmd;
if ((output_cmd = This->output_cmd) == NULL)
output_cmd = "scs2ascii |lpr";
This->printfile = popen(output_cmd, "w");
TN5250_ASSERT(This->printfile != NULL);
newjob = 0;
}
if (This->rec != NULL)
tn5250_record_destroy(This->rec);
This->rec = tn5250_stream_get_record(This->stream);
if(tn5250_record_opcode(This->rec)
== TN5250_RECORD_OPCODE_CLEAR)
{
syslog(LOG_INFO, "Clearing print buffers");
continue;
}
header.h5250.flowtype = TN5250_RECORD_FLOW_CLIENTO;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_PRINT_COMPLETE;
tn5250_stream_send_packet(This->stream, 0,
header,
NULL);
if (tn5250_record_length(This->rec) == 0x11) {
syslog(LOG_INFO, "Job Complete\n");
pclose(This->printfile);
newjob = 1;
} else {
while (!tn5250_record_is_chain_end(This->rec))
fprintf(This->printfile, "%c",
tn5250_record_get_byte(This->rec));
}
}
}
else {
syslog(LOG_INFO, "Socket closed by host");
exit(-1);
}
}
}
}
/****f* lib5250/tn5250_print_session_waitevent
* NAME
* tn5250_print_session_waitevent
* SYNOPSIS
* ret = tn5250_print_session_waitevent (This);
* INPUTS
* Tn5250PrintSession * This -
* DESCRIPTION
* Calls select() to wait for data to arrive on the socket fdr.
* This is the socket being used by the print session to communicate
* with the AS/400. There is no timeout, so the function will wait forever
* if no data arrives.
*****/
static int tn5250_print_session_waitevent(Tn5250PrintSession * This)
{
fd_set fdr;
int result = 0;
FD_ZERO(&fdr);
FD_SET(This->conn_fd, &fdr);
select(This->conn_fd + 1, &fdr, NULL, NULL, NULL);
if (FD_ISSET(This->conn_fd, &fdr))
result = 1;
return result;
}
#endif /* ifndef WIN32 */
/* vi:set sts=3 sw=3: */
syntax highlighted by Code2HTML, v. 0.9.1