/* 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