/**MOD+***********************************************************************/
/* Module: wsli3270.c */
/* */
/* Purpose: Simple 3270 emulator */
/* */
/* (C) COPYRIGHT DATA CONNECTION LIMITED 1991 */
/* */
/**MOD-***********************************************************************/
/*****************************************************************************/
/* SLI Sample Program */
/* */
/* (C) Copyright 1990 - 1993 Data Connection Ltd. */
/* */
/* This program is a crude 3270 emulator. It uses the SLI API to access */
/* the LU session. Outbound data from the host is displayed on the screen */
/* unformatted. If the outbound data is an RQD request an automatic */
/* positive response is sent. Inbound data can be entered at the keyboard */
/* */
/* */
/* The program is invoked with two parameters - the name of the LUA LU */
/* to use and a logon string. This is must match an LUA LU in the */
/* configuration file. This LU should be configured for a 327? on the host. */
/* */
/* The program can only access hosts that use simple unformatted logon */
/* requests */
/* */
/* The CSV CONVERT function is used to convert data between ASCII and */
/* EBCDIC. This uses the type G conversion table, so the environment */
/* variable COMTBLG must be set to point to a suitable file. */
/* */
/* Keys that work are: */
/* */
/* Alt-1 to Alt-9 are PF1 to PF9 */
/* backspace */
/* Letters, numbers and symbols */
/* */
/*****************************************************************************/
/*****************************************************************************/
/* SYSTEM INCLUDES */
/*****************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <winlua.h>
#include <wincsv.h>
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
/*****************************************************************************/
/* Program constants */
/*****************************************************************************/
#define DATASIZE 4096 /* Max size of RU */
#define BETB 1 /* Between brackets */
#define SEND 2 /* In bracket and can send */
#define RECV 3 /* In bracket, but cannot send */
#define APPNAME "WSLI3270"
#define SLI_WINDOW_MESSAGE "WinSLI"
#define DISPLAY_BUFFER_SIZE 3200 /* size of circular display buffer */
/*****************************************************************************/
/* State variables */
/* */
/* We can only have one read or write verb outstanding per flow. These */
/* state variables keep track of these verbs and what we need to do with */
/* them. */
/*****************************************************************************/
UINT write_state;
#define NO_WRITE 1
#define WRITE_OUTSTANDING 2 /* waiting for write to complete */
#define WRITE_QUEUED 3 /* have data to write */
UINT read_state;
#define NO_READ 1
#define READ_OUTSTANDING 2 /* read verb outstanding */
#define RSP_QUEUED 3 /* have a response to write */
#define RSP_OUTSTANDING 4 /* waiting for a response to complete */
UINT rpq_state;
#define NO_RPQ 1
#define RPQ_OUTSTANDING 2 /* waiting for an RPQ to complete */
#define RPQ_QUEUED 3 /* have RPQ to send */
/***************************************************************************/
/* Global variables */
/* */
/***************************************************************************/
LUA_VERB_RECORD read_verb; /* SLI recv verb */
LUA_VERB_RECORD close_verb; /* SLI recv verb */
LUA_VERB_RECORD other_verb; /* SLI open or send verb */
LUA_VERB_RECORD rpq_verb; /* SLI_SEND for RPQs */
UCHAR rpq_data[] = {
0x88,
0x00, 0x0C, 0x81, 0x80, 0x80, 0x81, 0x85, 0x86, 0x87, 0x88, 0x95, 0xA6,
0x00, 0x17, 0x81, 0x81, 0x21, 0x00, 0x00, 0x50, 0x00, 0x18, 0x00, 0x00,
0x0A, 0x02, 0xE5, 0x00, 0x02, 0x00, 0x6F, 0x09, 0x10, 0x07, 0x80,
0x00, 0x14, 0x81, 0x85, 0x02, 0x00, 0x09, 0x0E, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x02, 0xB9, 0x01, 0x1D,
0x00, 0x16, 0x81, 0x86, 0x00, 0x08, 0x00, 0xF4, 0xF1, 0x00, 0xF2, 0x00,
0xF3, 0x00, 0xF4, 0x00, 0xF5, 0x00, 0xF6, 0x00, 0xF7, 0x00,
0x00, 0x0D, 0x81, 0x87, 0x04, 0x00, 0xF0, 0xF1, 0x00, 0xF2, 0x00, 0xF4,
0x00,
0x00, 0x07, 0x81, 0x88, 0x00, 0x01, 0x02,
0x00, 0x0C, 0x81, 0x95, 0x00, 0x00, 0x7F, 0xFF, 0x7F, 0xFF, 0x01, 0x01,
0x00, 0x11, 0x81, 0xA6, 0x00, 0x00, 0x0B, 0x01, 0x00, 0x00, 0x50, 0x00,
0x18, 0x00, 0x50, 0x00, 0x18};
#define RPQ_LENGTH (sizeof(rpq_data))
UCHAR display_buffer[DISPLAY_BUFFER_SIZE] = {0};
UINT buffer_end = 0; /* end of data in display buffer */
BOOL wrapped = FALSE; /* has buffer wrapped? */
/*****************************************************************************/
/* Global Variables */
/*****************************************************************************/
HANDLE hInst = 0; /* current instance */
UINT verb_complete = 0; /* verb completion message */
HANDLE hWnd = 0; /* Handle to program window */
BOOL init_done = FALSE; /* SLI_OPEN completed */
unsigned char read_data[DATASIZE]; /* Outbound RU */
#define WRITE_EXTRA 6
unsigned char write_array[DATASIZE + WRITE_EXTRA] =
{0x7d, 0x40, 0x40, 0x11, 0x40, 0x40};
/* Inbound RU */
unsigned char *write_data = write_array + WRITE_EXTRA;
/* Pointer to inbound RU */
UINT data_offset = 0; /* offset into read_data */
UINT write_len = 0; /* length of write data */
struct convert convert_to_asc; /* Outbound convert verb */
struct convert convert_to_ebc; /* Inbound convert verb */
BOOL terminating = FALSE; /* are we already in closedown() ? */
unsigned long sense = 0l; /* sense code */
unsigned char lu_name[9] = " "; /* LU name */
unsigned long sid; /* SLI session ID */
int send_state = BETB; /* LU session send state */
#define LOGON_MAX 25 /* maximum logon string length */
UCHAR logon_data[LOGON_MAX+1] = {0};
UCHAR logon_length = 0;
UCHAR string[64]={0};
void csv_init (void);
void issue_init (void);
void issue_close (void);
void issue_read (void);
void other_done (LUA_VERB_RECORD FAR *verb);
void read_done (LUA_VERB_RECORD FAR *verb);
void issue_rsp (unsigned long sense);
void rsp_done (LUA_VERB_RECORD FAR *verb);
void closedown (void);
BOOL do_write (void);
void wait_verb_complete (LUA_VERB_RECORD FAR *verb);
void set_semaphore (LUA_VERB_RECORD FAR *verb);
BOOL do_keyboard_stuff (UINT, UCHAR);
BOOL check_verb_complete (LUA_VERB_RECORD FAR *verb);
void parse_data (UCHAR FAR *, USHORT);
BOOL issue_rpq (void);
void verb_complete_proc (LUA_VERB_RECORD FAR * verb);
void add_to_display_buffer (UCHAR FAR *);
/*****************************************************************************/
/* Windows function prototypes. */
/*****************************************************************************/
int PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
long FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
/***PROC+*********************************************************************/
/* Name: WinMain */
/* */
/* Purpose: Main Windows function */
/* */
/* Params: IN current instance handle */
/* IN previous instance handle */
/* IN pointer to command line */
/* IN show window type */
/* */
/* Returns: int */
/* */
/**PROC-**********************************************************************/
int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HINSTANCE hInstance; /* current instance */
HINSTANCE hPrevInstance; /* previous instance */
LPSTR lpCmdLine; /* command line */
int nCmdShow; /* show-window type (open/icon) */
{
/***************************************************************************/
/* LOCAL VARIABLES */
/***************************************************************************/
MSG msg; /* message */
int xscreen;
int yscreen;
int delta;
WNDCLASS class;
LUADATA LUAData;
UINT cmdlength; /* length of command line */
UINT lu_name_length; /* length of LU name */
if (!hPrevInstance)
{
class.style = CS_HREDRAW | CS_VREDRAW;
class.lpfnWndProc = (WNDPROC)WndProc;
class.cbClsExtra = 0;
class.cbWndExtra = 0;
class.hInstance = hInstance;
class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
class.hCursor = LoadCursor(NULL, IDC_ARROW);
class.hbrBackground = GetStockObject(WHITE_BRUSH);
class.lpszMenuName = NULL;
class.lpszClassName = APPNAME;
if (!RegisterClass(&class))
{
return (0);
}
}
/***************************************************************************/
/* save current instance handle */
/***************************************************************************/
hInst = hInstance;
/***************************************************************************/
/* Set initial states */
/***************************************************************************/
write_state = NO_WRITE;
read_state = NO_READ;
rpq_state = NO_RPQ;
/***************************************************************************/
/* get details of display */
/***************************************************************************/
xscreen = GetSystemMetrics(SM_CXSCREEN);
yscreen = GetSystemMetrics(SM_CYSCREEN);
/***************************************************************************/
/* invent somewhere to put window */
/***************************************************************************/
delta = xscreen / 100;
/***************************************************************************/
/* create display window */
/***************************************************************************/
hWnd = CreateWindow(APPNAME, /* window class */
"SLI3270", /* window name */
WS_OVERLAPPEDWINDOW, /* window style */
(xscreen/2) + delta, /* x position */
yscreen / 8, /* y position */
(xscreen / 2) - (delta * 2), /* width */
3 * yscreen / 4, /* height */
NULL, /* parent handle */
NULL, /* menu or child ID */
hInstance, /* instance */
NULL); /* additional info */
if (!hWnd)
{
return (0);
}
ShowWindow(hWnd, nCmdShow); /* Shows the window */
UpdateWindow(hWnd); /* Sends WM_PAINT message */
/***************************************************************************/
/* Register message used for async completion */
/***************************************************************************/
verb_complete = RegisterWindowMessage(SLI_WINDOW_MESSAGE);
if (verb_complete == 0)
{
return (0);
}
WinSLIStartup (0x0001, &LUAData);
/***************************************************************************/
/* Issue SLI_OPEN to get the ball rolling. Setup up the LU name */
/***************************************************************************/
cmdlength = _fstrlen(lpCmdLine);
for (lu_name_length = 0; lu_name_length < cmdlength; lu_name_length++)
{
if (lpCmdLine[lu_name_length] == ' ')
{
break;
}
else
{
lu_name[lu_name_length] = lpCmdLine[lu_name_length];
}
}
if (lu_name_length == cmdlength)
{
/*************************************************************************/
/* Need a logon string */
/*************************************************************************/
closedown();
}
else
{
while (lpCmdLine[lu_name_length] == ' ')
{
lu_name_length++;
}
logon_length = _fstrlen(lpCmdLine + lu_name_length);
_fstrncpy ((UCHAR FAR *)logon_data,
lpCmdLine + lu_name_length,
logon_length);
convert_to_ebc.opcode = SV_CONVERT;
convert_to_ebc.direction = SV_ASCII_TO_EBCDIC;
convert_to_ebc.char_set = SV_G;
convert_to_ebc.source = logon_data;
convert_to_ebc.target = logon_data;
convert_to_ebc.len = (unsigned short) logon_length;
ACSSVC_C((LONG)((UCHAR FAR *)&convert_to_ebc));
/*************************************************************************/
/* Set up CSV convert verbs */
/*************************************************************************/
csv_init();
issue_init ();
}
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam; /* save exit parameter for return */
}
/***PROC+*********************************************************************/
/* Name: WndProc */
/* */
/* Purpose: Windows call-back routine */
/* */
/* Params: IN window handle */
/* IN message type */
/* IN additional information 1 */
/* IN additional information 2 */
/* */
/* Returns: long */
/* */
/* Operation:set up window characteristics and register it */
/* return success or failure */
/* */
/**PROC-**********************************************************************/
long FAR PASCAL WndProc(hWnd, message, wParam, lParam)
HWND hWnd; /* window handle */
UINT message; /* type of message */
UINT wParam; /* additional information */
LONG lParam; /* additional information */
{
/***************************************************************************/
/* LOCAL VARIABLES */
/***************************************************************************/
HDC hDC; /* handle to our device context */
TEXTMETRIC tm; /* holds info on the current font */
PAINTSTRUCT ps; /* paint structure */
RECT rc; /* holds info on the size oof our window */
ULONG width; /* width of window in chars */
ULONG height; /* height of window in chars */
UINT buffer_offset; /* offset withing display buffer */
UINT buffer_length; /* length of data in buffer */
UINT out_length; /* lngth of text to output */
UINT out_length2; /* and again */
static int xChar, yChar; /* width & height of the average char */
int position; /* number of lines down the screen */
BOOL whole_data; /* do we have data to send? */
if ((message == verb_complete) &&
(!terminating))
{
/*************************************************************************/
/* Message is SLI verb completed. We are not terminating, so process */
/* the message. */
/*************************************************************************/
verb_complete_proc ((LUA_VERB_RECORD FAR *) lParam);
return(0l);
}
switch (message)
{
case WM_CREATE:
/***********************************************************************/
/* Window creation message. Get some infomation about our font and */
/* save it for later */
/***********************************************************************/
hDC= GetDC(hWnd);
GetTextMetrics (hDC, &tm);
xChar = (int)tm.tmAveCharWidth;
yChar = (int)(tm.tmHeight + tm.tmExternalLeading);
ReleaseDC(hWnd, hDC);
return 0l;
break;
case WM_CHAR:
case WM_SYSCHAR:
/***********************************************************************/
/* Character or Alt+char hit */
/***********************************************************************/
if ((init_done) &&
(!terminating) &&
(write_state == NO_WRITE) &&
(rpq_state == NO_RPQ) &&
(read_state != RSP_QUEUED) &&
(read_state != RSP_OUTSTANDING))
{
/*********************************************************************/
/* Someone pressed a key and we are in a state to deal with it */
/*********************************************************************/
whole_data = do_keyboard_stuff (message, (UCHAR)wParam);
if (whole_data)
{
/*******************************************************************/
/* We have data to send */
/* Attempt to write the data out */
/*******************************************************************/
if (do_write())
{
write_state = WRITE_OUTSTANDING;
}
else
{
write_state = WRITE_QUEUED;
}
}
return(0l);
}
break;
case WM_PAINT:
BeginPaint (hWnd, &ps);
/***********************************************************************/
/* Determine the size of the Window in characters */
/***********************************************************************/
GetClientRect (hWnd, &rc);
height = rc.bottom / yChar;
width = rc.right / xChar;
/***********************************************************************/
/* subtract 2 from height for the status line */
/***********************************************************************/
height -= 2;
/***********************************************************************/
/* Work out how early in the buffer we can start */
/***********************************************************************/
if (!wrapped)
{
/*********************************************************************/
/* buffer is not wrapped */
/*********************************************************************/
buffer_length = buffer_end;
buffer_offset = (buffer_length > (width * height)) ?
buffer_end - (width * height) :
0;
}
else
{
/*********************************************************************/
/* buffer is wrapped */
/*********************************************************************/
buffer_length = DISPLAY_BUFFER_SIZE;
if (buffer_length > width * height)
{
/*******************************************************************/
/* buffer is too big. Work out where best to start in the buffer/ */
/*******************************************************************/
if (buffer_end > width * height)
{
buffer_offset = buffer_end - (width * height);
}
else
{
buffer_offset = DISPLAY_BUFFER_SIZE +
buffer_end -
(width * height);
}
}
else
{
/*******************************************************************/
/* We can fit everything in */
/*******************************************************************/
buffer_offset = buffer_end;
}
}
/***********************************************************************/
/* We've worked out where to start printing from, so start printing */
/***********************************************************************/
position = 0;
out_length = width;
if (buffer_offset > buffer_end)
{
while (buffer_offset < DISPLAY_BUFFER_SIZE)
{
if (DISPLAY_BUFFER_SIZE - buffer_offset < width)
{
out_length = DISPLAY_BUFFER_SIZE - buffer_offset;
}
else
{
out_length = width;
}
TextOut(ps.hdc,
0,
yChar * position,
display_buffer + buffer_offset,
out_length);
buffer_offset += out_length;
position++;
}
buffer_offset = 0;
}
/***********************************************************************/
/* If last line printed was a partial line, print the rest of the line */
/***********************************************************************/
if (out_length < width)
{
out_length2 = out_length;
if (buffer_end < (width - out_length))
{
out_length = buffer_end;
}
else
{
out_length = width - out_length;
}
TextOut(ps.hdc,
xChar * out_length2,
yChar * (position - 1),
display_buffer,
out_length);
buffer_offset += out_length;
}
/***********************************************************************/
/* Now print to the end of the buffer */
/***********************************************************************/
while (buffer_offset < buffer_end)
{
if (buffer_end - buffer_offset < width)
{
out_length = buffer_end - buffer_offset;
}
else
{
out_length = width;
}
TextOut(ps.hdc,
0,
yChar * position,
display_buffer + buffer_offset,
out_length);
buffer_offset += out_length;
position++;
}
/***********************************************************************/
/* Now fill in the status line */
/***********************************************************************/
out_length = wsprintf (string,
"%s",
(UCHAR FAR *)((send_state == BETB) ? "BETB" : "INB"));
TextOut(ps.hdc,
0,
(UINT) (yChar * (height + 2)),
string,
out_length);
/***********************************************************************/
/* Now write the input line. Only in NO_WRITE state, o.w. data is in */
/* EBCDIC */
/***********************************************************************/
if (write_state == NO_WRITE)
{
TextOut(ps.hdc,
0,
(UINT) (yChar * (height+1)),
write_data,
data_offset);
}
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
if (!terminating)
{
/*********************************************************************/
/* Tell the SLI we are going */
/*********************************************************************/
terminating = TRUE;
issue_close();
WinSLICleanup();
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0l;
break;
default:
break;
}
return (DefWindowProc(hWnd, message, wParam, lParam));
}
/**PROC+**********************************************************************/
/* Name: verb_complete_proc */
/* */
/* Purpose: deal with verb completion */
/* */
/* Returns: void */
/* */
/* Params: IN verb - pointer to completed verb */
/* */
/* Operation: Determine which verb has completed and perform the appropriate */
/* action */
/**PROC-**********************************************************************/
VOID verb_complete_proc (verb)
LUA_VERB_RECORD FAR * verb;
{
switch (verb->common.lua_opcode)
{
case LUA_OPCODE_SLI_CLOSE:
break;
case LUA_OPCODE_SLI_OPEN:
/***********************************************************************/
/* Received ACTLU. Save the SID for use on other verbs, flag init */
/* done so that we can write data, and issue first read */
/***********************************************************************/
sid = other_verb.common.lua_sid;
init_done = TRUE;
issue_read();
break;
case LUA_OPCODE_SLI_RECEIVE:
/***********************************************************************/
/* Read completed. Call read dne processor to display data and */
/* determine if a response is required. */
/* If no response is required issue a new read */
/* if a response is required issue the response if we can */
/***********************************************************************/
read_done (verb);
if (terminating == TRUE)
break;
if (read_state == NO_READ)
{
/*********************************************************************/
/* No work to do, issue a new read verb */
/*********************************************************************/
read_state = READ_OUTSTANDING;
issue_read();
}
else if ((read_state == RSP_QUEUED) &&
(write_state != WRITE_OUTSTANDING) &&
(rpq_state != RPQ_OUTSTANDING))
{
/*********************************************************************/
/* We need to send a response to the RU we have just received. The */
/* write flow is free, so send it */
/*********************************************************************/
read_state = RSP_OUTSTANDING;
issue_rsp (sense);
}
if ((rpq_state == RPQ_QUEUED) &&
(write_state != WRITE_OUTSTANDING) &&
(read_state != RSP_OUTSTANDING))
{
/*********************************************************************/
/* We need to send a read partition query response and we can, so do */
/* it. */
/*********************************************************************/
if (issue_rpq())
{
rpq_state = RPQ_OUTSTANDING;
}
}
break;
case LUA_OPCODE_SLI_SEND:
/***********************************************************************/
/* Determine what kind of SLI_SEND completed */
/* either */
/* - writing user data */
/* - writing a RPQ response */
/* - writing a RSP to host data */
/***********************************************************************/
if (write_state == WRITE_OUTSTANDING)
{
write_state = NO_WRITE;
write_data[0] = '\0';
}
else if (rpq_state == RPQ_OUTSTANDING)
{
rpq_state = NO_RPQ;
}
else if (read_state == RSP_OUTSTANDING)
{
read_state = NO_READ;
issue_read();
}
/***********************************************************************/
/* Perform the next action depending on what work their is to do. */
/***********************************************************************/
if (read_state == RSP_QUEUED)
{
/*********************************************************************/
/* We need to issue a RSP to an RU we have received. Do it */
/*********************************************************************/
read_state = RSP_OUTSTANDING;
issue_rsp (sense);
}
else if (rpq_state == RPQ_QUEUED)
{
/*********************************************************************/
/* We need to issue a response to a read partion query. Send it if */
/* the bracket state allows. */
/*********************************************************************/
if (issue_rpq())
{
rpq_state = RPQ_OUTSTANDING;
}
}
else if (write_state == WRITE_QUEUED)
{
/*********************************************************************/
/* We have user data to send to the Host. Send it if the bracket */
/* state allows */
/*********************************************************************/
if (do_write())
{
write_state = WRITE_OUTSTANDING;
}
}
break;
default:
break;
}
} /* verb_complete_proc */
/**PROC+**********************************************************************/
/* Name: csv_init */
/* */
/* Purpose: set up CSV convert verbs */
/* */
/* Returns: void */
/* */
/* Params: none */
/* */
/* Operation: sets uup two CSV convert verbs, one in each direction. Only */
/* the length needs to be set when the verb is called */
/**PROC-**********************************************************************/
void csv_init (void)
{
convert_to_asc.opcode = SV_CONVERT;
convert_to_asc.direction = SV_EBCDIC_TO_ASCII;
convert_to_asc.char_set = SV_G;
convert_to_asc.source = read_data;
convert_to_asc.target = read_data;
convert_to_ebc.opcode = SV_CONVERT;
convert_to_ebc.direction = SV_ASCII_TO_EBCDIC;
convert_to_ebc.char_set = SV_G;
convert_to_ebc.source = write_data;
convert_to_ebc.target = write_data;
} /* csv_init */
/**PROC+**********************************************************************/
/* Name: issue_init */
/* */
/* Purpose: build a verb and send it */
/* */
/* Returns: void */
/* */
/* Params: None */
/* */
/* Operation: Build an OPEN verb and issue it. */
/**PROC-**********************************************************************/
void issue_init(void)
{
memset(&other_verb, 0, sizeof(other_verb));
other_verb.common.lua_verb = LUA_VERB_SLI;
other_verb.common.lua_opcode = LUA_OPCODE_SLI_OPEN;
other_verb.common.lua_verb_length = sizeof(struct LUA_COMMON)+
sizeof(other_verb.specific.open.lua_init_type) +
sizeof(other_verb.specific.open.lua_resv65) +
sizeof(other_verb.specific.open.lua_wait) +
sizeof(other_verb.specific.open.lua_ending_delim);
memcpy(other_verb.common.lua_luname, lu_name, 8);
other_verb.specific.open.lua_init_type = LUA_INIT_TYPE_SEC_LOG;
other_verb.common.lua_data_length = logon_length;
other_verb.common.lua_data_ptr = logon_data;
other_verb.specific.open.lua_open_extension[0].lua_routine_type =
LUA_ROUTINE_TYPE_END;
WinSLI(hWnd, (LUA_VERB_RECORD FAR *) &other_verb);
/***************************************************************************/
/* The sid is valid immediately. Save it now. */
/***************************************************************************/
sid = other_verb.common.lua_sid;
if (!other_verb.common.lua_flag2.async)
{
/*************************************************************************/
/* Verb completed immediately. Post our own completion message */
/*************************************************************************/
PostMessage (hWnd, verb_complete, 0, (LPARAM) (VOID FAR *)&other_verb);
}
} /* issue_init */
/**PROC+**********************************************************************/
/* Name: issue_read */
/* */
/* Purpose: build a read verb and send it */
/* */
/* Returns: void */
/* */
/* Params: none */
/* */
/* Operation: Build a read verb for all flows and issue it */
/**PROC-**********************************************************************/
void issue_read (void)
{
memset(&read_verb, 0, sizeof(read_verb));
memset(read_data, 0, DATASIZE);
read_verb.common.lua_verb = LUA_VERB_SLI;
read_verb.common.lua_verb_length = sizeof(struct LUA_COMMON);
read_verb.common.lua_opcode = LUA_OPCODE_SLI_RECEIVE;
read_verb.common.lua_sid = sid;
read_verb.common.lua_max_length = DATASIZE;
read_verb.common.lua_data_ptr = (char FAR *) read_data;
read_verb.common.lua_flag1.lu_norm = 1;
read_verb.common.lua_flag1.lu_exp = 1;
read_verb.common.lua_flag1.sscp_norm = 1;
read_verb.common.lua_flag1.sscp_exp = 1;
WinSLI(hWnd, (LUA_VERB_RECORD FAR *)&(read_verb));
if (!read_verb.common.lua_flag2.async)
{
/*************************************************************************/
/* Verb completed immediately. Post our own completion message */
/*************************************************************************/
PostMessage (hWnd, verb_complete, 0, (LPARAM) (VOID FAR *)&read_verb);
}
} /* issue_read */
void issue_close (void)
{
memset(&close_verb, 0, sizeof(close_verb));
memset(read_data, 0, DATASIZE);
close_verb.common.lua_verb = LUA_VERB_SLI;
close_verb.common.lua_verb_length = sizeof(struct LUA_COMMON);
close_verb.common.lua_opcode = LUA_OPCODE_SLI_CLOSE;
close_verb.common.lua_sid = sid;
WinSLI(hWnd, (LUA_VERB_RECORD FAR *)&(close_verb));
if (!close_verb.common.lua_flag2.async)
{
/*************************************************************************/
/* Verb completed immediately. Post our own completion message */
/*************************************************************************/
PostMessage (hWnd, verb_complete, 0, (LPARAM) (VOID FAR *)&close_verb);
}
} /* issue_read */
/**PROC+**********************************************************************/
/* Name: read_done */
/* */
/* Purpose: handle completed read verb */
/* */
/* Returns: void */
/* */
/* Params: IN verb - completed read verb */
/* */
/* Operation: If the completed verb contains data, first parse it and then */
/* display it. */
/* If message is a BIND or an UNBIND, set the LU-LU session state */
/* accordingly */
/* Also check for EB, CD and change session state flags */
/**PROC-**********************************************************************/
void read_done(verb)
LUA_VERB_RECORD FAR * verb;
{
BOOL rsp_required = FALSE; /* is a resonse required */
sense = 0l;
if (verb->common.lua_prim_rc == LUA_OK)
{
if (verb->common.lua_message_type == LUA_MESSAGE_TYPE_LU_DATA)
{
if (verb->common.lua_data_length > 0)
{
/*********************************************************************/
/* We now have to parse the data. For the moment we only look for */
/* RPQ requests. */
/*********************************************************************/
parse_data (read_data, (USHORT) (verb->common.lua_data_length));
/*********************************************************************/
/* Display outbound data. */
/*********************************************************************/
convert_to_asc.len = (unsigned short) verb->common.lua_data_length;
ACSSVC_C((LONG)((UCHAR FAR *)&convert_to_asc));
add_to_display_buffer (read_data);
}
/***********************************************************************/
/* Set session state. */
/***********************************************************************/
if (verb->common.lua_rh.ebi)
{
send_state = BETB;
}
else if (verb->common.lua_rh.cdi)
{
send_state = SEND;
}
else
{
send_state = RECV;
}
InvalidateRect (hWnd, NULL, TRUE);
}
/*************************************************************************/
/* Respond to any RQD request. */
/*************************************************************************/
if ((verb->common.lua_message_type != LUA_MESSAGE_TYPE_RSP) &&
(verb->common.lua_rh.ri == 0)) /* definite response */
{
rsp_required = TRUE;
}
}
else if (verb->common.lua_prim_rc != LUA_STATUS)
{
closedown();
}
/***************************************************************************/
/* Continue processing with either another read or a write positive rsp. */
/* (The callback from issuing response will then issue another read) If */
/* we've already gone into closedown, stop here */
/***************************************************************************/
if (!terminating)
{
if (rsp_required)
{
read_state = RSP_QUEUED;
}
else
{
read_state = NO_READ;
}
}
} /* read_done */
/**PROC+**********************************************************************/
/* Name: issue_rsp */
/* */
/* Purpose: issue a response for a request from the host */
/* */
/* Returns: void */
/* */
/* Params: IN sense - sense code for the response */
/* */
/* Operation: Build a response and write it out. Uses the read verb control */
/* block because it has the necessary information. */
/* */
/**PROC-**********************************************************************/
void issue_rsp(sense)
unsigned long sense;
{
read_verb.common.lua_opcode = LUA_OPCODE_SLI_SEND;
read_verb.common.lua_max_length = 0;
read_verb.common.lua_verb_length = sizeof(struct LUA_COMMON) +
sizeof(read_verb.specific.lua_sequence_number);
read_verb.common.lua_rh.rri = 1; /* response */
read_verb.common.lua_post_handle = NULL;
read_verb.common.lua_flag1.lu_norm = 0;
read_verb.common.lua_flag1.lu_exp = 0;
read_verb.common.lua_flag1.sscp_norm = 0;
read_verb.common.lua_flag1.sscp_exp = 0;
read_verb.common.lua_message_type = LUA_MESSAGE_TYPE_RSP;
memset(read_verb.common.lua_resv56, '\0', 7);
#if 0
read_verb.common.lua_rh.eci = 0;
read_verb.common.lua_rh.bci = 0;
read_verb.common.lua_rh.dr1i = 0;
read_verb.common.lua_rh.dr2i = 0;
read_verb.common.lua_rh.qri = 0;
read_verb.common.lua_rh.pi = 0;
read_verb.common.lua_rh.bbi = 0;
read_verb.common.lua_rh.ebi = 0;
read_verb.common.lua_rh.cdi = 0;
read_verb.common.lua_rh.csi = 0;
read_verb.common.lua_rh.edi = 0;
read_verb.common.lua_rh.pdi = 0;
#endif
/***************************************************************************/
/* If we have been given a sense code this must be a negative response */
/***************************************************************************/
if (sense)
{
read_verb.common.lua_data_length = 4;
memcpy(read_data, &sense, 4);
read_verb.common.lua_rh.ri = 1; /* negative rsp */
}
else
{
read_verb.common.lua_data_ptr = NULL;
read_verb.common.lua_data_length = 0;
read_verb.common.lua_rh.ri = 0; /* positive rsp */
}
/***************************************************************************/
/* Send the response back on the flow from which the request came */
/***************************************************************************/
if (read_verb.common.lua_flag2.lu_norm)
{
read_verb.common.lua_flag1.lu_norm = 1;
read_verb.common.lua_flag2.lu_norm = 0;
}
else if (read_verb.common.lua_flag2.lu_exp)
{
read_verb.common.lua_flag1.lu_exp = 1;
read_verb.common.lua_flag2.lu_exp = 0;
}
else if (read_verb.common.lua_flag2.sscp_norm)
{
read_verb.common.lua_flag1.sscp_norm = 1;
read_verb.common.lua_flag2.sscp_norm = 0;
}
else if (read_verb.common.lua_flag2.sscp_exp)
{
read_verb.common.lua_flag1.sscp_exp = 1;
read_verb.common.lua_flag2.sscp_exp = 0;
}
read_verb.common.lua_flag2.async = 0;
/***************************************************************************/
/* Send out the verb */
/***************************************************************************/
WinSLI(hWnd, (LUA_VERB_RECORD FAR *)&read_verb); /* write the response */
if (!read_verb.common.lua_flag2.async)
{
/*************************************************************************/
/* Verb completed immediately. Post our own completion message */
/*************************************************************************/
PostMessage (hWnd, verb_complete, 0, (LPARAM) (VOID FAR *)&read_verb);
}
} /* issue_rsp */
/**PROC+**********************************************************************/
/* Name: rsp_done */
/* */
/* Purpose: handle completion of SLI_SEND, when SLI_SEND has written a */
/* response */
/* */
/* Returns: void */
/* */
/* Params: IN verb - completed verb */
/* */
/* Operation: If verb did not complete OK terminate */
/* */
/**PROC-**********************************************************************/
void rsp_done (verb)
LUA_VERB_RECORD FAR * verb;
{
if (verb->common.lua_prim_rc != LUA_OK) /* failed to write the response */
{ /* so stop here */
closedown();
}
} /* rsp_done */
/**PROC+**********************************************************************/
/* Name: closedown */
/* */
/* Purpose: terminate the application cleanly */
/* */
/* Returns: void */
/* */
/* Params: none */
/* */
/* Operation: Issue a WinSLICleanup() to tell SLI the we are about to go, */
/* and then post a close message so that we do. */
/* */
/**PROC-**********************************************************************/
void closedown (void)
{
if (!terminating) /* check we haven't already got here from */
{ /* another section of the code */
terminating = TRUE; /* then make sure we can't get here again */
issue_close();
WinSLICleanup();
PostMessage (hWnd, WM_CLOSE, 0, 0l);
}
} /* closedown */
/**PROC+**********************************************************************/
/* Name: do_keyboard_stuff */
/* */
/* Purpose: poll keyboard for data */
/* */
/* Returns: BOOL - TRUE => we have data to send */
/* */
/* Params: none */
/* */
/* Operation: Look for Alt-1 to Alt-9 and ascii chars. */
/* */
/**PROC-**********************************************************************/
BOOL do_keyboard_stuff (type, key)
UINT type;
UCHAR key;
{
BOOL data_to_send; /* do we have data to send? */
data_to_send = FALSE;
if (type == WM_SYSCHAR)
{
/*************************************************************************/
/* Alt key pressed */
/*************************************************************************/
if ((key >= '1') &&
(key <= '9'))
{
/***********************************************************************/
/* ALT-1 to ALT-9 0xF1 is the AID code for PF1. Follow this with the */
/* cursor address */
/***********************************************************************/
*write_data = 0xF1 + key - '1';
*(write_data + 1) = 0x40;
*(write_data + 2) = 0x40;
write_len = 3;
data_to_send = TRUE;
}
}
else
{
/*************************************************************************/
/* Ordinary ASCII char */
/* Key should be real data. Add it to the string */
/*************************************************************************/
if (key == 13)
{
/***********************************************************************/
/* If user pressed return key then send the data. Reset data_offset */
/* for next data. */
/***********************************************************************/
write_data[data_offset++] = '\0';
data_to_send = TRUE;
data_offset = 0;
/***********************************************************************/
/* Convert data to EBCDIC */
/***********************************************************************/
convert_to_ebc.len = (unsigned short) (strlen(write_data) );
if (convert_to_ebc.len > 0)
{
ACSSVC_C((LONG)((UCHAR FAR *)&convert_to_ebc));
}
write_len = convert_to_ebc.len;
/***********************************************************************/
/* Allow for ENTER AID if necessary */
/***********************************************************************/
write_data -= WRITE_EXTRA;
write_len += WRITE_EXTRA;
}
else if (key == 8)
{
/***********************************************************************/
/* Backspace. Delete last char */
/***********************************************************************/
if (data_offset > 0)
{
data_offset--;
}
}
else if (key != 0)
{
/***********************************************************************/
/* ASCII char. Add it to the data buffer */
/***********************************************************************/
write_data[data_offset++] = (UCHAR) key;
}
/*************************************************************************/
/* Invalidate our window so that the new data is displayed */
/*************************************************************************/
InvalidateRect (hWnd, NULL, TRUE);
}
return(data_to_send);
} /* do_keyboard_stuff */
/**PROC+**********************************************************************/
/* Name: do_write */
/* */
/* Purpose: issue a write verb */
/* */
/* Returns: BOOL - TRUE => data sent OK */
/* */
/* Params: none */
/* */
/* Operation: convert data to EBCDIC and send it on the right session */
/* */
/**PROC-**********************************************************************/
BOOL do_write (void)
{
BOOL ok;
ok = TRUE;
/***************************************************************************/
/* Set up the vcb */
/***************************************************************************/
memset(&other_verb, 0, sizeof(other_verb));
other_verb.common.lua_verb = LUA_VERB_SLI;
other_verb.common.lua_verb_length = sizeof(struct LUA_COMMON) +
sizeof(other_verb.specific.lua_sequence_number);
other_verb.common.lua_opcode = LUA_OPCODE_SLI_SEND;
other_verb.common.lua_message_type = LUA_MESSAGE_TYPE_LU_DATA;
other_verb.common.lua_sid = sid;
other_verb.common.lua_data_length = write_len;
other_verb.common.lua_data_ptr = (char far *) write_data;
other_verb.common.lua_rh.dr1i = 1;
/***************************************************************************/
/* On the LU session we must add the <enter> key prefix. All inbound */
/* requests flow RQE with the BBI and CDI flags set depending on the */
/* current session state. */
/***************************************************************************/
other_verb.common.lua_rh.ri = 1;
if (send_state == BETB)
{
/*************************************************************************/
/* Between bracket, so open bracket and give direction. Note that we */
/* can do this since we will always be contention winner. */
/*************************************************************************/
other_verb.common.lua_rh.bbi = 1;
other_verb.common.lua_rh.cdi = 1;
send_state = RECV;
}
else if (send_state = SEND)
{
/*************************************************************************/
/* In bracket and we have direction, so simply give direction. */
/*************************************************************************/
other_verb.common.lua_rh.cdi = 1;
send_state = RECV;
}
else
{
/*************************************************************************/
/* In bracket and we do not have direction, so do not send. */
/*************************************************************************/
ok = FALSE;
}
if (ok)
{
/*************************************************************************/
/* Issue write verb */
/*************************************************************************/
WinSLI(hWnd, (LUA_VERB_RECORD FAR *) &other_verb);
if (!other_verb.common.lua_flag2.async)
{
/***********************************************************************/
/* Verb completed immediately. Post our own completion message */
/***********************************************************************/
PostMessage (hWnd, verb_complete, 0, (LPARAM) (VOID FAR *)&other_verb);
}
/*************************************************************************/
/* Reset write_data to point to correct point in write_array */
/*************************************************************************/
write_data = write_array + WRITE_EXTRA;
}
return(ok);
} /* do_write () */
/**PROC+**********************************************************************/
/* Name: parse_data */
/* */
/* Purpose: parse data from the host */
/* */
/* Returns: void */
/* */
/* Params: IN data - pointer to data */
/* */
/* Operation: Looks through data for read partition query from host. Could */
/* be expanded to format data from host */
/* */
/**PROC-**********************************************************************/
void parse_data (data, length)
UCHAR FAR * data;
USHORT length;
{
USHORT field_length;
switch (*(data++))
{
case 0xF3: /* write structured field */
/***********************************************************************/
/* Next byte is the WCC - ignore */
/***********************************************************************/
data++;
length -= 2;
while (length > 0)
{
/*********************************************************************/
/* We're just looking for a Read Partion query */
/*********************************************************************/
field_length = (((USHORT) *data) << 8) || ((USHORT) *(data + 1));
if ((*(data+2) == 0x01) && /* Read partition */
(*(data+3) == 0xFF) && /* Query */
(*(data+4) == 0x02)) /* not a list */
{
/*******************************************************************/
/* Build an RPQ and flag it to be sent */
/*******************************************************************/
rpq_state = RPQ_QUEUED;
}
data += field_length;
length -= field_length;
}
break;
default:
break;
}
} /* parse_data */
/**PROC+**********************************************************************/
/* Name: issue_rpq */
/* */
/* Purpose: issue a response to a Read partition query */
/* */
/* Returns: BOOL - TRUE => sent OK */
/* */
/* Params: none */
/* */
/* Operation: Builds and sends an RPQ reesponse */
/* */
/**PROC-**********************************************************************/
BOOL issue_rpq (void)
{
BOOL issue_rpq;
issue_rpq = TRUE;
/***************************************************************************/
/* Set up the vcb */
/***************************************************************************/
memset(&rpq_verb, 0, sizeof(rpq_verb));
rpq_verb.common.lua_verb = LUA_VERB_SLI;
rpq_verb.common.lua_verb_length = sizeof(struct LUA_COMMON) +
sizeof(rpq_verb.specific.lua_sequence_number);
rpq_verb.common.lua_opcode = LUA_OPCODE_SLI_SEND;
rpq_verb.common.lua_sid = sid;
rpq_verb.common.lua_message_type = LUA_MESSAGE_TYPE_LU_DATA;
rpq_verb.common.lua_data_length = RPQ_LENGTH;
rpq_verb.common.lua_data_ptr = (char far *) rpq_data;
rpq_verb.common.lua_rh.dr1i = 1;
/***************************************************************************/
/* All inbound requests flow RQD with the BBI and CDI flags set depending */
/* on the current session state. */
/***************************************************************************/
rpq_verb.common.lua_rh.ri = 1;
if (send_state == BETB)
{
/*************************************************************************/
/* Between bracket, so open bracket and give direction. Note that we */
/* can do this since we will always be contention winner. */
/*************************************************************************/
rpq_verb.common.lua_rh.bbi = 1;
rpq_verb.common.lua_rh.cdi = 1;
send_state = RECV;
}
else if (send_state = SEND)
{
/*************************************************************************/
/* In bracket and we have direction, so simply give direction. */
/*************************************************************************/
rpq_verb.common.lua_rh.cdi = 1;
send_state = RECV;
}
else
{
/*************************************************************************/
/* In bracket and we do not have direction, so do not send. */
/*************************************************************************/
issue_rpq = FALSE;
}
if (issue_rpq)
{
WinSLI(hWnd, (LUA_VERB_RECORD FAR *) &rpq_verb);
if (!rpq_verb.common.lua_flag2.async)
{
/***********************************************************************/
/* Verb completed immediately. Post our own completion message */
/***********************************************************************/
PostMessage (hWnd, verb_complete, 0, (LPARAM) (VOID FAR *)&rpq_verb);
}
}
return(issue_rpq);
} /* issue_rpq */
/**PROC+**********************************************************************/
/* Name: add_to_display_buffer */
/* */
/* Purpose: add data to the display buffer */
/* */
/* Returns: void */
/* */
/* Params: IN data - data to be displayed */
/* */
/* Operation: Add the zero terminated data string to the circular display */
/* buffer. Cope with wrapping */
/* */
/**PROC-**********************************************************************/
void add_to_display_buffer (data)
UCHAR FAR * data;
{
UINT data_length; /* length of new data to display */
BOOL need_to_wrap; /* do we need to wrap to the start of the buffer */
UINT copy_length; /* length of data to copy */
data_length = _fstrlen (data);
/***************************************************************************/
/* Work out whether the data will go over the end of the dispaly buffer. */
/* If it will, wrap it back over the start of the buffer. */
/***************************************************************************/
need_to_wrap = (buffer_end + data_length > DISPLAY_BUFFER_SIZE);
if (need_to_wrap)
{
copy_length = DISPLAY_BUFFER_SIZE - buffer_end;
wrapped = TRUE;
}
else
{
copy_length = data_length;
}
/***************************************************************************/
/* Copy as much data as will fit into the buffer */
/***************************************************************************/
_fmemcpy ((UCHAR FAR *) (display_buffer + buffer_end),
data,
copy_length);
/***************************************************************************/
/* If there is more data to copy, copy it to the start of the buffer */
/* Set up the new end point. */
/***************************************************************************/
if (need_to_wrap)
{
_fmemcpy ((UCHAR FAR *)display_buffer,
data + copy_length,
data_length - copy_length);
buffer_end = data_length - copy_length;
}
else
{
buffer_end += data_length;
}
/***************************************************************************/
/* Cause the window to be re-painted */
/***************************************************************************/
InvalidateRect (hWnd, NULL, TRUE);
} /* add_to_display_buffer */