/* 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"
static void tn5250_session_send_error (Tn5250Session * This,
unsigned long errorcode);
static void tn5250_session_handle_receive (Tn5250Session * This);
static void tn5250_session_invite (Tn5250Session * This);
static void tn5250_session_cancel_invite (Tn5250Session * This);
static void tn5250_session_send_fields (Tn5250Session * This, int aidcode);
static void tn5250_session_send_field (Tn5250Session * This,
Tn5250Buffer * buf,
Tn5250Field * field);
static void tn5250_session_process_stream (Tn5250Session * This);
static void tn5250_session_write_error_code (Tn5250Session * This);
static void tn5250_session_write_to_display (Tn5250Session * This);
static void tn5250_session_clear_unit (Tn5250Session * This);
static void tn5250_session_clear_unit_alternate (Tn5250Session * This);
static void tn5250_session_clear_format_table (Tn5250Session * This);
static void tn5250_session_read_immediate (Tn5250Session * This);
/*static void tn5250_session_home (Tn5250Session * This);*/
/*static void tn5250_session_print (Tn5250Session * This);*/
static void tn5250_session_output_only (Tn5250Session * This);
static void tn5250_session_save_screen (Tn5250Session * This);
static void tn5250_session_roll (Tn5250Session * This);
static void tn5250_session_start_of_field (Tn5250Session * This);
static void tn5250_session_start_of_header (Tn5250Session * This);
static void tn5250_session_set_buffer_address (Tn5250Session * This);
static void tn5250_session_write_extended_attribute (Tn5250Session * This);
static void tn5250_session_write_structured_field (Tn5250Session * This);
static void tn5250_session_write_display_structured_field (Tn5250Session *
This);
static void tn5250_session_transparent_data (Tn5250Session * This);
static void tn5250_session_move_cursor (Tn5250Session * This);
static void tn5250_session_insert_cursor (Tn5250Session * This);
static void tn5250_session_erase_to_address (Tn5250Session * This);
static void tn5250_session_repeat_to_address (Tn5250Session * This);
static void tn5250_session_read_screen_immediate (Tn5250Session * This);
static void tn5250_session_read_cmd (Tn5250Session * This, int readop);
/*static int tn5250_session_valid_wtd_data_char (unsigned char c);*/
static int tn5250_session_handle_aidkey (Tn5250Session * This, int key);
static void tn5250_session_handle_cc1 (Tn5250Session * This,
unsigned char cc1);
static void tn5250_session_handle_cc2 (Tn5250Session * This,
unsigned char cc2);
static void tn5250_session_query_reply (Tn5250Session * This);
static void tn5250_session_define_selection_field (Tn5250Session * This,
int length);
static void tn5250_session_remove_gui_selection_field (Tn5250Session * This,
int length);
static void tn5250_session_define_selection_item (Tn5250Session * This,
Tn5250Menubar * menubar,
int length, int count,
short createnew);
static void tn5250_session_create_window_structured_field (Tn5250Session *
This, int length);
static void tn5250_session_define_scrollbar (Tn5250Session * This,
int length);
static void
tn5250_session_remove_gui_window_structured_field (Tn5250Session * This,
int length);
static void
tn5250_session_remove_all_gui_constructs_structured_field (Tn5250Session *
This, int length);
static void tn5250_session_write_data_structured_field (Tn5250Session *
This, int length);
/****f* lib5250/tn5250_session_new
* NAME
* tn5250_session_new
* SYNOPSIS
* ret = tn5250_session_new ();
* INPUTS
* None
* DESCRIPTION
* DOCUMENT ME!!!
*****/
Tn5250Session *
tn5250_session_new ()
{
Tn5250Session *This;
This = tn5250_new (Tn5250Session, 1);
if (This == NULL)
{
return NULL;
}
This->record = tn5250_record_new ();
if (This->record == NULL)
{
free (This);
return NULL;
}
This->config = NULL;
This->stream = NULL;
This->invited = 1;
This->read_opcode = 0;
This->handle_aidkey = tn5250_session_handle_aidkey;
This->display = NULL;
return This;
}
/****f* lib5250/tn5250_session_destroy
* NAME
* tn5250_session_destroy
* SYNOPSIS
* tn5250_session_destroy (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void
tn5250_session_destroy (Tn5250Session * This)
{
if (This->stream != NULL)
{
tn5250_stream_destroy (This->stream);
This->stream = NULL;
}
if (This->record != NULL)
{
tn5250_record_destroy (This->record);
This->record = NULL;
}
if (This->config != NULL)
{
tn5250_config_unref (This->config);
This->config = NULL;
}
free (This);
return;
}
/****f* lib5250/tn5250_session_config
* NAME
* tn5250_session_config
* SYNOPSIS
* tn5250_session_config (This);
* INPUTS
* Tn5250Session * This - The session to configure.
* Tn5250Config * config - The configuration object to use.
* DESCRIPTION
* DOCUMENT ME!!!
*****/
int
tn5250_session_config (Tn5250Session * This, Tn5250Config * config)
{
tn5250_config_ref (config);
if (This->config != NULL)
{
tn5250_config_unref (This->config);
}
This->config = config;
/* FIXME: Validate */
return 0;
}
/****f* lib5250/tn5250_session_set_stream
* NAME
* tn5250_session_set_stream
* SYNOPSIS
* tn5250_session_set_stream (This, newstream);
* INPUTS
* Tn5250Session * This -
* Tn5250Stream * newstream -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void
tn5250_session_set_stream (Tn5250Session * This, Tn5250Stream * newstream)
{
if ((This->stream = newstream) != NULL)
{
tn5250_display_update (This->display);
}
return;
}
/****f* lib5250/tn5250_session_main_loop
* NAME
* tn5250_session_main_loop
* SYNOPSIS
* tn5250_session_main_loop (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void
tn5250_session_main_loop (Tn5250Session * This)
{
int r;
while (1)
{
r = tn5250_display_waitevent (This->display);
if ((r & TN5250_TERMINAL_EVENT_QUIT) != 0)
{
return;
}
if ((r & TN5250_TERMINAL_EVENT_DATA) != 0)
{
if (!tn5250_stream_handle_receive (This->stream))
{
return;
}
tn5250_session_handle_receive (This);
}
}
return;
}
void
tn5250_session_send_error (Tn5250Session * This, unsigned long errorcode)
{
StreamHeader header;
errorcode = htonl (errorcode);
TN5250_LOG (("Sending negative response = %x", errorcode));
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_ERR;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_stream_send_packet (This->stream, 4, header,
(unsigned char *) &errorcode);
tn5250_record_skip_to_end (This->record);
return;
}
/****i* lib5250/tn5250_session_handle_receive
* NAME
* tn5250_session_handle_receive
* SYNOPSIS
* tn5250_session_handle_receive (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* Tell the socket to receive as much data as possible, then, if there are
* full packets to handle, handle them.
*****/
static void
tn5250_session_handle_receive (Tn5250Session * This)
{
int atn;
int cur_opcode;
TN5250_LOG (("HandleReceive: entered.\n"));
while (tn5250_stream_record_count (This->stream) > 0)
{
if (This->record != NULL)
{
tn5250_record_destroy (This->record);
}
This->record = tn5250_stream_get_record (This->stream);
cur_opcode = tn5250_record_opcode (This->record);
atn = tn5250_record_attention (This->record);
TN5250_LOG (("HandleReceive: cur_opcode = 0x%02X %d\n", cur_opcode,
atn));
switch (cur_opcode)
{
case TN5250_RECORD_OPCODE_PUT_GET:
case TN5250_RECORD_OPCODE_INVITE:
tn5250_session_invite (This);
break;
case TN5250_RECORD_OPCODE_OUTPUT_ONLY:
tn5250_session_output_only (This);
break;
case TN5250_RECORD_OPCODE_CANCEL_INVITE:
tn5250_session_cancel_invite (This);
break;
case TN5250_RECORD_OPCODE_MESSAGE_ON:
tn5250_display_indicator_set (This->display,
TN5250_DISPLAY_IND_MESSAGE_WAITING);
tn5250_display_beep (This->display);
break;
case TN5250_RECORD_OPCODE_MESSAGE_OFF:
tn5250_display_indicator_clear (This->display,
TN5250_DISPLAY_IND_MESSAGE_WAITING);
break;
case TN5250_RECORD_OPCODE_NO_OP:
case TN5250_RECORD_OPCODE_SAVE_SCR:
case TN5250_RECORD_OPCODE_RESTORE_SCR:
case TN5250_RECORD_OPCODE_READ_IMMED:
case TN5250_RECORD_OPCODE_READ_SCR:
break;
default:
TN5250_LOG (("Error: unknown opcode %2.2X\n", cur_opcode));
TN5250_ASSERT (0);
}
if (!tn5250_record_is_chain_end (This->record))
tn5250_session_process_stream (This);
}
tn5250_display_update (This->display);
return;
}
/****i* lib5250/tn5250_session_invite
* NAME
* tn5250_session_invite
* SYNOPSIS
* tn5250_session_invite (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_invite (Tn5250Session * This)
{
TN5250_LOG (("Invite: entered.\n"));
This->invited = 1;
tn5250_display_indicator_clear (This->display, TN5250_DISPLAY_IND_X_CLOCK);
return;
}
/****i* lib5250/tn5250_session_cancel_invite
* NAME
* tn5250_session_cancel_invite
* SYNOPSIS
* tn5250_session_cancel_invite (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_cancel_invite (Tn5250Session * This)
{
StreamHeader header;
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_CANCEL_INVITE;
TN5250_LOG (("CancelInvite: entered.\n"));
tn5250_display_indicator_set (This->display, TN5250_DISPLAY_IND_X_CLOCK);
tn5250_stream_send_packet (This->stream, 0, header, NULL);
This->invited = 0;
return;
}
/****i* lib5250/tn5250_session_send_fields
* NAME
* tn5250_session_send_fields
* SYNOPSIS
* tn5250_session_send_fields (This, aidcode);
* INPUTS
* Tn5250Session * This -
* int aidcode -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_send_fields (Tn5250Session * This, int aidcode)
{
Tn5250Buffer field_buf;
Tn5250Field *field;
Tn5250DBuffer *dbuffer;
int X, Y;
StreamHeader header;
X = tn5250_display_cursor_x (This->display);
Y = tn5250_display_cursor_y (This->display);
dbuffer = tn5250_display_dbuffer (This->display);
TN5250_ASSERT (dbuffer != NULL);
TN5250_LOG (("SendFields: Number of fields: %d\n",
tn5250_dbuffer_field_count (dbuffer)));
tn5250_buffer_init (&field_buf);
tn5250_buffer_append_byte (&field_buf, Y + 1);
tn5250_buffer_append_byte (&field_buf, X + 1);
/* We can have an aidcode of 0 if we are doing a Read Immediate */
tn5250_buffer_append_byte (&field_buf, aidcode);
TN5250_LOG (("SendFields: row = %d; col = %d; aid = 0x%02x\n", Y, X,
aidcode));
/* FIXME: Implement field resequencing. */
switch (This->read_opcode)
{
case CMD_READ_INPUT_FIELDS:
TN5250_ASSERT (aidcode != 0);
if (tn5250_dbuffer_mdt (dbuffer)
&& tn5250_dbuffer_send_data_for_aid_key (dbuffer, aidcode))
{
field = dbuffer->field_list;
if (field != NULL)
{
do
{
tn5250_session_send_field (This, &field_buf, field);
field = field->next;
}
while (field != dbuffer->field_list);
}
}
break;
case CMD_READ_IMMEDIATE:
if (tn5250_dbuffer_mdt (dbuffer))
{
field = dbuffer->field_list;
if (field != NULL)
{
do
{
tn5250_session_send_field (This, &field_buf, field);
field = field->next;
}
while (field != dbuffer->field_list);
}
}
break;
case CMD_READ_MDT_FIELDS:
case CMD_READ_MDT_FIELDS_ALT:
TN5250_ASSERT (aidcode != 0);
case CMD_READ_IMMEDIATE_ALT:
if (tn5250_dbuffer_send_data_for_aid_key (dbuffer, aidcode))
{
field = dbuffer->field_list;
if (field != NULL)
{
do
{
if (tn5250_field_mdt (field))
{
tn5250_session_send_field (This, &field_buf, field);
}
field = field->next;
}
while (field != dbuffer->field_list);
}
}
break;
default: /* Huh? */
TN5250_LOG (("BUG!!! Trying to transmit fields when This->read_opcode = 0x%02X.\n", This->read_opcode));
TN5250_ASSERT (0);
}
This->read_opcode = 0; /* No longer in a read command. */
tn5250_display_indicator_set (This->display, TN5250_DISPLAY_IND_X_SYSTEM);
This->display->keystate = TN5250_KEYSTATE_LOCKED;
tn5250_display_indicator_clear (This->display, TN5250_DISPLAY_IND_INSERT);
tn5250_display_update (This->display);
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_PUT_GET;
tn5250_stream_send_packet (This->stream,
tn5250_buffer_length (&field_buf),
header, tn5250_buffer_data (&field_buf));
tn5250_buffer_free (&field_buf);
return;
}
/****i* lib5250/tn5250_session_send_field
* NAME
* tn5250_session_send_field
* SYNOPSIS
* tn5250_session_send_field (This, buf, field);
* INPUTS
* Tn5250Session * This -
* Tn5250Buffer * buf -
* Tn5250Field * field -
* DESCRIPTION
* Append a single field to the transmit buffer in the manner required
* by the current read opcode.
*****/
static void
tn5250_session_send_field (Tn5250Session * This, Tn5250Buffer * buf,
Tn5250Field * field)
{
int size, n;
unsigned char *data;
unsigned char c;
Tn5250Field *iter;
size = tn5250_field_length (field);
data = tn5250_display_field_data (This->display, field);
TN5250_LOG (("Sending:\n"));
tn5250_field_dump (field);
TN5250_ASSERT (!tn5250_field_is_continued_middle (field) &&
!tn5250_field_is_continued_last (field));
/* find the following fields with the continuous flag set
* until we got them all.
*
* Assumes for now that all the continued field are one after the
* other and not distributed among other fields.
*
* Which appears to be a perfectly valid assumption since the "Functions
* Reference" manual says they have to be.
*/
if (field->continuous)
{
/* We also must only send back data for the first subfield of a
* continuous field. All subfields are treated as one and are sent
* as part of the first subfield.
*/
if (tn5250_field_is_continued_first (field))
{
/* The trick is to construct a temporary data which hold the entire
* reconstructed field
*/
int i = 0;
/* 1st loop: Guess the full size */
for (iter = field->next; iter->continuous; iter = iter->next)
{
size += tn5250_field_length (iter);
if (tn5250_field_is_continued_last (iter))
{
break;
}
}
data = malloc (size);
/* 2nd loop: Copy the data in the temporary buffer */
for (iter = field; iter->continuous; iter = iter->next)
{
memcpy (data + i,
tn5250_display_field_data (This->display, iter),
tn5250_field_length (iter));
i += tn5250_field_length (iter);
if (tn5250_field_is_continued_last (iter))
{
break;
}
}
}
else
{
return;
}
}
switch (This->read_opcode)
{
case CMD_READ_INPUT_FIELDS:
case CMD_READ_IMMEDIATE:
if (tn5250_field_is_signed_num (field))
{
for (n = 0; n < size - 1; n++)
{
tn5250_buffer_append_byte (buf, data[n] == 0 ? 0x40 : data[n]);
}
c = data[size - 2];
tn5250_buffer_append_byte (buf,
tn5250_char_map_to_local
(tn5250_display_char_map (This->display),
data[size - 1]) ==
'-' ? (0xd0 | (0x0f & c)) : c);
}
else
{
for (n = 0; n < size; n++)
{
tn5250_buffer_append_byte (buf, data[n] == 0 ? 0x40 : data[n]);
}
}
break;
case CMD_READ_MDT_FIELDS:
case CMD_READ_MDT_FIELDS_ALT:
case CMD_READ_IMMEDIATE_ALT:
tn5250_buffer_append_byte (buf, SBA);
tn5250_buffer_append_byte (buf, tn5250_field_start_row (field) + 1);
tn5250_buffer_append_byte (buf, tn5250_field_start_col (field) + 1);
/* For signed numeric fields, if the second-last character is a digit
* and the last character is a '-', zone shift the second-last char.
* In any case, don't send the sign position. */
c = data[size - 1];
if (tn5250_field_is_signed_num (field))
{
size--;
c = size > 0 ? data[size - 1] : 0;
if (size > 1
&& data[size] ==
tn5250_char_map_to_remote (tn5250_display_char_map
(This->display), '-')
&&
isdigit (tn5250_char_map_to_local
(tn5250_display_char_map (This->display), c)))
{
c = (0xd0 | (0x0f & c));
}
}
/* Strip trailing NULs */
while (size > 0 && data[size - 1] == 0)
{
size--;
c = size > 0 ? data[size - 1] : 0;
}
/* Send all but the last character, then send the last character.
* This is because we don't want to modify the display buffer's data
*
* For Read MDT Fields, we translate leading and embedded NULs to
* blanks, for the 'Alternate' commands, we do not.
*/
for (n = 0; n < size - 1; n++)
{
if (This->read_opcode != CMD_READ_MDT_FIELDS)
{
tn5250_buffer_append_byte (buf, data[n]);
}
else
{
tn5250_buffer_append_byte (buf, data[n] == 0 ? 0x40 : data[n]);
}
}
if (size > 0)
{
if (This->read_opcode != CMD_READ_MDT_FIELDS)
{
tn5250_buffer_append_byte (buf, c);
}
else
{
tn5250_buffer_append_byte (buf, c == 0 ? 0x40 : c);
}
}
break;
}
if (field->continuous)
{
free (data);
}
return;
}
/****i* lib5250/tn5250_session_process_stream
* NAME
* tn5250_session_process_stream
* SYNOPSIS
* tn5250_session_process_stream (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_process_stream (Tn5250Session * This)
{
int cur_command;
unsigned long errorcode;
TN5250_LOG (("ProcessStream: entered.\n"));
while (!tn5250_record_is_chain_end (This->record))
{
cur_command = tn5250_record_get_byte (This->record);
if (cur_command != ESC)
{
TN5250_LOG (("cur_command != ESC; cur_pos = %d\n",
This->record->cur_pos));
TN5250_LOG (("Ignoring record!\n"));
return;
TN5250_ASSERT (0);
}
cur_command = tn5250_record_get_byte (This->record);
TN5250_LOG (("ProcessStream: cur_command = 0x%02X\n", cur_command));
switch (cur_command)
{
case CMD_WRITE_TO_DISPLAY:
tn5250_session_write_to_display (This);
break;
case CMD_CLEAR_UNIT:
tn5250_session_clear_unit (This);
break;
case CMD_CLEAR_UNIT_ALTERNATE:
tn5250_session_clear_unit_alternate (This);
break;
case CMD_CLEAR_FORMAT_TABLE:
tn5250_session_clear_format_table (This);
break;
case CMD_READ_MDT_FIELDS:
case CMD_READ_MDT_FIELDS_ALT:
case CMD_READ_INPUT_FIELDS:
tn5250_session_read_cmd (This, cur_command);
break;
case CMD_READ_IMMEDIATE:
tn5250_session_read_immediate (This);
break;
case CMD_READ_SCREEN_IMMEDIATE:
tn5250_session_read_screen_immediate (This);
break;
case CMD_WRITE_STRUCTURED_FIELD:
tn5250_session_write_structured_field (This);
break;
case CMD_SAVE_SCREEN:
tn5250_session_save_screen (This);
break;
case CMD_RESTORE_SCREEN:
/* Ignored, the data following this should be a valid
* Write To Display command. */
TN5250_LOG (("RestoreScreen (ignored)\n"));
break;
case CMD_WRITE_ERROR_CODE:
tn5250_session_write_error_code (This);
break;
case CMD_ROLL:
tn5250_session_roll (This);
break;
case 0x0a:
TN5250_LOG (("Ignoring record!\n"));
break;
default:
TN5250_LOG (("Error: Unknown command 0x%02X.\n", cur_command));
errorcode = TN5250_NR_INVALID_COMMAND;
tn5250_session_send_error (This, errorcode);
}
}
return;
}
/****i* lib5250/tn5250_session_write_error_code
* NAME
* tn5250_session_write_error_code
* SYNOPSIS
* tn5250_session_write_error_code (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_write_error_code (Tn5250Session * This)
{
unsigned char c;
int end_x, end_y;
int have_ic = 0;
unsigned char *tempmsg;
int msglen;
TN5250_LOG (("WriteErrorCode: entered.\n"));
end_x = tn5250_display_cursor_x (This->display);
end_y = tn5250_display_cursor_y (This->display);
/* Message line is restored next time the X II indicator is
* cleared. */
tn5250_display_save_msg_line (This->display);
tn5250_display_set_cursor (This->display,
tn5250_display_msg_line (This->display), 0);
tempmsg = malloc (tn5250_display_width (This->display));
msglen = 0;
while (1)
{
if (tn5250_record_is_chain_end (This->record))
{
break;
}
c = tn5250_record_get_byte (This->record);
if (c == ESC)
{
tn5250_record_unget_byte (This->record);
break;
}
/* In this context, IC does NOT change the Insert Cursor position,
* it just moves the cursor. This is described as the case for the
* Write Error Code command. */
if (c == IC)
{
have_ic = 1;
end_y = tn5250_record_get_byte (This->record) - 1;
end_x = tn5250_record_get_byte (This->record) - 1;
continue;
}
if (tn5250_char_map_printable_p
(tn5250_display_char_map (This->display), c))
{
tempmsg[msglen] = c;
msglen++;
continue;
}
TN5250_LOG (("Error: Unknown order -- %2.2X --\n", c));
TN5250_ASSERT (0);
}
tn5250_display_set_msg_line (This->display, tempmsg, msglen);
free (tempmsg);
tn5250_display_set_cursor (This->display, end_y, end_x);
This->display->keystate = TN5250_KEYSTATE_POSTHELP;
tn5250_display_inhibit (This->display);
return;
}
/****i* lib5250/tn5250_session_handle_cc1
* NAME
* tn5250_session_handle_cc1
* SYNOPSIS
* tn5250_session_handle_cc1 (This, cc1);
* INPUTS
* Tn5250Session * This -
* unsigned char cc1 -
* DESCRIPTION
* Process the first byte of the CC from the WTD command.
*****/
static void
tn5250_session_handle_cc1 (Tn5250Session * This, unsigned char cc1)
{
int lock_kb = 1;
int reset_non_bypass_mdt = 0;
int reset_all_mdt = 0;
int null_non_bypass_mdt = 0;
int null_non_bypass = 0;
Tn5250Field *iter;
switch (cc1 & 0xE0)
{
case 0x00:
lock_kb = 0;
break;
case 0x40:
reset_non_bypass_mdt = 1;
break;
case 0x60:
reset_all_mdt = 1;
break;
case 0x80:
null_non_bypass_mdt = 1;
break;
case 0xA0:
reset_non_bypass_mdt = 1;
null_non_bypass = 1;
break;
case 0xC0:
reset_non_bypass_mdt = 1;
null_non_bypass_mdt = 1;
break;
case 0xE0:
reset_all_mdt = 1;
null_non_bypass = 1;
break;
}
if (lock_kb)
{
TN5250_LOG (("tn5250_session_handle_cc1: Locking keyboard.\n"));
tn5250_display_indicator_set (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
This->display->keystate = TN5250_KEYSTATE_LOCKED;
}
TN5250_ASSERT (This->display != NULL
&& tn5250_display_dbuffer (This->display) != NULL);
if ((iter = tn5250_display_dbuffer (This->display)->field_list) != NULL)
{
do
{
if (!tn5250_field_is_bypass (iter))
{
if ((null_non_bypass_mdt && tn5250_field_mdt (iter))
|| null_non_bypass)
{
unsigned char *data;
data = tn5250_display_field_data (This->display, iter);
memset (data, 0, tn5250_field_length (iter));
}
}
if (reset_all_mdt
|| (reset_non_bypass_mdt && !tn5250_field_is_bypass (iter)))
{
tn5250_field_clear_mdt (iter);
}
iter = iter->next;
}
while (iter != This->display->display_buffers->field_list);
}
return;
}
/****i* lib5250/tn5250_session_write_to_display
* NAME
* tn5250_session_write_to_display
* SYNOPSIS
* tn5250_session_write_to_display (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_write_to_display (Tn5250Session * This)
{
unsigned char cur_order;
unsigned char CC1;
unsigned char CC2;
int done = 0;
unsigned char end_x = 0xff, end_y = 0xff;
int old_x = tn5250_display_cursor_x (This->display);
int old_y = tn5250_display_cursor_y (This->display);
int is_x_system;
int will_be_unlocked;
int cur_opcode;
TN5250_LOG (("WriteToDisplay: entered.\n"));
CC1 = tn5250_record_get_byte (This->record);
CC2 = tn5250_record_get_byte (This->record);
TN5250_LOG (("WriteToDisplay: 0x%02X:0x%02X\n", CC1, CC2));
tn5250_session_handle_cc1 (This, CC1);
while (!done)
{
if (tn5250_record_is_chain_end (This->record))
{
done = 1;
}
else
{
cur_order = tn5250_record_get_byte (This->record);
#ifndef NDEBUG
if (cur_order > 0 && cur_order < 0x40)
TN5250_LOG (("\n"));
#endif
switch (cur_order)
{
case WEA:
tn5250_session_write_extended_attribute (This);
break;
case TD:
tn5250_session_transparent_data (This);
break;
case WDSF:
tn5250_session_write_display_structured_field (This);
break;
case MC:
tn5250_session_move_cursor (This);
break;
case IC:
tn5250_session_insert_cursor (This);
break;
case EA:
tn5250_session_erase_to_address (This);
break;
case RA:
tn5250_session_repeat_to_address (This);
break;
case SBA:
tn5250_session_set_buffer_address (This);
break;
case SF:
tn5250_session_start_of_field (This);
break;
case SOH:
tn5250_session_start_of_header (This);
break;
case ESC:
done = 1;
tn5250_record_unget_byte (This->record);
break;
default:
if (tn5250_char_map_printable_p
(tn5250_display_char_map (This->display), cur_order))
{
tn5250_display_addch (This->display, cur_order);
#ifndef NDEBUG
if (tn5250_char_map_attribute_p
(tn5250_display_char_map (This->display), cur_order))
{
TN5250_LOG (("(0x%02X) ", cur_order));
}
else
{
TN5250_LOG (("%c (0x%02X) ",
tn5250_char_map_to_local
(tn5250_display_char_map (This->display),
cur_order), cur_order));
}
#endif
}
else
{
TN5250_LOG (("Error: Unknown order -- %2.2X --\n",
cur_order));
TN5250_ASSERT (0);
}
} /* end switch */
} /* end else */
} /* end while */
TN5250_LOG (("\n"));
/* If we've gotten an MC or IC order, set the cursor to that position.
* Otherwise set the cursor to the home position (which could be the IC
* position from a prior IC if the unit hasn't been cleared since then,
* but is probably the first position of the first non-bypass field). */
is_x_system = (This->display->keystate != TN5250_KEYSTATE_UNLOCKED);
will_be_unlocked = ((CC2 & TN5250_SESSION_CTL_UNLOCK) != 0);
cur_opcode = tn5250_record_opcode (This->record);
if (end_y != 0xff && end_x != 0xff && !(CC2 & TN5250_SESSION_CTL_IC_ULOCK))
{
tn5250_display_set_cursor (This->display, end_y, end_x);
}
else if ((will_be_unlocked && !(CC2 & TN5250_SESSION_CTL_IC_ULOCK)) ||
cur_opcode == TN5250_RECORD_OPCODE_RESTORE_SCR)
{
tn5250_display_set_cursor_home (This->display);
}
else
{
tn5250_display_set_cursor (This->display, old_y, old_x);
}
tn5250_session_handle_cc2 (This, CC2);
return;
}
/****i* lib5250/tn5250_session_handle_cc2
* NAME
* tn5250_session_handle_cc2
* SYNOPSIS
* tn5250_session_handle_cc2 (This, CC2);
* INPUTS
* Tn5250Session * This -
* unsigned char CC2 -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_handle_cc2 (Tn5250Session * This, unsigned char CC2)
{
TN5250_LOG (("Processing CC2 0x%02X.\n", (int) CC2));
if (CC2 & TN5250_SESSION_CTL_MESSAGE_ON)
{
tn5250_display_indicator_set (This->display,
TN5250_DISPLAY_IND_MESSAGE_WAITING);
}
if ((CC2 & TN5250_SESSION_CTL_MESSAGE_OFF)
&& !(CC2 & TN5250_SESSION_CTL_MESSAGE_ON))
{
tn5250_display_indicator_clear (This->display,
TN5250_DISPLAY_IND_MESSAGE_WAITING);
}
if ((CC2 & TN5250_SESSION_CTL_CLR_BLINK) != 0
&& (CC2 & TN5250_SESSION_CTL_SET_BLINK) == 0)
{
/* FIXME: Hand off to terminal */
}
if ((CC2 & TN5250_SESSION_CTL_SET_BLINK) != 0)
{
/* FIXME: Hand off to terminal */
}
if ((CC2 & TN5250_SESSION_CTL_ALARM) != 0)
{
TN5250_LOG (("TN5250_SESSION_CTL_ALARM was set.\n"));
tn5250_display_beep (This->display);
}
if ((CC2 & TN5250_SESSION_CTL_UNLOCK) != 0)
{
tn5250_display_indicator_clear (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_LOCKED)
{
This->display->keystate = TN5250_KEYSTATE_UNLOCKED;
}
}
TN5250_LOG (("Done Processing CC2.\n"));
return;
}
/****i* lib5250/tn5250_session_clear_unit
* NAME
* tn5250_session_clear_unit
* SYNOPSIS
* tn5250_session_clear_unit (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_clear_unit (Tn5250Session * This)
{
TN5250_LOG (("ClearUnit: entered.\n"));
if (This->display->display_buffers->window_count > 0)
{
Tn5250Window *iter, *next;
if ((iter = This->display->display_buffers->window_list) != NULL)
{
do
{
next = iter->next;
TN5250_LOG (("destroying window id: %d\n", iter->id));
tn5250_terminal_destroy_window (This->display->terminal,
This->display, iter);
iter = next;
}
while (iter != This->display->display_buffers->window_list);
}
This->display->display_buffers->window_list =
tn5250_window_list_destroy (This->display->display_buffers->
window_list);
This->display->display_buffers->window_count = 0;
}
if (This->display->display_buffers->menubar_count > 0)
{
Tn5250Menubar *iter, *next;
if ((iter = This->display->display_buffers->menubar_list) != NULL)
{
do
{
next = iter->next;
tn5250_terminal_destroy_menubar (This->display->terminal,
This->display, iter);
iter = next;
}
while (iter != This->display->display_buffers->menubar_list);
}
This->display->display_buffers->menubar_list =
tn5250_menubar_list_destroy (This->display->display_buffers->
menubar_list);
This->display->display_buffers->menubar_count = 0;
}
if (This->display->display_buffers->scrollbar_count > 0)
{
tn5250_terminal_destroy_scrollbar (This->display->terminal,
This->display);
This->display->display_buffers->scrollbar_list =
tn5250_scrollbar_list_destroy (This->display->display_buffers->
scrollbar_list);
This->display->display_buffers->scrollbar_count = 0;
}
tn5250_display_clear_unit (This->display);
This->read_opcode = 0;
return;
}
/****i* lib5250/tn5250_session_clear_unit_alternate
* NAME
* tn5250_session_clear_unit_alternate
* SYNOPSIS
* tn5250_session_clear_unit_alternate (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_clear_unit_alternate (Tn5250Session * This)
{
unsigned char c;
unsigned long errorcode;
TN5250_LOG (("tn5250_session_clear_unit_alternate entered.\n"));
c = tn5250_record_get_byte (This->record);
TN5250_LOG (("tn5250_session_clear_unit_alternate, parameter is 0x%02X.\n",
(int) c));
if (c != 0x00 && c != 0x80)
{
errorcode = TN5250_NR_INVALID_CLEAR_UNIT_ALT;
tn5250_session_send_error (This, errorcode);
return;
}
if (This->display->display_buffers->window_count > 0)
{
Tn5250Window *iter, *next;
if ((iter = This->display->display_buffers->window_list) != NULL)
{
do
{
next = iter->next;
TN5250_LOG (("destroying window id: %d\n", iter->id));
tn5250_terminal_destroy_window (This->display->terminal,
This->display, iter);
iter = next;
}
while (iter != This->display->display_buffers->window_list);
}
This->display->display_buffers->window_list =
tn5250_window_list_destroy (This->display->display_buffers->
window_list);
This->display->display_buffers->window_count = 0;
}
if (This->display->display_buffers->scrollbar_count > 0)
{
tn5250_terminal_destroy_scrollbar (This->display->terminal,
This->display);
This->display->display_buffers->scrollbar_list =
tn5250_scrollbar_list_destroy (This->display->display_buffers->
scrollbar_list);
This->display->display_buffers->scrollbar_count = 0;
}
tn5250_display_clear_unit_alternate (This->display);
This->read_opcode = 0;
return;
}
/****i* lib5250/tn5250_session_clear_format_table
* NAME
* tn5250_session_clear_format_table
* SYNOPSIS
* tn5250_session_clear_format_table (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_clear_format_table (Tn5250Session * This)
{
TN5250_LOG (("ClearFormatTable: entered.\n"));
tn5250_display_clear_format_table (This->display);
This->read_opcode = 0;
return;
}
/****i* lib5250/tn5250_session_read_immediate
* NAME
* tn5250_session_read_immediate
* SYNOPSIS
* tn5250_session_read_immediate (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_read_immediate (Tn5250Session * This)
{
int old_opcode;
TN5250_LOG (("ReadImmediate: entered.\n"));
old_opcode = This->read_opcode;
This->read_opcode = CMD_READ_IMMEDIATE;
tn5250_session_send_fields (This, 0);
This->read_opcode = old_opcode;
return;
}
/****i* lib5250/tn5250_session_handle_aidkey
* NAME
* tn5250_session_handle_aidkey
* SYNOPSIS
* ret = tn5250_session_handle_aidkey (This, key);
* INPUTS
* Tn5250Session * This -
* int key -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static int
tn5250_session_handle_aidkey (Tn5250Session * This, int key)
{
Tn5250Buffer buf;
StreamHeader header;
switch (key)
{
case TN5250_SESSION_AID_PRINT:
case TN5250_SESSION_AID_RECORD_BS:
tn5250_buffer_init (&buf);
tn5250_buffer_append_byte (&buf,
tn5250_display_cursor_y (This->display) + 1);
tn5250_buffer_append_byte (&buf,
tn5250_display_cursor_x (This->display) + 1);
tn5250_buffer_append_byte (&buf, key);
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_stream_send_packet (This->stream, tn5250_buffer_length (&buf),
header, tn5250_buffer_data (&buf));
tn5250_buffer_free (&buf);
break;
case TN5250_SESSION_AID_SYSREQ:
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_SRQ;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_display_indicator_set (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_UNLOCKED)
{
This->display->keystate = TN5250_KEYSTATE_LOCKED;
}
tn5250_stream_send_packet (This->stream, 0, header, NULL);
tn5250_display_indicator_clear (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_LOCKED)
{
This->display->keystate = TN5250_KEYSTATE_UNLOCKED;
}
break;
case TN5250_SESSION_AID_TESTREQ:
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_TRQ;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_stream_send_packet (This->stream, 0, header, NULL);
break;
case TN5250_SESSION_AID_ATTN:
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_ATN;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_display_indicator_set (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_UNLOCKED)
{
This->display->keystate = TN5250_KEYSTATE_LOCKED;
}
tn5250_stream_send_packet (This->stream, 0, header, NULL);
tn5250_display_indicator_clear (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_LOCKED)
{
This->display->keystate = TN5250_KEYSTATE_UNLOCKED;
}
break;
case TN5250_SESSION_AID_HELP:
if (This->display->keystate == TN5250_KEYSTATE_PREHELP)
{
unsigned char src[2];
src[0] = (This->display->keySRC >> 8) & 0xff;
src[1] = (This->display->keySRC) & 0xff;
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_HLP;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
TN5250_LOG (("PreHelp HELP key: %02x %02x\n", src[0], src[1]));
tn5250_stream_send_packet (This->stream, 2, header, src);
This->display->keystate = TN5250_KEYSTATE_POSTHELP;
break;
}
/* FALLTHROUGH */
default:
/* This should exit the read and set the X SYSTEM indicator. */
tn5250_session_send_fields (This, key);
break;
}
return 1; /* Continue processing. */
}
/****i* lib5250/tn5250_session_output_only
* NAME
* tn5250_session_output_only
* SYNOPSIS
* tn5250_session_output_only (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* I'm not sure what the actual behavior of this opcode is supposed
* to be. I'm just sort-of fudging it based on empirical testing.
*****/
static void
tn5250_session_output_only (Tn5250Session * This)
{
unsigned char temp[2];
TN5250_LOG (("OutputOnly: entered.\n"));
/*
We get this if the user picks something they shouldn't from the
System Request Menu - such as transfer to previous system.
*/
if (tn5250_record_sys_request (This->record))
{
temp[0] = tn5250_record_get_byte (This->record);
temp[1] = tn5250_record_get_byte (This->record);
TN5250_LOG (("OutputOnly: ?? = 0x%02X; ?? = 0x%02X\n", temp[0],
temp[1]));
}
else
{
/*
Otherwise it seems to mean the Attention key menu is being
displayed.
*/
}
return;
}
/****i* lib5250/tn5250_session_save_screen
* NAME
* tn5250_session_save_screen
* SYNOPSIS
* tn5250_session_save_screen (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_save_screen (Tn5250Session * This)
{
Tn5250Buffer buffer;
StreamHeader header;
TN5250_LOG (("SaveScreen: entered.\n"));
tn5250_buffer_init (&buffer);
tn5250_display_make_wtd_data (This->display, &buffer, NULL);
/* Okay, now if we were in a Read MDT Fields or a Read Input Fields,
* we need to append a command which would put us back in the appropriate
* read. */
if (This->read_opcode != 0)
{
tn5250_buffer_append_byte (&buffer, ESC);
tn5250_buffer_append_byte (&buffer, This->read_opcode);
tn5250_buffer_append_byte (&buffer, 0x00); /* FIXME: ? CC1 */
tn5250_buffer_append_byte (&buffer, 0x00); /* FIXME: ? CC2 */
}
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_SAVE_SCR;
tn5250_stream_send_packet (This->stream, tn5250_buffer_length (&buffer),
header, tn5250_buffer_data (&buffer));
tn5250_buffer_free (&buffer);
return;
}
/****i* lib5250/tn5250_session_roll
* NAME
* tn5250_session_roll
* SYNOPSIS
* tn5250_session_roll (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_roll (Tn5250Session * This)
{
unsigned char direction, top, bot;
int lines;
direction = tn5250_record_get_byte (This->record);
top = tn5250_record_get_byte (This->record);
bot = tn5250_record_get_byte (This->record);
TN5250_LOG (("Roll: direction = 0x%02X; top = %d; bottom = %d\n",
(int) direction, (int) top, (int) bot));
lines = (direction & 0x1f);
if ((direction & 0x80) == 0)
{
lines = -lines;
}
TN5250_LOG (("Roll: lines = %d\n", lines));
if (lines == 0)
{
return;
}
tn5250_display_roll (This->display, top, bot, lines);
return;
}
/****i* lib5250/tn5250_session_start_of_field
* NAME
* tn5250_session_start_of_field
* SYNOPSIS
* tn5250_session_start_of_field (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_start_of_field (Tn5250Session * This)
{
int Y, X;
/* int done, curpos; */
Tn5250Field *field;
unsigned char FFW1, FFW2, FCW1, FCW2;
Tn5250Uint16 FCW;
unsigned char Attr;
unsigned char Length1, Length2, cur_char;
int input_field;
int endrow, endcol;
int width;
int height;
unsigned long errorcode;
int startx;
int starty;
int length;
int resequence = 0;
short magstripe = 0;
short lightpen = 0;
short magandlight = 0;
short lightandattn = 0;
short ideographiconly = 0;
short ideographicdatatype = 0;
short ideographiceither = 0;
short ideographicopen = 0;
int transparency = 0;
short forwardedge = 0;
int continuous = 0;
int cont_first = 0;
int cont_middle = 0;
int cont_last = 0;
static int wordwrap = 0;
int progressionid;
unsigned char highlightentryattr = 0x00;
unsigned char pointeraid = 0x00;
short selfcheckmod11 = 0;
short selfcheckmod10 = 0;
TN5250_LOG (("StartOfField: entered.\n"));
cur_char = tn5250_record_get_byte (This->record);
if ((cur_char & 0xe0) != 0x20)
{
/*
* Lock the keyboard and clear any pending aid bytes.
* Only for input fields
*/
tn5250_display_indicator_set (This->display,
TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_UNLOCKED)
{
This->display->keystate = TN5250_KEYSTATE_LOCKED;
}
input_field = 1;
FFW1 = cur_char;
FFW2 = tn5250_record_get_byte (This->record);
TN5250_LOG (("StartOfField: field format word = 0x%02X%02X\n", FFW1,
FFW2));
cur_char = tn5250_record_get_byte (This->record);
continuous = 0;
cont_first = 0;
cont_middle = 0;
cont_last = 0;
progressionid = 0;
FCW1 = 0;
FCW2 = 0;
FCW = 0;
while ((cur_char & 0xe0) != 0x20)
{
FCW1 = cur_char;
FCW2 = tn5250_record_get_byte (This->record);
FCW = (FCW1 << 8) | FCW2;
TN5250_LOG (("StartOfField: field control word = 0x%02X%02X\n",
FCW1, FCW2));
cur_char = tn5250_record_get_byte (This->record);
if (FCW1 == 0x80)
{
resequence = FCW2;
}
if (FCW == 0x8101)
{
magstripe = 1;
}
if (FCW == 0x8102)
{
lightpen = 1;
}
if (FCW == 0x8103)
{
magandlight = 1;
}
if (FCW == 0x8106)
{
lightandattn = 1;
}
if (FCW == 0x8200)
{
ideographiconly = 1;
}
if (FCW == 0x8220)
{
ideographicdatatype = 1;
}
if (FCW == 0x8240)
{
ideographiceither = 1;
}
if ((FCW == 0x8280) || (FCW == 0x82C0))
{
ideographicopen = 1;
}
if (FCW1 == 0x84)
{
transparency = FCW2;
}
if (FCW == 0x8501)
{
forwardedge = 1;
}
if (FCW == 0x8601)
{
continuous = 1;
cont_first = 1;
}
if (FCW == 0x8603)
{
continuous = 1;
cont_middle = 1;
}
if (FCW == 0x8602)
{
continuous = 1;
cont_last = 1;
}
if (FCW == 0x8680)
{
wordwrap = 1;
}
if ((FCW == 0x8602) && (wordwrap == 1))
{
wordwrap = 0;
}
if (FCW1 == 0x88)
{
progressionid = FCW2;
}
if (FCW1 == 0x89)
{
highlightentryattr = FCW2;
}
if (FCW1 == 0x8A)
{
pointeraid = FCW2;
}
if (FCW == 0xB140)
{
selfcheckmod11 = 1;
}
if (FCW == 0xB1A0)
{
selfcheckmod10 = 1;
}
}
}
else
{
/* Output only field. */
input_field = 0;
FFW1 = 0;
FFW2 = 0;
FCW1 = 0;
FCW2 = 0;
}
TN5250_ASSERT ((cur_char & 0xe0) == 0x20);
TN5250_LOG (("StartOfField: attribute = 0x%02X\n", cur_char));
Attr = cur_char;
tn5250_display_addch (This->display, cur_char);
Length1 = tn5250_record_get_byte (This->record);
Length2 = tn5250_record_get_byte (This->record);
length = (Length1 << 8) | Length2;
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
startx = tn5250_display_cursor_x (This->display) + 1;
starty = tn5250_display_cursor_y (This->display) + 1;
TN5250_LOG (("starty = %d width = %d startx = %d length = %d height = %d\n",
starty, width, startx, length, height));
if (continuous)
{
TN5250_LOG (("field is continuous\n"));
}
if (wordwrap)
{
TN5250_LOG (("field has wordwrap\n"));
}
if (progressionid != 0)
{
TN5250_LOG (("field has cursor progression: %d\n", progressionid));
}
if (((starty - 1) * width + startx - 1 + length) > width * height)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
if (input_field)
{
/* FIXME: `This address is either determined by the contents of the
* preceding SBA order or calculated from the field length parameter
* in the last SF order.' 5494 Functions Reference. -JMF */
X = tn5250_display_cursor_x (This->display);
Y = tn5250_display_cursor_y (This->display);
if ((field = tn5250_display_field_at (This->display, Y, X)) != NULL)
{
TN5250_LOG (("StartOfField: Modifying field.\n"));
if (tn5250_field_start_col (field) == X &&
tn5250_field_start_row (field) == Y)
{
field->FFW = (FFW1 << 8) | FFW2;
field->attribute = Attr;
}
}
else
{
TN5250_LOG (("StartOfField: Adding field.\n"));
field = tn5250_field_new (tn5250_display_width (This->display));
TN5250_ASSERT (field != NULL);
field->FFW = (FFW1 << 8) | FFW2;
field->resequence = resequence;
field->magstripe = magstripe;
field->lightpen = lightpen;
field->magandlight = magandlight;
field->lightandattn = lightandattn;
field->ideographiconly = ideographiconly;
field->ideographicdatatype = ideographicdatatype;
field->ideographiceither = ideographiceither;
field->ideographicopen = ideographicopen;
field->transparency = transparency;
field->forwardedge = forwardedge;
field->continuous = continuous;
field->continued_first = cont_first;
field->continued_middle = cont_middle;
field->continued_last = cont_last;
field->wordwrap = wordwrap;
field->nextfieldprogressionid = progressionid;
field->highlightentryattr = highlightentryattr;
field->pointeraid = pointeraid;
field->selfcheckmod11 = selfcheckmod11;
field->selfcheckmod10 = selfcheckmod10;
field->attribute = Attr;
field->length = (Length1 << 8) | Length2;
field->start_row = Y;
field->start_col = X;
tn5250_dbuffer_add_field (tn5250_display_dbuffer (This->display),
field);
}
}
else
{
TN5250_LOG (("StartOfField: Output only field.\n"));
field = NULL;
}
if (input_field)
{
TN5250_ASSERT (field != NULL);
endrow = tn5250_field_end_row (field);
endcol = tn5250_field_end_col (field);
if (endcol == tn5250_display_width (This->display) - 1)
{
endcol = 0;
if (endrow == tn5250_display_height (This->display) - 1)
{
endrow = 0;
}
else
{
endrow++;
}
}
else
{
endcol++;
}
TN5250_LOG (("StartOfField: endrow = %d; endcol = %d\n", endrow,
endcol));
#ifndef NDEBUG
tn5250_field_dump (field);
#endif
tn5250_display_set_cursor (This->display, endrow, endcol);
tn5250_display_addch (This->display, 0x20);
tn5250_display_set_cursor (This->display, Y, X);
}
return;
}
/****i* lib5250/tn5250_session_start_of_header
* NAME
* tn5250_session_start_of_header
* SYNOPSIS
* tn5250_session_start_of_header (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* Clear the format table, get the table header data, and copy it to the
* table. This includes the operator error line (byte 4).
*****/
static void
tn5250_session_start_of_header (Tn5250Session * This)
{
int i, n;
unsigned char *ptr = NULL;
unsigned long errorcode;
TN5250_LOG (("StartOfHeader: entered.\n"));
tn5250_dbuffer_clear_table (tn5250_display_dbuffer (This->display));
tn5250_display_clear_pending_insert (This->display);
tn5250_display_indicator_set (This->display, TN5250_DISPLAY_IND_X_SYSTEM);
if (This->display->keystate == TN5250_KEYSTATE_UNLOCKED)
{
This->display->keystate = TN5250_KEYSTATE_LOCKED;
}
n = tn5250_record_get_byte (This->record);
if (n < 0 || n > 7)
{
errorcode = TN5250_NR_INVALID_SOH_LENGTH;
tn5250_session_send_error (This, errorcode);
return;
}
TN5250_ASSERT ((n > 0 && n <= 7));
if (n > 0)
{
ptr = (unsigned char *) malloc (n);
}
for (i = 0; i < n; i++)
{
ptr[i] = tn5250_record_get_byte (This->record);
}
tn5250_display_set_header_data (This->display, ptr, n);
if (ptr != NULL)
{
free (ptr);
}
return;
}
/****i* lib5250/tn5250_session_set_buffer_address
* NAME
* tn5250_session_set_buffer_address
* SYNOPSIS
* tn5250_session_set_buffer_address (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* FIXME: According to "Functions Reference",
* http://publib.boulder.ibm.com:80/cgi-bin/bookmgr/BOOKS/C02E2001/15.6.4,
* a zero in the column field (X) is acceptable if:
* - The rows field is 1.
* - The SBA order is followed by an SF (Start of Field) order.
* This is how to start a field at row 1, column 1. We should also be
* able to handle a starting attribute there in the display buffer.
*****/
static void
tn5250_session_set_buffer_address (Tn5250Session * This)
{
int X, Y;
int width;
int height;
unsigned long errorcode;
Y = tn5250_record_get_byte (This->record);
X = tn5250_record_get_byte (This->record);
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
if (Y == 0 || Y > height || X == 0 || X > width)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
/* Since we can't handle it yet... */
TN5250_ASSERT ((X == 0 && Y == 1) || (X > 0 && Y > 0));
tn5250_display_set_cursor (This->display, Y - 1, X - 1);
TN5250_LOG (("SetBufferAddress: row = %d; col = %d\n", Y, X));
return;
}
static void
tn5250_session_write_extended_attribute (Tn5250Session * This)
{
/*
This order is not really implemented. It is just here for catching data
stream errors.
*/
unsigned char attrtype;
unsigned char attr;
unsigned long errorcode;
attrtype = tn5250_record_get_byte (This->record);
attr = tn5250_record_get_byte (This->record);
TN5250_LOG (("WEA order (type = 0x%02X, attribute = 0x%02X).\n",
attrtype, attr));
if (attrtype != 0x01 && attrtype != 0x03 && attrtype != 0x05)
{
errorcode = TN5250_NR_INVALID_EXT_ATTR_TYPE;
tn5250_session_send_error (This, errorcode);
return;
}
return;
}
static void
tn5250_session_write_display_structured_field (Tn5250Session * This)
{
/*
This order is not really implemented. We just do enough to checking so
we can handle data stream errors.
*/
unsigned char class;
unsigned char type;
unsigned long errorcode;
int len;
/* first two bytes are the length of the WDSF parameter (the length bytes
are included in the count) */
len = (tn5250_record_get_byte (This->record) << 8) |
tn5250_record_get_byte (This->record);
/* 3rd byte is the class... 0xd9, I think, always */
class = tn5250_record_get_byte (This->record);
if (class != 0xd9)
{
errorcode = TN5250_NR_INVALID_SF_CLASS_TYPE;
tn5250_session_send_error (This, errorcode);
return;
}
/* 4th byte is the type of structured field */
type = tn5250_record_get_byte (This->record);
len -= 4;
switch (type)
{
case UNREST_WIN_CURS_MOVE:
case PROGRAMMABLE_MOUSE_BUT:
case REM_GUI_SCROLL_BAR_FIELD:
case DRAW_ERASE_GRID_LINES:
case CLEAR_GRID_LINE_BUFFER:
TN5250_LOG (("Unhandled WDSF class=%02x type=%02x data=", class, type));
while (len > 0)
{
TN5250_LOG (("%02x", tn5250_record_get_byte (This->record)));
len--;
}
TN5250_LOG (("\n"));
break;
case DEFINE_SELECTION_FIELD:
tn5250_session_define_selection_field (This, len);
break;
case REM_GUI_SEL_FIELD:
tn5250_session_remove_gui_selection_field (This, len);
break;
case WRITE_DATA:
tn5250_session_write_data_structured_field (This, len);
break;
case CREATE_WINDOW:
tn5250_session_create_window_structured_field (This, len);
break;
case REM_GUI_WINDOW:
tn5250_session_remove_gui_window_structured_field (This, len);
break;
case DEFINE_SCROLL_BAR_FIELD:
tn5250_session_define_scrollbar (This, len);
break;
case REM_ALL_GUI_CONSTRUCTS:
tn5250_session_remove_all_gui_constructs_structured_field (This, len);
break;
default:
TN5250_LOG (("tn5250_write_display_structured_field: Invalid SF Class: %02x\n", type));
errorcode = TN5250_NR_INVALID_SF_CLASS_TYPE;
tn5250_session_send_error (This, errorcode);
return;
}
return;
}
static void
tn5250_session_transparent_data (Tn5250Session * This)
{
unsigned char l1, l2;
unsigned td_len;
int width;
int height;
int curx;
int cury;
int end;
int errorcode;
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
curx = tn5250_display_cursor_x (This->display);
cury = tn5250_display_cursor_y (This->display);
l1 = tn5250_record_get_byte (This->record);
l2 = tn5250_record_get_byte (This->record);
td_len = (l1 << 8) | l2;
end = (cury - 1) * width + curx + td_len;
TN5250_LOG (("TD order (length = X'%04X').\n", td_len));
if (end > width * height)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
while (td_len > 0)
{
l1 = tn5250_record_get_byte (This->record);
tn5250_display_addch (This->display, l1);
td_len--;
}
return;
}
static void
tn5250_session_move_cursor (Tn5250Session * This)
{
/*
FIXME: This function is not really implemented. It is just here to
catch errors in the data stream.
*/
unsigned char x = 0xff, y = 0xff;
int width;
int height;
unsigned long errorcode;
y = tn5250_record_get_byte (This->record) - 1;
x = tn5250_record_get_byte (This->record) - 1;
TN5250_LOG (("MC order (y = X'%02X', x = X'%02X').\n", y, x));
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
if (y == 0 || y > height || x == 0 || x > width)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
return;
}
static void
tn5250_session_insert_cursor (Tn5250Session * This)
{
unsigned char x = 0xff, y = 0xff;
int width;
int height;
unsigned long errorcode;
y = tn5250_record_get_byte (This->record);
x = tn5250_record_get_byte (This->record);
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
if (y == 0 || y > height || x == 0 || x > width)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
y--;
x--;
TN5250_LOG (("IC order (y = X'%02X', x = X'%02X').\n", y, x));
tn5250_display_set_pending_insert (This->display, y, x);
return;
}
static void
tn5250_session_erase_to_address (Tn5250Session * This)
{
/*
* FIXME: This function is not completely implemented. It needs to
* support erasing only those attributes listed in the attributes list.
* Right now it only supports the case of erasing everything.
*
* From reading the docs it seems that erasing only attributes will only
* happen after previously receiving a WEA order that puts extended
* attributes in the Extended Character Buffer. Since we don't support
* the extended character buffer we shouldn't ever get a WEA order (the
* QUERY order figures this out). Thus it probably doesn't matter that we
* don't support erasing only attributes.
*/
int x;
int y;
int attribute;
int length;
int curx;
int cury;
unsigned long errorcode;
int start;
int end;
int width;
int height;
TN5250_LOG (("EraseToAddress: entered.\n"));
curx = tn5250_display_cursor_x (This->display) + 1;
cury = tn5250_display_cursor_y (This->display) + 1;
y = tn5250_record_get_byte (This->record);
x = tn5250_record_get_byte (This->record);
length = tn5250_record_get_byte (This->record);
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
start = ((cury - 1) * width) + curx;
end = ((y - 1) * width) + x;
if (end < start || length < 2 || length > 5)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
TN5250_LOG (("Erase from %d, %d to %d, %d\n", curx, cury, x, y));
TN5250_LOG (("Erase attribute type(s) ="));
length--;
while (length > 0)
{
attribute = tn5250_record_get_byte (This->record);
TN5250_LOG ((" 0x%02X", attribute));
length--;
}
TN5250_LOG (("\n"));
if (attribute == 0xFF)
{
tn5250_display_erase_region (This->display, cury, curx, y, x, 1, width);
}
/* the docs say:
* [the EA order] sets the current display address to the location
* specified in the EA plus one.
* But that doesn't seem to always work. The address in the EA can be
* the end of the screen, so we can't really set the cursor there.
*/
if (x >= width)
{
x = 0;
}
if (y >= height)
{
y = 0;
}
tn5250_display_set_cursor (This->display, y, x);
return;
}
/****i* lib5250/tn5250_session_repeat_to_address
* NAME
* tn5250_session_repeat_to_address
* SYNOPSIS
* tn5250_session_repeat_to_address (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_repeat_to_address (Tn5250Session * This)
{
unsigned char temp[3];
int x, y;
/* These variables don't appear to be needed
* int ins_loc;
* Tn5250Field *field;
*/
unsigned long errorcode;
int width;
int height;
int start;
int end;
TN5250_LOG (("RepeatToAddress: entered.\n"));
temp[0] = tn5250_record_get_byte (This->record);
temp[1] = tn5250_record_get_byte (This->record);
temp[2] = tn5250_record_get_byte (This->record);
y = tn5250_display_cursor_y (This->display) + 1;
x = tn5250_display_cursor_x (This->display) + 1;
width = tn5250_display_width (This->display);
height = tn5250_display_height (This->display);
start = (y - 1) * width + x;
end = (temp[0] - 1) * width + temp[1];
TN5250_LOG (("RepeatToAddress: row = %d; col = %d; char = 0x%02X\n",
temp[0], temp[1], temp[2]));
if (temp[0] == 0 || temp[0] > height
|| temp[1] == 0 || temp[1] > width || end < start)
{
errorcode = TN5250_NR_INVALID_ROW_COL_ADDR;
tn5250_session_send_error (This, errorcode);
return;
}
while (1)
{
y = tn5250_display_cursor_y (This->display);
x = tn5250_display_cursor_x (This->display);
tn5250_display_addch (This->display, temp[2]);
if (y == temp[0] - 1 && x == temp[1] - 1)
{
break;
}
}
return;
}
/****i* lib5250/tn5250_session_write_structured_field
* NAME
* tn5250_session_write_structured_field
* SYNOPSIS
* tn5250_session_write_structured_field (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_write_structured_field (Tn5250Session * This)
{
unsigned char temp[5];
unsigned long errorcode;
TN5250_LOG (("WriteStructuredField: entered.\n"));
temp[0] = tn5250_record_get_byte (This->record);
temp[1] = tn5250_record_get_byte (This->record);
temp[2] = tn5250_record_get_byte (This->record);
temp[3] = tn5250_record_get_byte (This->record);
temp[4] = tn5250_record_get_byte (This->record);
TN5250_LOG (("WriteStructuredField: length = %d\n",
(temp[0] << 8) | temp[1]));
TN5250_LOG (("WriteStructuredField: command class = 0x%02X\n", temp[2]));
TN5250_LOG (("WriteStructuredField: command type = 0x%02X\n", temp[3]));
if (temp[2] != 0xD9)
{
TN5250_LOG (("tn5250_write_structured_field: Invalid SF Class: %02x\n",
temp[2]));
errorcode = TN5250_NR_INVALID_SF_CLASS_TYPE;
tn5250_session_send_error (This, errorcode);
return;
}
else
{
switch (temp[3])
{
case DEFINE_AUDIT_WINDOW_TABLE:
case DEFINE_COMMAND_KEY_FUNCTION:
case READ_TEXT_SCREEN:
case DEFINE_PENDING_OPERATIONS:
case DEFINE_TEXT_SCREEN_FORMAT:
case DEFINE_SCALE_TIME:
case WRITE_TEXT_SCREEN:
case DEFINE_SPECIAL_CHARACTERS:
case PENDING_DATA:
case DEFINE_OPERATOR_ERROR_MSGS:
case DEFINE_PITCH_TABLE:
case DEFINE_FAKE_DP_CMD_KEY_FUNC:
case PASS_THROUGH:
case SF_5250_QUERY:
case SF_5250_QUERY_STATION_STATE:
break;
default:
TN5250_LOG (("tn5250_write_structured_field(2): Invalid SF Class: %02x\n", temp[3]));
errorcode = TN5250_NR_INVALID_SF_CLASS_TYPE;
tn5250_session_send_error (This, errorcode);
return;
}
}
tn5250_session_query_reply (This);
return;
}
/****i* lib5250/tn5250_session_read_screen_immediate
* NAME
* tn5250_session_read_screen_immediate
* SYNOPSIS
* tn5250_session_read_screen_immediate (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_read_screen_immediate (Tn5250Session * This)
{
int row, col;
int buffer_size;
unsigned char *buffer;
StreamHeader header;
TN5250_LOG (("ReadScreenImmediate: entered.\n"));
buffer_size = tn5250_display_width (This->display) *
tn5250_display_height (This->display);
buffer = (unsigned char *) malloc (buffer_size);
for (row = 0; row < tn5250_display_height (This->display); row++)
{
for (col = 0; col < tn5250_display_width (This->display); col++)
{
buffer[row * tn5250_display_width (This->display) + col]
= tn5250_display_char_at (This->display, row, col);
}
}
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_stream_send_packet (This->stream, buffer_size, header, buffer);
free (buffer);
return;
}
/****i* lib5250/tn5250_session_read_cmd
* NAME
* tn5250_session_read_cmd
* SYNOPSIS
* tn5250_session_read_cmd (This, readop);
* INPUTS
* Tn5250Session * This -
* int readop -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_read_cmd (Tn5250Session * This, int readop)
{
unsigned char CC1, CC2;
TN5250_LOG (("tn5250_session_read_cmd: readop = 0x%02X.\n", readop));
CC1 = tn5250_record_get_byte (This->record);
tn5250_session_handle_cc1 (This, CC1);
CC2 = tn5250_record_get_byte (This->record);
tn5250_session_handle_cc2 (This, CC2);
TN5250_LOG (("tn5250_session_read_cmd: CC1 = 0x%02X; CC2 = 0x%02X\n", CC1,
CC2));
tn5250_display_indicator_clear (This->display,
TN5250_DISPLAY_IND_X_SYSTEM |
TN5250_DISPLAY_IND_X_CLOCK);
/* The read command only uninhibits the keyboard if we were in a
"normal locked" keystate. (In other words, we weren't inhibited
by an error, but by a normal condition) */
if (This->display->keystate == TN5250_KEYSTATE_LOCKED)
{
tn5250_display_uninhibit (This->display);
This->display->keystate = TN5250_KEYSTATE_UNLOCKED;
}
This->read_opcode = readop;
return;
}
/****i* lib5250/tn5250_session_query_reply
* NAME
* tn5250_session_query_reply
* SYNOPSIS
* tn5250_session_query_reply (This);
* INPUTS
* Tn5250Session * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_query_reply (Tn5250Session * This)
{
unsigned char temp[67];
const char *scan;
int dev_type, dev_model, i, enhanced;
StreamHeader header;
TN5250_LOG (("Sending QueryReply.\n"));
if (tn5250_terminal_enhanced (This->display->terminal))
{
enhanced = tn5250_config_get_bool (This->config, "enhanced");
}
else
{
enhanced = 0;
}
if (enhanced)
{
TN5250_LOG (("turning on enhanced 5250 features\n"));
}
temp[0] = 0x00; /* Cursor Row/Column (set to zero) */
temp[1] = 0x00;
temp[2] = 0x88; /* Inbound Write Structured Field Aid */
/* Note that the IBM docs show this length as X'0044'. */
temp[3] = 0x00; /* Length of Query Reply */
if (enhanced)
{
temp[4] = 0x40;
}
else
{
temp[4] = 0x3A;
}
temp[5] = 0xD9; /* Command class */
temp[6] = 0x70; /* Command type - Query */
temp[7] = 0x80; /* Flag byte */
/* The following bytes are supposed to correspond to table 89 of section
* 15.27.2 5250 QUERY Command of the Functions Reference manual.
*/
/* This appears to be wrong. Table 89 describes the first field of the
* QUERY Response Data Field as:
* Workstation Control Unit | X'0043' | Identifies the controller as
* a 5494
*
* I don't know where the X'0600' came from, but it appears to be
* working.
*/
temp[8] = 0x06; /* Controller hardware class */
temp[9] = 0x00; /* 0x600 - Other WSF or another 5250 emulator */
/* Here the docs use X'040310' for version 4 release 3.1. But it doesn't
* appear to make any difference.
*/
temp[10] = 0x01; /* Controller code level (Version 1 Release 1.0 */
temp[11] = 0x01;
temp[12] = 0x00;
temp[13] = 0x00; /* Reserved (set to zero) */
temp[14] = 0x00;
temp[15] = 0x00;
temp[16] = 0x00;
temp[17] = 0x00;
temp[18] = 0x00;
temp[19] = 0x00;
temp[20] = 0x00;
temp[21] = 0x00;
temp[22] = 0x00;
temp[23] = 0x00;
temp[24] = 0x00;
temp[25] = 0x00;
temp[26] = 0x00;
temp[27] = 0x00;
temp[28] = 0x00;
temp[29] = 0x01; /* Display or printer emulation */
/* Retreive the device type from the stream, parse out the device
* type and model, convert it to EBCDIC, and put it in the packet. */
scan = tn5250_config_get (This->config, "env.TERM");
TN5250_ASSERT (scan != NULL);
TN5250_ASSERT (strchr (scan, '-') != NULL);
scan = strchr (scan, '-') + 1;
dev_type = atoi (scan);
if (strchr (scan, '-'))
{
dev_model = atoi (strchr (scan, '-') + 1);
}
else
{
dev_model = 1;
}
sprintf ((char *) temp + 30, "%04d", dev_type);
sprintf ((char *) temp + 35, "%02d", dev_model);
for (i = 30; i <= 36; i++)
{
temp[i] =
tn5250_char_map_to_remote (tn5250_display_char_map (This->display),
temp[i]);
}
temp[37] = 0x02; /* Keyboard ID:
X'02' = Standard Keyboard
X'82' = G Keyboard */
temp[38] = 0x00; /* Extended keyboard ID */
temp[39] = 0x00; /* Reserved */
/* I really doubt we have serial number. This should probably be set to
* all zeroes since the docs say so for workstations without a serial
* number.
*/
temp[40] = 0x00; /* Display serial number */
temp[41] = 0x61;
temp[42] = 0x50;
temp[43] = 0x00;
/* Here the docs suggest that the maximum is 256. I guess it would be
* possible to have a screen with 1701 input fields (a 127 by 27 screen
* can have at most (126/2) * 27) = 1701 fields on it). At any rate,
* 65535 doesn't appear to be supported.
*/
temp[44] = 0xff; /* Maximum number of input fields (65535) */
temp[45] = 0xff;
temp[46] = 0x00; /* Control unit customization */
temp[47] = 0x00; /* Reserved (set to zero) */
temp[48] = 0x00;
temp[49] = 0x23; /* Controller/Display Capability */
temp[50] = 0x31;
temp[51] = 0x00; /* Reserved */
temp[52] = 0x00;
/* byte 53:
* bits 0-2: B'000' = no graphics
* B'001' = 5292-style graphics
* B'010' = GDDM-OS/2 Link Graphics
* bit 3: extended 3270 data stream capability
* bit 4: pointer device (mouse) available
* bit 5: GUI-like characters available
* bit 6: Enhanced 5250 FCW & WDSFs
* bit 7: WRITE ERROR CODE TO WINDOW command support
*
* byte 54:
* bit 0: enhanced user interface support level 2
* bit 1: GUI device w/all-points addressable windows, etc
* bit 2: WordPerfect support is available
* bit 3: Dynamic status & scale line
* bit 4: enhanced user interface support level 3
* bit 5: cursor draw is supported in Office editor
* bits 6-7: video delivery capability B'00' = none, B'01'=5250
*
* Enabling enhanced 5250 means we need to support:
* WDSFs: CREATE WINDOW
* UNRESTRICTED CURSOR MOVEMENT
* DEFINE SELECTION FIELD
* DEFINE SCROLL BAR FIELD
* REMOVE ALL GUI CONSTRUCTS
* REMOVE GUI WINDOW
* REMOVE GUI SELECTION FIELD
* REMOVE GUI SCROLL BAR FIELD
* READ SCREEN TO PRINT
* READ SCREEN TO PRINT WITH EXTENDED ATTRIBUTES
* WRITE ERROR CODE TO WINDOW
* SAVE PARTIAL SCREEN
* RESTORE PARTIAL SCREEN
*
* FCWs: Continued Fields
* Cursor Progression
* Highlighted
* Mouse Selection
*
* Enabling enhanced 5250 Level 2 means we also need to support:
* WDSFs: WRITE DATA
* PROGRAMMABLE MOUSE BUTTONS
* FCWs: Word Wrap
* Ideographic Continued Entry Fields
*/
if (enhanced)
{
temp[53] = 0x02;
temp[54] = 0x80;
}
else
{
temp[53] = 0x00;
temp[54] = 0x00;
}
temp[55] = 0x00;
temp[56] = 0x00;
temp[57] = 0x00;
temp[58] = 0x00;
temp[59] = 0x00;
temp[60] = 0x00;
temp[61] = 0x00;
temp[62] = 0x00;
temp[63] = 0x00;
temp[64] = 0x00;
temp[65] = 0x00;
temp[66] = 0x00;
header.h5250.flowtype = TN5250_RECORD_FLOW_DISPLAY;
header.h5250.flags = TN5250_RECORD_H_NONE;
header.h5250.opcode = TN5250_RECORD_OPCODE_NO_OP;
tn5250_stream_send_packet (This->stream, temp[4] + 3, header,
(unsigned char *) temp);
return;
}
/****i* lib5250/tn5250_session_define_selection_field
* NAME
* tn5250_session_define_selection_field
* SYNOPSIS
* tn5250_session_define_selection_field (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_define_selection_field (Tn5250Session * This, int length)
{
Tn5250DBuffer *dbuffer;
Tn5250Menubar *menubar;
unsigned char flagbyte1;
unsigned char flagbyte2;
unsigned char flagbyte3;
unsigned char fieldtype;
unsigned char padding;
unsigned char separator;
unsigned char selectionchar;
unsigned char cancelaid;
unsigned char reserved;
int minorlength;
int menuitemcount;
short usescrollbar = 0;
short createnewmenubar = 0;
TN5250_LOG (("Entering tn5250_session_define_selection_field()\n"));
/* Menus can't overlay each other. If this menu is in the same position as
* another, redefine the menu instead of creating a new one.
*/
dbuffer = tn5250_display_dbuffer (This->display);
if ((menubar = tn5250_menubar_hit_test (dbuffer->menubar_list,
tn5250_display_cursor_x (This->
display),
tn5250_display_cursor_y (This->
display)))
== NULL)
{
menubar = tn5250_menubar_new ();
createnewmenubar = 1;
}
flagbyte1 = tn5250_record_get_byte (This->record);
/* The first two bits define mouse characteristics */
if ((flagbyte1 & 0xC0) == 0)
{
TN5250_LOG (("Use this selection field in all cases\n"));
}
/* both bits cannot be on */
if ((flagbyte1 & 0xC0) == 3)
{
TN5250_LOG (("Reserved usage of mouse characteristics!\n"));
}
else
{
if (flagbyte1 & 0x40)
{
TN5250_LOG (("Use this selection field only if the display does not have a mouse\n"));
}
if (flagbyte1 & 0x80)
{
TN5250_LOG (("Use this selection field only if the display has a mouse\n"));
}
}
/* bits 4 and 5 define auto enter */
if ((flagbyte1 & 0x0C) == 0)
{
TN5250_LOG (("Selection field is not auto-enter\n"));
}
else if ((flagbyte1 & 0x0C) == 1)
{
TN5250_LOG (("Selection field is auto-enter on selection except if double-digit numeric selection is used\n"));
}
else if ((flagbyte1 & 0x0C) == 2)
{
TN5250_LOG (("Selection field is auto-enter on selection or deselection except if double-digit numeric selection is used\n"));
}
else
{
TN5250_LOG (("Selection field is auto-enter on selection except if single-digit or double-digit numeric selection is used\n"));
}
/* bit six controls auto-select */
if (flagbyte1 & 0x02)
{
TN5250_LOG (("Auto-select active\n"));
}
flagbyte2 = tn5250_record_get_byte (This->record);
if (flagbyte2 & 0x80)
{
TN5250_LOG (("Use scroll bar\n"));
usescrollbar = 1;
}
if (flagbyte2 & 0x40)
{
TN5250_LOG (("Add blank after numeric seperator\n"));
}
if (flagbyte2 & 0x20)
{
TN5250_LOG (("Use * for unavailable options\n"));
}
if (flagbyte2 & 0x10)
{
TN5250_LOG (("Limit cursor to input capable positions\n"));
}
if (flagbyte2 & 0x08)
{
TN5250_LOG (("Field advance = character advance\n"));
}
if (flagbyte2 & 0x04)
{
menubar->restricted_cursor = 1;
TN5250_LOG (("Cursor may not exit selection field\n"));
}
else
{
menubar->restricted_cursor = 0;
}
flagbyte3 = tn5250_record_get_byte (This->record);
if (flagbyte3 & 0x80)
{
TN5250_LOG (("Make selected choices available when keyboard is unlocked\n"));
}
TN5250_LOG (("Selection field type: "));
fieldtype = tn5250_record_get_byte (This->record);
if (fieldtype == 0x01)
{
TN5250_LOG (("Menubar\n"));
}
else if (fieldtype == 0x11)
{
TN5250_LOG (("Single choice selection field\n"));
}
else if (fieldtype == 0x12)
{
TN5250_LOG (("Multiple choice selection field\n"));
}
else if (fieldtype == 0x21)
{
TN5250_LOG (("Single choice selection list\n"));
}
else if (fieldtype == 0x22)
{
TN5250_LOG (("Multiple choice selection list\n"));
}
else if (fieldtype == 0x31)
{
TN5250_LOG (("Single choice selection field and pulldown list\n"));
}
else if (fieldtype == 0x32)
{
TN5250_LOG (("Multiple choice selection field and pulldown list\n"));
}
else if (fieldtype == 0x41)
{
TN5250_LOG (("Push buttons\n"));
}
else if (fieldtype == 0x51)
{
TN5250_LOG (("Push buttons in a pulldown menu\n"));
}
else
{
TN5250_LOG (("Invalid field selection type!!\n"));
}
menubar->flagbyte1 = flagbyte1;
menubar->flagbyte2 = flagbyte2;
menubar->flagbyte3 = flagbyte3;
menubar->type = fieldtype;
reserved = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
menubar->itemsize = tn5250_record_get_byte (This->record);
TN5250_LOG (("textsize = 0x%02X (%d)\n", menubar->itemsize,
menubar->itemsize));
menubar->height = tn5250_record_get_byte (This->record);
TN5250_LOG (("rows = 0x%02X (%d)\n", menubar->height, menubar->height));
menubar->items = tn5250_record_get_byte (This->record);
TN5250_LOG (("choices = 0x%02X (%d)\n", menubar->items, menubar->items));
padding = tn5250_record_get_byte (This->record);
TN5250_LOG (("padding = 0x%02X (%d)\n", padding, (int) padding));
separator = tn5250_record_get_byte (This->record);
TN5250_LOG (("separator = 0x%02X\n", separator));
selectionchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("selectionchar = 0x%02X\n", selectionchar));
cancelaid = tn5250_record_get_byte (This->record);
TN5250_LOG (("cancelaid = 0x%02X\n", cancelaid));
length = length - 16;
if (length == 0)
{
return;
}
/* The docs are confusing and I'm not sure what to do. So I'll give up */
if (usescrollbar)
{
TN5250_LOG (("Scroll bars not supported in selection fields\n"));
}
if (createnewmenubar)
{
menubar->column = tn5250_display_cursor_x (This->display);
menubar->row = tn5250_display_cursor_y (This->display);
tn5250_dbuffer_add_menubar (tn5250_display_dbuffer (This->display),
menubar);
tn5250_terminal_create_menubar (This->display->terminal,
This->display, menubar);
}
menuitemcount = 0;
while (length > 0)
{
minorlength = (int) tn5250_record_get_byte (This->record) - 2;
length--;
reserved = tn5250_record_get_byte (This->record);
length--;
if (reserved == 0x10)
{
tn5250_session_define_selection_item (This, menubar, minorlength,
menuitemcount,
createnewmenubar);
menuitemcount++;
length = length - minorlength;
}
/* Get the Choice Presentation Display Attributes Minor Structure if
* it is there.
*/
else if (reserved == 0x01)
{
while (minorlength > 0)
{
reserved = tn5250_record_get_byte (This->record);
TN5250_LOG (("Choice Presentation = 0x%02X\n", reserved));
length--;
minorlength--;
}
}
/* Get the Menu Bar Separator Minor Structure if it is there.
*/
else if (reserved == 0x09)
{
while (minorlength > 0)
{
reserved = tn5250_record_get_byte (This->record);
TN5250_LOG (("Menu Bar Separator = 0x%02X\n", reserved));
length--;
minorlength--;
}
}
/* Get the Choice Indicator Minor Structure if it is there.
*/
else if (reserved == 0x02)
{
while (minorlength > 0)
{
reserved = tn5250_record_get_byte (This->record);
TN5250_LOG (("Choice Indicator = 0x%02X\n", reserved));
length--;
minorlength--;
}
}
/* Get the Scroll Bar Indicators Minor Structure if it is there.
*/
else if (reserved == 0x03)
{
while (minorlength > 0)
{
reserved = tn5250_record_get_byte (This->record);
TN5250_LOG (("Scroll Bar Indicators = 0x%02X\n", reserved));
length--;
minorlength--;
}
}
else
{
TN5250_LOG (("unknown data = 0x%02X\n", reserved));
}
}
return;
}
/****i* lib5250/tn5250_session_define_selection_item
* NAME
* tn5250_session_define_selection_item
* SYNOPSIS
* tn5250_session_define_selection_item (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_define_selection_item (Tn5250Session * This,
Tn5250Menubar * menubar, int length,
int count, short createnew)
{
Tn5250Menuitem *menuitem;
unsigned char flagbyte1;
unsigned char flagbyte2;
unsigned char flagbyte3;
unsigned char reserved;
short offset_incl = 0;
short aid_incl = 0;
short selectchars_incl = 0;
int i;
TN5250_LOG (("Entering tn5250_session_define_selection_item()\n"));
if (createnew)
{
menuitem = tn5250_menuitem_new ();
}
else
{
menuitem = tn5250_menuitem_list_find_by_id (menubar->menuitem_list,
count);
}
flagbyte1 = tn5250_record_get_byte (This->record);
length--;
/* The first two bits choice state */
if ((flagbyte1 & 0xC0) == 0)
{
menuitem->available = 1;
TN5250_LOG (("Available and not a default selection\n"));
}
/* both bits cannot be on */
if ((flagbyte1 & 0xC0) == 3)
{
TN5250_LOG (("Reserved usage of choice state!\n"));
}
else
{
if (flagbyte1 & 0x40)
{
menuitem->selected = 1;
menuitem->available = 1;
TN5250_LOG (("Available and is a default selection (selected state)\n"));
}
if (flagbyte1 & 0x80)
{
menuitem->selected = 0;
menuitem->available = 0;
TN5250_LOG (("Not available\n"));
}
}
/* bit 2 specifies menu item that start a new row */
if (flagbyte1 & 0x20)
{
TN5250_LOG (("Menu item starts a new row\n"));
}
/* bit 4 indicates mnemonic offset is included */
if (flagbyte1 & 0x08)
{
TN5250_LOG (("mnemonic offset is included\n"));
offset_incl = 1;
}
/* bit 5 specifies an AID if selected is included in this minor structure */
if (flagbyte1 & 0x04)
{
TN5250_LOG (("AID is included\n"));
aid_incl = 1;
}
/* bits 6 and 7 define numeric selection characters */
if ((flagbyte1 & 0x03) == 0)
{
TN5250_LOG (("Numeric selection characters are not included in this minor structure\n"));
}
else if ((flagbyte1 & 0x0C) == 1)
{
TN5250_LOG (("A single-digit numeric selection character is included in this minor structure\n"));
selectchars_incl = 1;
}
else if ((flagbyte1 & 0x0C) == 2)
{
TN5250_LOG (("Double-digit numeric selection characters are included in this minor structure\n"));
selectchars_incl = 1;
}
else
{
TN5250_LOG (("Reserved use of numeric selection charaters!!\n"));
}
flagbyte2 = tn5250_record_get_byte (This->record);
length--;
if (flagbyte2 & 0x80)
{
TN5250_LOG (("choice cannot accept a cursor\n"));
}
if (flagbyte2 & 0x40)
{
TN5250_LOG (("application user desires a roll-down AID if the Cursor Up key is pressed on this choice\n"));
}
if (flagbyte2 & 0x20)
{
TN5250_LOG (("application user desires a roll-up AID if the Cursor Down key is pressed on this choice\n"));
}
if (flagbyte2 & 0x10)
{
TN5250_LOG (("application user desires a roll-left AID if the Cursor Left key is pressed on this choice\n"));
}
if (flagbyte2 & 0x08)
{
TN5250_LOG (("application user desires a roll-right AID if the Cursor Right key is pressed on this choice\n"));
}
if (flagbyte2 & 0x04)
{
TN5250_LOG (("no push-button box is written for this choice\n"));
}
if (flagbyte2 & 0x01)
{
TN5250_LOG (("cursor direction is right to left\n"));
}
flagbyte3 = tn5250_record_get_byte (This->record);
length--;
menuitem->flagbyte1 = flagbyte1;
menuitem->flagbyte2 = flagbyte2;
menuitem->flagbyte3 = flagbyte3;
/* The first three bits cannot all be off */
if ((flagbyte3 & 0xE0) == 0)
{
TN5250_LOG (("Minor structure ignored\n"));
while (length > 0)
{
reserved = tn5250_record_get_byte (This->record);
TN5250_LOG (("ignored = 0x%02X\n", reserved));
length--;
}
return;
}
if (flagbyte3 & 0x80)
{
TN5250_LOG (("use this minor structure for GUI devices (including GUI-like NWSs)\n"));
}
if (flagbyte3 & 0x40)
{
TN5250_LOG (("use this minor structure for non-GUI NWSs that are capable of creating mnemonic underscores\n"));
}
if (flagbyte3 & 0x20)
{
TN5250_LOG (("use this minor structure for NWS display devices that are not capable of creating underscores\n"));
}
if (offset_incl)
{
reserved = tn5250_record_get_byte (This->record);
length--;
TN5250_LOG (("mnemonic offset: 0x%02X\n", reserved));
}
if (aid_incl)
{
reserved = tn5250_record_get_byte (This->record);
length--;
TN5250_LOG (("AID: 0x%02X\n", reserved));
}
if (selectchars_incl)
{
reserved = tn5250_record_get_byte (This->record);
length--;
TN5250_LOG (("Numeric characters: 0x%02X\n", reserved));
}
if (!createnew)
{
free (menuitem->text);
}
menuitem->text = tn5250_new (unsigned char, menubar->itemsize + 1);
for (i = 0; (i < menubar->itemsize) && (length > 0); i++)
{
menuitem->text[i] = tn5250_record_get_byte (This->record);
TN5250_LOG (("Choice text = %c\n", tn5250_char_map_to_local
(tn5250_display_char_map (This->display),
menuitem->text[i])));
length--;
}
/* The size of this menu item is the length of the text plus two
* attribute characters.
*/
menuitem->size = i + 2;
/* fill the rest of the text with nulls since that will allow us to use
* strlen() on it.
*/
for (; (i < menubar->itemsize + 1); i++)
{
menuitem->text[i] = '\0';
}
if (createnew)
{
tn5250_menu_add_menuitem (menubar, menuitem);
/* The row and column must be calculated after adding the menu item to
* the list.
*/
menuitem->row = tn5250_menuitem_new_row (menuitem);
menuitem->column = tn5250_menuitem_new_col (menuitem);
/*
menuitem->row = tn5250_display_cursor_y (This->display);
menuitem->column = tn5250_display_cursor_x (This->display);
*/
}
if (createnew)
{
tn5250_terminal_create_menuitem (This->display->terminal,
This->display, menuitem);
}
return;
}
/****i* lib5250/tn5250_session_remove_gui_selection_field
* NAME
* tn5250_session_remove_gui_selection_field
* SYNOPSIS
* tn5250_session_remove_gui_selection_field (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_remove_gui_selection_field (Tn5250Session * This, int length)
{
unsigned char flagbyte1;
unsigned char reserved;
TN5250_LOG (("Entering tn5250_session_remove_gui_selection_field()\n"));
flagbyte1 = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
if (tn5250_dbuffer_menubar_count (This->display->display_buffers) > 0)
{
tn5250_terminal_destroy_menubar (This->display->terminal,
This->display,
This->display->display_buffers->
menubar_list);
This->display->display_buffers->menubar_list =
tn5250_menubar_list_destroy (This->display->display_buffers->
menubar_list);
This->display->display_buffers->menubar_count = 0;
}
return;
}
/****i* lib5250/tn5250_session_create_window_structured_field
* NAME
* tn5250_session_create_window_structured_field
* SYNOPSIS
* tn5250_session_create_window_structured_field (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_create_window_structured_field (Tn5250Session * This,
int length)
{
Tn5250Window *window;
unsigned char flagbyte1;
unsigned char depth;
unsigned char width;
unsigned char reserved;
int border_length;
unsigned char border_type, border_flags, border_mono;
unsigned char border_color, border_upperlchar, border_topchar;
unsigned char border_upperrchar, border_leftchar, border_rightchar;
unsigned char border_lowerlchar, border_bottomchar, border_lowerrchar;
short pulldown = 0;
TN5250_LOG (("Entering tn5250_session_create_window_structured_field()\n"));
flagbyte1 = tn5250_record_get_byte (This->record);
if (flagbyte1 & 0x80)
{
TN5250_LOG (("Cursor restricted to window\n"));
}
if (flagbyte1 & 0x40)
{
/*
TN5250_LOG (("Pull down window - data ignored (will use selection field data)\n"));
*/
TN5250_LOG (("Pull down window\n"));
pulldown = 1;
}
reserved = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
depth = tn5250_record_get_byte (This->record);
TN5250_LOG (("depth = 0x%02X (%d)\n", depth, (int) depth));
width = tn5250_record_get_byte (This->record);
TN5250_LOG (("width = 0x%02X (%d)\n", width, (int) width));
/*
if (!pulldown)
{
*/
/*
if ((window =
tn5250_window_match_test (This->display->display_buffers->
window_list,
tn5250_display_cursor_x (This->display) +
1,
tn5250_display_cursor_y (This->display) +
1, width, depth)) != NULL)
{
}
else
{
*/
window = tn5250_window_new ();
/*
}
*/
/*
}
*/
if ((length - 5) > 0)
{
length = length - 5;
border_length = tn5250_record_get_byte (This->record);
TN5250_LOG (("border_length = 0x%02X (%d)\n", border_length,
border_length));
border_length--;
length--;
if (border_length > 0)
{
border_type = tn5250_record_get_byte (This->record);
TN5250_LOG (("Border type = 0x%02X\n", border_length));
border_length--;
length--;
}
/* Format for Border Presentation Minor Structure */
if (border_type == 0x01)
{
if (border_length > 0)
{
border_flags = tn5250_record_get_byte (This->record);
if (border_flags & 0x80)
{
TN5250_LOG (("Use border presentation characters (GUI-like NWS)\n"));
}
border_length--;
length--;
}
if (border_length > 0)
{
border_mono = tn5250_record_get_byte (This->record);
TN5250_LOG (("Monochrome border attribute = 0x%02X\n",
border_mono));
border_length--;
length--;
}
if (border_length > 0)
{
border_color = tn5250_record_get_byte (This->record);
TN5250_LOG (("Color border attribute = 0x%02X\n",
border_color));
border_length--;
length--;
}
if (border_length > 0)
{
border_upperlchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Upper left border character = 0x%02X\n",
border_upperlchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_topchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Top border character = 0x%02X\n",
border_topchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_upperrchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Upper right border character = 0x%02X\n",
border_upperrchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_leftchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Left border character = 0x%02X\n",
border_leftchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_rightchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Right border character = 0x%02X\n",
border_rightchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_lowerlchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Lower left border character = 0x%02X\n",
border_lowerlchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_bottomchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Bottom border character = 0x%02X\n",
border_bottomchar));
border_length--;
length--;
}
if (border_length > 0)
{
border_lowerrchar = tn5250_record_get_byte (This->record);
TN5250_LOG (("Lower right border character = 0x%02X\n",
border_lowerrchar));
border_length--;
length--;
}
}
/* Format for Window Title/Footer Minor Structure */
else if (border_type == 0x10)
{
if (border_length > 0)
{
border_flags = tn5250_record_get_byte (This->record);
border_length--;
length--;
}
if (border_length > 0)
{
border_mono = tn5250_record_get_byte (This->record);
border_length--;
length--;
}
if (border_length > 0)
{
border_color = tn5250_record_get_byte (This->record);
border_length--;
length--;
}
if (border_length > 0)
{
reserved = tn5250_record_get_byte (This->record);
border_length--;
length--;
}
while (border_length > 0)
{
reserved = tn5250_record_get_byte (This->record);
border_length--;
length--;
}
}
}
while (length > 0)
{
reserved = tn5250_record_get_byte (This->record);
length--;
}
/*
if (!pulldown)
{
*/
window->width = (int) width;
window->height = (int) depth;
window->column = tn5250_display_cursor_x (This->display) + 1;
window->row = tn5250_display_cursor_y (This->display) + 1;
TN5250_LOG (("window position: %d, %d\n", window->column, window->row));
tn5250_dbuffer_add_window (tn5250_display_dbuffer (This->display),
window);
tn5250_terminal_create_window (This->display->terminal, This->display,
window);
/* Forcibly erase the region of the screen that the window covers. I
* thought that the iSeries would always send an Erase To Address command
* after each Create Window command, but that isn't the case. The weird
* part is that sometimes we do get the erase command, and sometimes we
* don't. I have no idea why.
*/
tn5250_display_erase_region (This->display, window->row + 1,
window->column + 2,
window->row + window->height + 1,
window->column + window->column + 2,
window->column + 2,
window->column + window->width + 2);
/*
}
*/
return;
}
/****i* lib5250/tn5250_session_define_scrollbar
* NAME
* tn5250_session_define_scrollbar
* SYNOPSIS
* tn5250_session_define_scrollbar (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_define_scrollbar (Tn5250Session * This, int length)
{
Tn5250Scrollbar *scrollbar;
unsigned char flagbyte1;
unsigned char reserved;
unsigned char totalrowscols;
unsigned char sliderpos;
unsigned char size;
TN5250_LOG (("Entering tn5250_session_define_scrollbar()\n"));
scrollbar = tn5250_scrollbar_new ();
flagbyte1 = tn5250_record_get_byte (This->record);
length--;
if (flagbyte1 & 0x80)
{
TN5250_LOG (("Creating horizontal scrollbar\n"));
scrollbar->direction = 1;
}
else
{
TN5250_LOG (("Creating vertical scrollbar\n"));
scrollbar->direction = 0;
}
reserved = tn5250_record_get_byte (This->record);
length--;
totalrowscols = tn5250_record_get_byte (This->record);
length--;
scrollbar->rowscols = (int) totalrowscols;
TN5250_LOG (("Total rows/columns that can be scrolled: %d\n",
(int) totalrowscols));
sliderpos = tn5250_record_get_byte (This->record);
length--;
scrollbar->sliderpos = (int) sliderpos;
TN5250_LOG (("Slider position: %d\n", (int) sliderpos));
if (length > 0)
{
size = tn5250_record_get_byte (This->record);
length--;
scrollbar->size = (int) size;
TN5250_LOG (("Scrollbar size: %d\n", (int) size));
}
while (length > 0)
{
reserved = tn5250_record_get_byte (This->record);
length--;
}
/*
scrollbar5250.direction = This->display->terminal->scrollbar.direction;
scrollbar5250.rowscols = This->display->terminal->scrollbar.rowscols;
scrollbar5250.sliderpos = This->display->terminal->scrollbar.sliderpos;
scrollbar5250.size = This->display->terminal->scrollbar.size;
*/
tn5250_dbuffer_add_scrollbar (tn5250_display_dbuffer (This->display),
scrollbar);
tn5250_terminal_create_scrollbar (This->display->terminal, This->display,
scrollbar);
return;
}
/****i* lib5250/tn5250_session_remove_gui_window_structured_field
* NAME
* tn5250_session_remove_gui_window_structured_field
* SYNOPSIS
* tn5250_session_remove_gui_window_structured_field (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_remove_gui_window_structured_field (Tn5250Session * This,
int length)
{
Tn5250Window *window;
unsigned char flagbyte1;
unsigned char flagbyte2;
unsigned char reserved;
TN5250_LOG (("Entering tn5250_session_remove_gui_window_structured_field()\n"));
flagbyte1 = tn5250_record_get_byte (This->record);
flagbyte2 = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
if (This->display->display_buffers->window_count > 0)
{
window =
tn5250_window_hit_test (This->display->display_buffers->window_list,
tn5250_display_cursor_x (This->display),
tn5250_display_cursor_y (This->display));
tn5250_terminal_destroy_window (This->display->terminal, This->display,
window);
This->display->display_buffers->window_count--;
if (This->display->display_buffers->window_count == 0)
{
This->display->display_buffers->window_list =
tn5250_window_list_destroy (This->display->display_buffers->
window_list);
}
}
if (This->display->display_buffers->scrollbar_count > 0)
{
tn5250_terminal_destroy_scrollbar (This->display->terminal,
This->display);
This->display->display_buffers->scrollbar_list =
tn5250_scrollbar_list_destroy (This->display->display_buffers->
scrollbar_list);
This->display->display_buffers->scrollbar_count = 0;
}
return;
}
/****i* lib5250/tn5250_session_remove_all_gui_constructs_structured_field
* NAME
* tn5250_session_remove_all_gui_constructs_structured_field
* SYNOPSIS
* tn5250_session_remove_all_gui_constructs_structured_field (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_remove_all_gui_constructs_structured_field (Tn5250Session *
This, int length)
{
unsigned char flagbyte1;
unsigned char flagbyte2;
unsigned char reserved;
TN5250_LOG (("Entering tn5250_session_remove_all_gui_constructs_structured_field()\n"));
flagbyte1 = tn5250_record_get_byte (This->record);
flagbyte2 = tn5250_record_get_byte (This->record);
reserved = tn5250_record_get_byte (This->record);
if (This->display->display_buffers->window_count > 0)
{
Tn5250Window *iter, *next;
if ((iter = This->display->display_buffers->window_list) != NULL)
{
do
{
next = iter->next;
TN5250_LOG (("destroying window id: %d\n", iter->id));
tn5250_terminal_destroy_window (This->display->terminal,
This->display, iter);
iter = next;
}
while (iter != This->display->display_buffers->window_list);
}
This->display->display_buffers->window_list =
tn5250_window_list_destroy (This->display->display_buffers->
window_list);
This->display->display_buffers->window_count = 0;
}
if (This->display->display_buffers->scrollbar_count > 0)
{
tn5250_terminal_destroy_scrollbar (This->display->terminal,
This->display);
This->display->display_buffers->scrollbar_list =
tn5250_scrollbar_list_destroy (This->display->display_buffers->
scrollbar_list);
This->display->display_buffers->scrollbar_count = 0;
}
return;
}
/****i* lib5250/tn5250_session_write_data_structured_field
* NAME
* tn5250_session_write_data_structured_field
* SYNOPSIS
* tn5250_session_write_data_structured_field (This, len)
* INPUTS
* Tn5250Session * This -
* int length -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
static void
tn5250_session_write_data_structured_field (Tn5250Session * This, int length)
{
Tn5250Field *field = tn5250_display_current_field (This->display);
unsigned char *data, *ptr;
int datalength;
unsigned char flagbyte1;
unsigned char c;
TN5250_LOG (("Entering tn5250_session_write_data_structured_field()\n"));
flagbyte1 = tn5250_record_get_byte (This->record);
length--;
if (flagbyte1 & 0x80)
{
TN5250_LOG (("Write data to entry field\n"));
}
data = (unsigned char *) malloc (length * sizeof (unsigned char));
ptr = data;
datalength = length;
TN5250_LOG (("Data: "));
while (length > 0)
{
c = tn5250_record_get_byte (This->record);
memcpy (ptr, &c, sizeof (unsigned char));
ptr = ptr + sizeof (unsigned char);
TN5250_LOG (("%c", tn5250_char_map_to_local (This->display->map, c)));
length--;
}
TN5250_LOG (("\n"));
if ((flagbyte1 & 0x80) && (tn5250_field_is_wordwrap (field)))
{
tn5250_display_wordwrap (This->display, data, datalength,
tn5250_field_length (field), field);
}
free (data);
return;
}
syntax highlighted by Code2HTML, v. 0.9.1