# HG changeset patch # User Carl Byington # Date 1400785870 25200 # Node ID e8d2a24e85c6e98675af30ad3bb9fd9f55a6b002 # Parent a01665cb683dc01c25ec24fa3bcf2061944617e0 adding tn5250 files diff -r a01665cb683d -r e8d2a24e85c6 TODO --- a/TODO Thu May 22 12:09:58 2014 -0700 +++ b/TODO Thu May 22 12:11:10 2014 -0700 @@ -41,6 +41,6 @@ merge tn5250j -svn checkout svn://svn.code.sf.net/p/tn5250j/code/trunk tn5250j +svn checkout svn://svn.code.sf.net/p/tn5250j/code/branches/new-tabs-jse1.6 tn5250j after 5250 merge, go up to version 1.8.0-1 diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/TN5250jConstants.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/TN5250jConstants.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,530 @@ +/* + * @(#)TN5250jConstants.java + * Copyright: Copyright (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ + +package org.tn5250j; + +public interface TN5250jConstants { + + // Version information + public static final String tn5250jRelease = "0"; + public static final String tn5250jVersion = ".7"; + public static final String tn5250jSubVer= ".3"; + + public static final String VERSION_INFO = tn5250jRelease + tn5250jVersion + tn5250jSubVer; + + // STATE + static final int STATE_DISCONNECTED = 0; + static final int STATE_CONNECTED = 1; + static final int STATE_REMOVE = 2; + + // SESSION Level key value pairs + public static final String SESSION_HOST = "SESSION_HOST"; + public static final String SESSION_HOST_PORT ="SESSION_HOST_PORT"; + public static final String SESSION_CONFIG_RESOURCE = "SESSION_CONFIG_RESOURCE"; + public static final String SESSION_TYPE = "SESSION_HOST_TYPE"; + public static final String SESSION_TN_ENHANCED = "SESSION_TN_ENHANCED"; + public static final String SESSION_SCREEN_SIZE = "SESSION_SCREEN_SIZE"; + public static final String SESSION_CODE_PAGE = "SESSION_CODE_PAGE"; + public static final String SESSION_PROXY_HOST = "SESSION_PROXY_HOST"; + public static final String SESSION_PROXY_PORT = "SESSION_PROXY_PORT"; + public static final String SESSION_USE_GUI = "SESSION_USE_GUI"; + public static final String SESSION_DEVICE_NAME = "SESSION_DEVICE_NAME"; + public static final String SESSION_NAMES_REFS = "SESSION_NAMES_REFS"; + public static final String SESSION_LOCALE = "SESSION_LOCALE"; + public static final String SESSION_CONFIG_FILE = "SESSION_CONFIG_FILE"; + public static final String SESSION_TERM_NAME_SYSTEM = "SESSION_TERM_NAME_SYSTEM"; + public static final String SESSION_TERM_NAME = "SESSION_TERM_NAME"; + public static final String SESSION_IS_APPLET = "SESSION_IS_APPLET"; + public static final String SESSION_HEART_BEAT = "SESSION_KEEP_ALIVE_ENABLED"; + +// public static final String GUI_MDI_TYPE = "GUI_MDI_TYPE"; + public static final String GUI_FRAME_WIDTH = "GUI_FRAME_WIDTH"; + public static final String GUI_FRAME_HEIGHT = "GUI_FRAME_HEIGHT"; + public static final String GUI_NO_TAB = "GUI_NO_TAB"; + public static final String NO_CHECK_RUNNING = "NO_CHECK_RUNNING"; + public static final String START_MONITOR_THREAD = "START_MONITOR_THREAD"; + +// public static final String SSL_TYPE = "TN5250J_SSL_TYPE"; + public static final String SSL_TYPE = "-sslType"; + public static final String SSL_TYPE_NONE = "NONE"; + public static final String SSL_TYPE_SSLv2 = "SSLv2"; + public static final String SSL_TYPE_SSLv3 = "SSLv3"; + public static final String SSL_TYPE_TLS = "TLS"; + + public static final String[] SSL_TYPES = {SSL_TYPE_NONE, + SSL_TYPE_SSLv2, + SSL_TYPE_SSLv3, + SSL_TYPE_TLS}; + + // Session JUMP Directions + static final int JUMP_PREVIOUS = 0; + static final int JUMP_NEXT = 1; + +// // OS_OHIO_SESSION_TYPE type of sessions +// public static final String OS_OHIO_SESSION_TYPE_5250_STR = "2"; + + // SCREEN_SIZE Size of screen string + public static final String SCREEN_SIZE_24X80_STR = "0"; + public static final String SCREEN_SIZE_27X132_STR = "1"; + + // SCREEN_SIZE Size of screen int + public static final int SCREEN_SIZE_24X80 = 0; + public static final int SCREEN_SIZE_27X132 = 1; + + public static final int NUM_PARMS = 20; + + // mnemonic value constants + public static final int BACK_SPACE = 1001; + public static final int BACK_TAB = 1002; + public static final int UP = 1003; + public static final int DOWN = 1004; + public static final int LEFT = 1005; + public static final int RIGHT = 1006; + public static final int DELETE = 1007; + public static final int TAB = 1008; + public static final int EOF = 1009; + public static final int ERASE_EOF = 1010; + public static final int ERASE_FIELD = 1011; + public static final int INSERT = 1012; + public static final int HOME = 1013; + public static final int KEYPAD_0 = 1014; + public static final int KEYPAD_1 = 1015; + public static final int KEYPAD_2 = 1016; + public static final int KEYPAD_3 = 1017; + public static final int KEYPAD_4 = 1018; + public static final int KEYPAD_5 = 1019; + public static final int KEYPAD_6 = 1020; + public static final int KEYPAD_7 = 1021; + public static final int KEYPAD_8 = 1022; + public static final int KEYPAD_9 = 1023; + public static final int KEYPAD_PERIOD = 1024; + public static final int KEYPAD_COMMA = 1025; + public static final int KEYPAD_MINUS = 1026; + public static final int FIELD_EXIT = 1027; + public static final int FIELD_PLUS = 1028; + public static final int FIELD_MINUS = 1029; + public static final int BOF = 1030; + public static final int SYSREQ = 1031; + public static final int RESET = 1032; + public static final int NEXTWORD = 1033; + public static final int PREVWORD = 1034; + public static final int COPY = 1035; + public static final int PASTE = 1036; + public static final int ATTN = 1037; + public static final int MARK_UP = 1038; + public static final int MARK_DOWN = 1039; + public static final int MARK_LEFT = 1040; + public static final int MARK_RIGHT = 1041; + public static final int DUP_FIELD = 1042; + public static final int NEW_LINE = 1043; + public static final int JUMP_NEXT_SESS = 5000; + public static final int JUMP_PREV_SESS = 5001; + public static final int OPEN_NEW = 5002; + public static final int TOGGLE_CONNECTION = 5003; + public static final int HOTSPOTS = 5004; + public static final int GUI = 5005; + public static final int DSP_MSGS = 5006; + public static final int DSP_ATTRIBUTES = 5007; + public static final int PRINT_SCREEN = 5008; + public static final int CURSOR = 5009; + public static final int DEBUG = 5010; + public static final int CLOSE = 5011; + public static final int TRANSFER = 5012; + public static final int E_MAIL = 5013; + public static final int RUN_SCRIPT = 5014; + public static final int SPOOL_FILE = 5015; + public static final int QUICK_MAIL = 5016; + public static final int OPEN_SAME = 5017; + public static final int FAST_CURSOR_DOWN = 5018; + public static final int FAST_CURSOR_UP = 5019; + public static final int FAST_CURSOR_RIGHT = 5020; + public static final int FAST_CURSOR_LEFT = 5021; + + // PF Keys + public static final int PF1 = 0x31; + public static final int PF2 = 0x32; + public static final int PF3 = 0x33; + public static final int PF4 = 0x34; + public static final int PF5 = 0x35; + public static final int PF6 = 0x36; + public static final int PF7 = 0x37; + public static final int PF8 = 0x38; + public static final int PF9 = 0x39; + public static final int PF10 = 0x3A; + public static final int PF11 = 0x3B; + public static final int PF12 = 0x3C; + public static final int PF13 = 0xB1; + public static final int PF14 = 0xB2; + public static final int PF15 = 0xB3; + public static final int PF16 = 0xB4; + public static final int PF17 = 0xB5; + public static final int PF18 = 0xB6; + public static final int PF19 = 0xB7; + public static final int PF20 = 0xB8; + public static final int PF21 = 0xB9; + public static final int PF22 = 0xBA; + public static final int PF23 = 0xBB; + public static final int PF24 = 0xBC; + + public static final String mnemonicData[] = { + "[backspace]", "[backtab]", "[up]", "[down]", "[left]", + "[right]", "[delete]", "[tab]", "[eof]", "[eraseeof]", + "[erasefld]", "[insert]", "[home]", "[keypad0]", "[keypad1]", + "[keypad2]", "[keypad3]", "[keypad4]", "[keypad5]", "[keypad6]", + "[keypad7]", "[keypad8]", "[keypad9]", "[keypad.]", "[keypad,]", + "[keypad-]", "[fldext]", "[field+]", "[field-]", "[bof]", + "[enter]","[pf1]","[pf2]","[pf3]","[pf4]", + "[pf5]","[pf6]","[pf7]","[pf8]","[pf9]", + "[pf10]","[pf11]","[pf12]","[pf13]","[pf14]", + "[pf15]","[pf16]","[pf17]","[pf18]","[pf19]", + "[pf20]","[pf21]","[pf22]","[pf23]","[pf24]", + "[clear]", "[help]", "[pgup]", "[pgdown]", "[rollleft]", + "[rollright]", "[hostprint]", "[pa1]", "[pa2]", "[pa3]", + "[sysreq]","[reset]","[nextword]", "[prevword]", "[copy]", + "[paste]","[attn]","[markup]", "[markdown]", "[markleft]", + "[markright]","[dupfield]","[newline]","[jumpnext]","[jumpprev]", + "[opennew]","[togcon]","[hotspots]","[gui]","[dspmsgs]", + "[dspattr]","[print]","[cursor]","[debug]","[close]", + "[transfer]","[e-mail]","[runscript]","[spoolfile]","[quick-mail]", + "[open-same]","[fastcursordown]","[fastcursorup]","[fastcursorright]","[fastcursorleft]" + }; + + public static final int mnemonicValue[] = { + 1001, 1002, 1003, 1004, 1005, + 1006, 1007, 1008, 1009, 1010, + 1011, 1012, 1013, 1014, 1015, + 1016, 1017, 1018, 1019, 1020, + 1021, 1022, 1023, 1024, 1025, + 1026, 1027, 1028, 1029, 1030, + 0xF1, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3A, 0x3B, 0x3C, 0xB1, 0xB2, + 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, + 0xBD, 0xF3, 0xF4, 0xF5, 0xD9, + 0xDA, 0xF6, 0x6C, 0x6E, 0x6B, + 1031, 1032, 1033, 1034, 1035, + 1036, 1037, 1038, 1039, 1040, + 1041, 1042, 1043, 5000, 5001, + 5002, 5003, 5004, 5005, 5006, + 5007, 5008, 5009, 5010, 5011, + 5012, 5013, 5014, 5015, 5016, + 5017, 5018, 5019, 5020, 5021 + }; + + public static final String MNEMONIC_CLEAR = "[clear]"; + public static final String MNEMONIC_ENTER = "[enter]"; + public static final String MNEMONIC_HELP = "[help]"; + public static final String MNEMONIC_PAGE_DOWN = "[pgdown]"; + public static final String MNEMONIC_PAGE_UP = "[pgup]"; + public static final String MNEMONIC_PRINT = "[hostprint]"; + public static final String MNEMONIC_PF1 = "[pf1]"; + public static final String MNEMONIC_PF2 = "[pf2]"; + public static final String MNEMONIC_PF3 = "[pf3]"; + public static final String MNEMONIC_PF4 = "[pf4]"; + public static final String MNEMONIC_PF5 = "[pf5]"; + public static final String MNEMONIC_PF6 = "[pf6]"; + public static final String MNEMONIC_PF7 = "[pf7]"; + public static final String MNEMONIC_PF8 = "[pf8]"; + public static final String MNEMONIC_PF9 = "[pf9]"; + public static final String MNEMONIC_PF10 = "[pf10]"; + public static final String MNEMONIC_PF11 = "[pf11]"; + public static final String MNEMONIC_PF12 = "[pf12]"; + public static final String MNEMONIC_PF13 = "[pf13]"; + public static final String MNEMONIC_PF14 = "[pf14]"; + public static final String MNEMONIC_PF15 = "[pf15]"; + public static final String MNEMONIC_PF16 = "[pf16]"; + public static final String MNEMONIC_PF17 = "[pf17]"; + public static final String MNEMONIC_PF18 = "[pf18]"; + public static final String MNEMONIC_PF19 = "[pf19]"; + public static final String MNEMONIC_PF20 = "[pf20]"; + public static final String MNEMONIC_PF21 = "[pf21]"; + public static final String MNEMONIC_PF22 = "[pf22]"; + public static final String MNEMONIC_PF23 = "[pf23]"; + public static final String MNEMONIC_PF24 = "[pf24]"; + public static final String MNEMONIC_BACK_SPACE = "[backspace]"; + public static final String MNEMONIC_BACK_TAB = "[backtab]"; + public static final String MNEMONIC_UP = "[up]"; + public static final String MNEMONIC_DOWN = "[down]"; + public static final String MNEMONIC_LEFT = "[left]"; + public static final String MNEMONIC_RIGHT = "[right]"; + public static final String MNEMONIC_DELETE = "[delete]"; + public static final String MNEMONIC_TAB = "[tab]"; + public static final String MNEMONIC_END_OF_FIELD = "[eof]"; + public static final String MNEMONIC_ERASE_EOF = "[eraseeof]"; + public static final String MNEMONIC_ERASE_FIELD = "[erasefld]"; + public static final String MNEMONIC_INSERT = "[insert]"; + public static final String MNEMONIC_HOME = "[home]"; + public static final String MNEMONIC_KEYPAD0 = "[keypad0]"; + public static final String MNEMONIC_KEYPAD1 = "[keypad1]"; + public static final String MNEMONIC_KEYPAD2 = "[keypad2]"; + public static final String MNEMONIC_KEYPAD3 = "[keypad3]"; + public static final String MNEMONIC_KEYPAD4 = "[keypad4]"; + public static final String MNEMONIC_KEYPAD5 = "[keypad5]"; + public static final String MNEMONIC_KEYPAD6 = "[keypad6]"; + public static final String MNEMONIC_KEYPAD7 = "[keypad7]"; + public static final String MNEMONIC_KEYPAD8 = "[keypad8]"; + public static final String MNEMONIC_KEYPAD9 = "[keypad9]"; + public static final String MNEMONIC_KEYPAD_PERIOD = "[keypad.]"; + public static final String MNEMONIC_KEYPAD_COMMA = "[keypad,]"; + public static final String MNEMONIC_KEYPAD_MINUS = "[keypad-]"; + public static final String MNEMONIC_FIELD_EXIT = "[fldext]"; + public static final String MNEMONIC_FIELD_PLUS = "[field+]"; + public static final String MNEMONIC_FIELD_MINUS = "[field-]"; + public static final String MNEMONIC_BEGIN_OF_FIELD = "[bof]"; + public static final String MNEMONIC_PA1 = "[pa1]"; + public static final String MNEMONIC_PA2 = "[pa2]"; + public static final String MNEMONIC_PA3 = "[pa3]"; + public static final String MNEMONIC_SYSREQ = "[sysreq]"; + public static final String MNEMONIC_RESET = "[reset]"; + public static final String MNEMONIC_NEXTWORD = "[nextword]"; + public static final String MNEMONIC_PREVWORD = "[prevword]"; + public static final String MNEMONIC_ATTN = "[attn]"; + public static final String MNEMONIC_MARK_LEFT = "[markleft]"; + public static final String MNEMONIC_MARK_RIGHT = "[markright]"; + public static final String MNEMONIC_MARK_UP = "[markup]"; + public static final String MNEMONIC_MARK_DOWN = "[markdown]"; + public static final String MNEMONIC_DUP_FIELD = "[dupfield]"; + public static final String MNEMONIC_NEW_LINE = "[newline]"; + public static final String MNEMONIC_JUMP_NEXT = "[jumpnext]"; + public static final String MNEMONIC_JUMP_PREV = "[jumpprev]"; + public static final String MNEMONIC_OPEN_NEW = "[opennew]"; + public static final String MNEMONIC_TOGGLE_CONNECTION = "[togcon]"; + public static final String MNEMONIC_HOTSPOTS = "[hotspots]"; + public static final String MNEMONIC_GUI = "[gui]"; + public static final String MNEMONIC_DISP_MESSAGES = "[dspmsgs]"; + public static final String MNEMONIC_DISP_ATTRIBUTES = "[dspattr]"; + public static final String MNEMONIC_PRINT_SCREEN = "[print]"; + public static final String MNEMONIC_CURSOR = "[cursor]"; + public static final String MNEMONIC_DEBUG = "[debug]"; + public static final String MNEMONIC_CLOSE = "[close]"; + public static final String MNEMONIC_E_MAIL = "[e-mail]"; + public static final String MNEMONIC_COPY = "[copy]"; + public static final String MNEMONIC_PASTE = "[paste]"; + public static final String MNEMONIC_FILE_TRANSFER = "[transfer]"; + public static final String MNEMONIC_RUN_SCRIPT = "[runscript]"; + public static final String MNEMONIC_SPOOL_FILE = "[spoolfile]"; + public static final String MNEMONIC_QUICK_MAIL = "[quick-mail]"; + public static final String MNEMONIC_OPEN_SAME = "[open-same]"; + public static final String MNEMONIC_FAST_CURSOR_DOWN = "[fastcursordown]"; + public static final String MNEMONIC_FAST_CURSOR_UP = "[fastcursorup]"; + public static final String MNEMONIC_FAST_CURSOR_RIGHT = "[fastcursorright]"; + public static final String MNEMONIC_FAST_CURSOR_LEFT = "[fastcursorleft]"; + + // AID-Generating Keys + public static final int AID_CLEAR = 0xBD; + public static final int AID_ENTER = 0xF1; + public static final int AID_HELP = 0xF3; + public static final int AID_ROLL_UP = 0xF4; + public static final int AID_ROLL_DOWN = 0xF5; + public static final int AID_ROLL_LEFT = 0xD9; + public static final int AID_ROLL_RIGHT = 0xDA; + public static final int AID_PRINT = 0xF6; + public static final int AID_PF1 = 0x31; + public static final int AID_PF2 = 0x32; + public static final int AID_PF3 = 0x33; + public static final int AID_PF4 = 0x34; + public static final int AID_PF5 = 0x35; + public static final int AID_PF6 = 0x36; + public static final int AID_PF7 = 0x37; + public static final int AID_PF8 = 0x38; + public static final int AID_PF9 = 0x39; + public static final int AID_PF10 = 0x3A; + public static final int AID_PF11 = 0x3B; + public static final int AID_PF12 = 0x3C; + public static final int AID_PF13 = 0xB1; + public static final int AID_PF14 = 0xB2; + public static final int AID_PF15 = 0xB3; + public static final int AID_PF16 = 0xB4; + public static final int AID_PF17 = 0xB5; + public static final int AID_PF18 = 0xB6; + public static final int AID_PF19 = 0xB7; + public static final int AID_PF20 = 0xB8; + public static final int AID_PF21 = 0xB9; + public static final int AID_PF22 = 0xBA; + public static final int AID_PF23 = 0xBB; + public static final int AID_PF24 = 0xBC; + + // negative response categories + public static final int NR_REQUEST_REJECT = 0x08; + public static final int NR_REQUEST_ERROR = 0x10; + public static final int NR_STATE_ERROR = 0x20; + public static final int NR_USAGE_ERROR = 0x40; + public static final int NR_PATH_ERROR = 0x80; + + // commands + public static final byte CMD_WRITE_TO_DISPLAY = 0x11; // 17 + public static final byte CMD_CLEAR_UNIT = 0x40; // 64 + public static final byte CMD_CLEAR_UNIT_ALTERNATE = 0x20; // 32 + public static final byte CMD_CLEAR_FORMAT_TABLE = 0x50; // 80 + public static final byte CMD_READ_INPUT_FIELDS = 0x42; // 66 + public static final byte CMD_READ_MDT_FIELDS = 0x52; // 82 + public static final byte CMD_READ_MDT_IMMEDIATE_ALT = (byte)0x83; // 131 +// public static final byte CMD_READ_MDT_FIELDS_ALT = (byte)0x82; // 130 +// public static final byte CMD_READ_IMMEDIATE = 0x72; // 114 + public static final byte CMD_READ_SCREEN_IMMEDIATE = 0x62; // 98 + public static final byte CMD_WRITE_STRUCTURED_FIELD = (byte)243; // (byte)0xF3 -13 + public static final byte CMD_SAVE_SCREEN = 0x02; // 02 + public static final byte CMD_RESTORE_SCREEN = 0x12; // 18 + public static final byte CMD_WRITE_ERROR_CODE = 0x21; // 33 + public static final byte CMD_WRITE_ERROR_CODE_TO_WINDOW = 0x22; // 34 + public static final byte CMD_ROLL = 0x23; // 35 + public static final byte CMD_READ_SCREEN_TO_PRINT = (byte)0x66; // 102 + + // PLANES + public static final int PLANE_TEXT = 1; + public static final int PLANE_COLOR = 2; + public static final int PLANE_FIELD = 3; + public static final int PLANE_EXTENDED = 4; + public static final int PLANE_EXTENDED_GRAPHIC = 5; + public static final int PLANE_EXTENDED_FIELD = 6; + public static final int PLANE_ATTR = 7; + public static final int PLANE_IS_ATTR_PLACE = 8; + + // COLOR_BG + public static final char COLOR_BG_BLACK = 0; + public static final char COLOR_BG_BLUE = 1; + public static final char COLOR_BG_GREEN = 2; + public static final char COLOR_BG_CYAN = 3; + public static final char COLOR_BG_RED = 4; + public static final char COLOR_BG_MAGENTA = 5; + public static final char COLOR_BG_YELLOW = 6; + public static final char COLOR_BG_WHITE = 7; + + // COLOR_FG + public static final char COLOR_FG_BLACK = 0; + public static final char COLOR_FG_BLUE = 1; + public static final char COLOR_FG_GREEN = 2; + public static final char COLOR_FG_CYAN = 3; + public static final char COLOR_FG_RED = 4; + public static final char COLOR_FG_MAGENTA = 5; + public static final char COLOR_FG_YELLOW = 6; + public static final char COLOR_FG_WHITE = 7; + public static final char COLOR_FG_BROWN = 0xE; + public static final char COLOR_FG_GRAY = 8; + public static final char COLOR_FG_LIGHT_BLUE = 9; + public static final char COLOR_FG_LIGHT_GREEN = 0xA; + public static final char COLOR_FG_LIGHT_CYAN = 0xB; + public static final char COLOR_FG_LIGHT_RED = 0xC; + public static final char COLOR_FG_LIGHT_MAGENTA = 0xD; + public static final char COLOR_FG_WHITE_HIGH = 0xF; + + public static final int EXTENDED_5250_REVERSE = 0x10; + public static final int EXTENDED_5250_UNDERLINE = 0x08; + public static final int EXTENDED_5250_BLINK = 0x04; + public static final int EXTENDED_5250_COL_SEP = 0x02; + public static final int EXTENDED_5250_NON_DSP = 0x01; + + public static final char ATTR_32 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_GREEN & 0xff); + public static final char ATTR_33 = (COLOR_BG_GREEN << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + public static final char ATTR_34 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_WHITE & 0xff); + public static final char ATTR_35 = (COLOR_BG_WHITE << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + public static final char ATTR_36 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_GREEN & 0xff); + public static final char ATTR_37 = (COLOR_BG_GREEN << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + public static final char ATTR_38 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_WHITE & 0xff); + public static final char ATTR_40 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_RED & 0xff); + public static final char ATTR_41 = (COLOR_BG_RED << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + public static final char ATTR_42 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_RED & 0xff); + public static final char ATTR_43 = (COLOR_BG_RED << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + + public static final char ATTR_44 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_RED & 0xff); + public static final char ATTR_45 = ( COLOR_BG_RED << 8 & 0xff00) | + ( COLOR_FG_BLACK & 0xff); + public static final char ATTR_46 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_RED & 0xff); + + public static final char ATTR_48 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_CYAN & 0xff); + public static final char ATTR_49 = (COLOR_BG_CYAN << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + public static final char ATTR_50 = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_YELLOW & 0xff); + + public static final char ATTR_51 = (COLOR_BG_YELLOW << 8 & 0xff00) | + (COLOR_FG_BLACK & 0xff); + public static final char ATTR_52 = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_CYAN & 0xff); + public static final char ATTR_53 = ( COLOR_BG_CYAN << 8 & 0xff00) | + ( COLOR_FG_BLACK & 0xff); + public static final char ATTR_54 = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_YELLOW & 0xff); + public static final char ATTR_56 = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_MAGENTA & 0xff); + public static final char ATTR_57 = ( COLOR_BG_MAGENTA << 8 & 0xff00) | + ( COLOR_FG_BLACK & 0xff); + public static final char ATTR_58 = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_BLUE & 0xff); + public static final char ATTR_59 = ( COLOR_BG_BLUE << 8 & 0xff00) | + ( COLOR_FG_BLACK & 0xff); + public static final char ATTR_60 = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_MAGENTA & 0xff); + public static final char ATTR_61 = ( COLOR_BG_MAGENTA << 8 & 0xff00) | + ( COLOR_FG_BLACK & 0xff); + public static final char ATTR_62 = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_BLUE & 0xff); + + public static final int NO_GUI = 0; + public static final int UPPER_LEFT = 1; + public static final int UPPER = 2; + public static final int UPPER_RIGHT = 3; + public static final int GUI_LEFT = 4; + public static final int GUI_RIGHT = 5; + public static final int LOWER_LEFT = 6; + public static final int BOTTOM = 7; + public static final int LOWER_RIGHT = 8; + public static final int FIELD_LEFT = 9; + public static final int FIELD_RIGHT = 10; + public static final int FIELD_MIDDLE = 11; + public static final int FIELD_ONE = 12; + public static final int BUTTON_LEFT = 13; + public static final int BUTTON_RIGHT = 14; + public static final int BUTTON_MIDDLE = 15; + public static final int BUTTON_ONE = 16; + public static final int BUTTON_LEFT_UP = 17; + public static final int BUTTON_RIGHT_UP = 18; + public static final int BUTTON_MIDDLE_UP = 19; + public static final int BUTTON_ONE_UP = 20; + public static final int BUTTON_LEFT_DN = 21; + public static final int BUTTON_RIGHT_DN = 22; + public static final int BUTTON_MIDDLE_DN = 23; + public static final int BUTTON_ONE_DN = 24; + public static final int BUTTON_LEFT_EB = 25; + public static final int BUTTON_RIGHT_EB = 26; + public static final int BUTTON_MIDDLE_EB = 27; + public static final int BUTTON_SB_UP = 28; + public static final int BUTTON_SB_DN = 29; + public static final int BUTTON_SB_GUIDE = 30; + public static final int BUTTON_SB_THUMB = 31; + public static final int BUTTON_LAST = 31; + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/Tn5250jEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/Tn5250jEvent.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,62 @@ +/**Copyright (C) 2004 Seagull Software +* +* This library 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 of the License, or (at your option) any later version. +* +* This library 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 library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*@author bvansomeren (bvansomeren@seagull.nl) +*/ +package org.tn5250j.framework; + +//import org.tn5250j.Screen5250; +import org.tn5250j.framework.tn5250.Screen5250; +import org.tn5250j.framework.tn5250.ScreenFields; +//import org.tn5250j.ScreenFields; + +public class Tn5250jEvent { + + private Screen5250 screen; + private char[] data; + private ScreenFields fields; + + public Tn5250jEvent() { + screen = null; + } + + public Tn5250jEvent(Screen5250 newscreen) { + screen = newscreen; +// Object[] original = (Object[])screen.getCharacters(); +// data = new ScreenChar[original.length]; +// System.arraycopy(original, 0, data, 0, original.length); + + // changed by Kenneth - This should be replaced with a call to + // getPlane method of screen object when they are implemented. These + // new methods will also do the array copy. + char[] original = screen.getCharacters(); + data = new char[original.length]; + System.arraycopy(original, 0, data, 0, original.length); + this.fields = newscreen.getScreenFields(); + } + + public char[] getData() { + return data; + } + + public Screen5250 getScreen() { + return screen; + } + + public ScreenFields getFields() { + return this.fields; + } +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/Tn5250jKeyEvents.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/Tn5250jKeyEvents.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,36 @@ +/**Copyright (C) 2004 Seagull Software +* +* This library 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 of the License, or (at your option) any later version. +* +* This library 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 library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*@author bvansomeren (bvansomeren@seagull.nl) +*/ +package org.tn5250j.framework; + +//import org.tn5250j.Screen5250; +import org.tn5250j.framework.tn5250.Screen5250; + +public class Tn5250jKeyEvents extends Tn5250jEvent { + private String keystrokes; + + public Tn5250jKeyEvents(Screen5250 screen, String strokes) { + super(screen); + this.keystrokes = strokes; + } + + public String getKeystrokes() { + return this.keystrokes; + } + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/Tn5250jListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/Tn5250jListener.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,38 @@ +/**Copyright (C) 2004 Seagull Software +* +* This library 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 of the License, or (at your option) any later version. +* +* This library 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 library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*@author bvansomeren (bvansomeren@seagull.nl) +*/ +package org.tn5250j.framework; + +import java.io.File; +import java.util.Properties; + +public abstract class Tn5250jListener { + public abstract void actionPerformed(Tn5250jEvent event); + + public abstract void init(File fileDir, Properties config); + + public abstract void run(); + + public abstract void destroy(); + + public abstract String getName(); + + public abstract void setController(Tn5250jController control); + + public abstract void sessionCreated(Tn5250jSession session); +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/DataStreamProducer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/DataStreamProducer.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,353 @@ +package org.tn5250j.framework.tn5250; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.SocketException; +import java.util.concurrent.BlockingQueue; + +import org.tn5250j.encoding.ICodePage; +import org.tn5250j.tools.logging.TN5250jLogFactory; +import org.tn5250j.tools.logging.TN5250jLogger; + +public class DataStreamProducer implements Runnable { + + private BufferedInputStream bin; + private ByteArrayOutputStream baosin; + private Thread me; + private byte[] saveStream; + private final BlockingQueue dsq; + private tnvt vt; + private byte[] abyte2; + private FileOutputStream fw; + private BufferedOutputStream dw; + private boolean dumpBytes = false; + private ICodePage codePage; + + private TN5250jLogger log = TN5250jLogFactory.getLogger (this.getClass()); + + public DataStreamProducer(tnvt vt, BufferedInputStream in, BlockingQueue queue, byte[] init) { + bin = in; + this.vt = vt; + baosin = new ByteArrayOutputStream(); + dsq = queue; + abyte2 = init; + } + + public void setInputStream(ByteArrayOutputStream is) { + + baosin = is; + + } + + public final void run() { + + boolean done = false; + + me = Thread.currentThread(); + + // load the first response screen + loadStream(abyte2, 0); + + while (!done) { + try { + + byte[] abyte0 = readIncoming(); + + // WVL - LDC : 17/05/2004 : Device name negotiations send TIMING MARK + // Restructured to the readIncoming() method to return null + // on TIMING MARK. Don't process in that case (abyte0 == null)! + if (abyte0 != null) + { + // WVL - LDC : 16/07/2003 : TR.000345 + // When the socket has been closed, the reading returns + // no bytes (an empty byte arrray). + // But the loadStream fails on this, so we check it here! + if (abyte0.length > 0) + { + loadStream(abyte0, 0); + } + // WVL - LDC : 16/07/2003 : TR.000345 + // Returning no bytes means the input buffer has + // reached end-of-stream, so we do a disconnect! + else + { + done = true; + vt.disconnect(); + } + } + + } + + catch (SocketException se) { + log.warn(" DataStreamProducer thread interrupted and stopping " + se.getMessage()); + done = true; + } + + catch (IOException ioe) { + + log.warn(ioe.getMessage()); + if (me.isInterrupted()) + done = true; + + } + catch (Exception ex) { + + log.warn(ex.getMessage()); + if (me.isInterrupted()) + done = true; + + } + } + } + + private final void loadStream(byte abyte0[], int i) { + + int j = 0; + int size = 0; + if (saveStream == null) { + j = (abyte0[i] & 0xff) << 8 | abyte0[i + 1] & 0xff; + size = abyte0.length; + } + else { + size = saveStream.length + abyte0.length; + byte[] inter = new byte[size]; + System.arraycopy(saveStream, 0, inter, 0, saveStream.length); + System.arraycopy(abyte0, 0, inter, saveStream.length, abyte0.length); + abyte0 = new byte[size]; + System.arraycopy(inter, 0, abyte0, 0, size); + saveStream = null; + inter = null; + j = (abyte0[i] & 0xff) << 8 | abyte0[i + 1] & 0xff; + log.debug("partial stream found"); + } + + if (j > size) { + saveStream = new byte[abyte0.length]; + System.arraycopy(abyte0, 0, saveStream, 0, abyte0.length); + log.debug("partial stream saved"); + } + else { + byte abyte1[]; + try { + abyte1 = new byte[j + 2]; + + System.arraycopy(abyte0, i, abyte1, 0, j + 2); + dsq.put(abyte1); + if(abyte0.length > abyte1.length + i) + loadStream(abyte0, i + j + 2); + } + catch (Exception ex) { + + log.warn("load stream error " + ex.getMessage()); + // ex.printStackTrace(); + // dump(abyte0); + + } + } + } + + public final byte[] readIncoming() + throws IOException { + + boolean done = false; + boolean negotiate = false; + + baosin.reset(); + int j = -1; + int i = 0; + + while(!done) { + + i = bin.read(); + + // WVL - LDC : 16/07/2003 : TR.000345 + // The inStream return -1 when end-of-stream is reached. This + // happens e.g. when the connection is closed from the AS/400. + // So we stop in this case! + // ==> an empty byte array is returned from this method. + if (i == -1) // nothing read! + { + done = true; + vt.disconnect(); + continue; + } + + // We use the values instead of the static values IAC and EOR + // because they are defined as bytes. + // + // The > if(i != 255 || j != 255) < is a hack for the double FF FF's + // that are being returned. I do not know why this is like this and + // can not find any documentation for it. It is also being returned + // on my Client Access tcp dump as well so they are handling it. + // + // my5250 + // 0000: 00 50 DA 44 C8 45 42 00 00 00 00 24 08 00 45 00 .P.D.EB....$..E. + // 0010: 04 2A BC F9 00 00 40 06 D0 27 C1 A8 33 04 C1 A8 .*....@..'..3... + // 0020: 33 58 00 17 04 18 6F A2 83 CB 00 1E D1 BA 50 18 3X....o.......P. + // 0030: 20 00 8A 9A 00 00 03 FF FF 12 A0 00 00 04 00 00 ............... + // --------------------------- || || ------------------------------------- + // 0040: 03 04 40 04 11 00 20 01 07 00 00 00 18 00 00 10 ..@... ......... + + if(j == 255 && i == 255) { + j = -1; + continue; + } + baosin.write(i); + // check for end of record EOR and IAC - FFEF + if(j == 255 && i == 239) + done = true; + + // This is to check for the TELNET TIMING MARK OPTION + // rfc860 explains this in more detail. When we receive it + // we will negotiate with the server by sending a WONT'T TIMING-MARK + // This will let the server know that we processed the information + // and are just waiting for the user to enter some data so keep the + // socket alive. This is more or less a AYT (ARE YOU THERE) or not. + if(i == 253 && j == 255) { + done = true; + negotiate = true; + } + j = i; + } + + // after the initial negotiation we might get other options such as + // timing marks ?????????????? do we ???????????? look at telnet spec + // yes we do. rfc860 explains about timing marks. + + // WVL - LDC : 17/05/2004 : Device name negotiations send TIMING MARK + // to existing device! + // Handled incorrectly: we cannot continue processing the TIMING MARK DO + // after we have handled it in the vt.negotiate() + // We should not return the bytes; + // ==> restructured to return null after negotiation! + // Impacts the run method! Added the null check. + byte[] rBytes = baosin.toByteArray(); + + if (dumpBytes) { + dump(rBytes); + } + + if (negotiate) { + // get the negotiation option + baosin.write(bin.read()); + vt.negotiate(rBytes); + + return null; + } + return rBytes; + } + + protected final void toggleDebug (ICodePage cp) { + + if (codePage == null) + codePage = cp; + + dumpBytes = !dumpBytes; + if (dumpBytes) { + + try { + if (fw == null) { + fw = new FileOutputStream("log.txt"); + dw = new BufferedOutputStream(fw); + } + } + catch (FileNotFoundException fnfe) { + log.warn(fnfe.getMessage()); + } + + } + else { + + try { + + if (dw != null) + dw.close(); + if (fw != null) + fw.close(); + dw = null; + fw = null; + codePage = null; + } + catch(IOException ioe) { + + log.warn(ioe.getMessage()); + } + } + + log.info("Data Stream output is now " + dumpBytes); + } + + public void dump (byte[] abyte0) { + try { + + log.info("\n Buffer Dump of data from AS400: "); + dw.write("\r\n Buffer Dump of data from AS400: ".getBytes()); + + StringBuffer h = new StringBuffer(); + for (int x = 0; x < abyte0.length; x++) { + if (x % 16 == 0) { + System.out.println(" " + h.toString()); + dw.write((" " + h.toString() + "\r\n").getBytes()); + + h.setLength(0); + h.append("+0000"); + h.setLength(5 - Integer.toHexString(x).length()); + h.append(Integer.toHexString(x).toUpperCase()); + + System.out.print(h.toString()); + dw.write(h.toString().getBytes()); + + h.setLength(0); + } + char ac = codePage.ebcdic2uni(abyte0[x]); + if (ac < ' ') + h.append('.'); + else + h.append(ac); + if (x % 4 == 0) { + System.out.print(" "); + dw.write((" ").getBytes()); + + } + + if (Integer.toHexString(abyte0[x] & 0xff).length() == 1){ + System.out.print("0" + Integer.toHexString(abyte0[x] & 0xff).toUpperCase()); + dw.write(("0" + Integer.toHexString(abyte0[x] & 0xff).toUpperCase()).getBytes()); + + } + else { + System.out.print(Integer.toHexString(abyte0[x] & 0xff).toUpperCase()); + dw.write((Integer.toHexString(abyte0[x] & 0xff).toUpperCase()).getBytes()); + } + + } + System.out.println(); + dw.write("\r\n".getBytes()); + + dw.flush(); + } + catch(EOFException _ex) { } + catch(Exception _ex) { + log.warn("Cannot dump from host\n\r"); + } + + } + +// public void dumpBytes() { +// byte shit[] = bk.buffer; +// for (int i = 0;i < shit.length;i++) +// System.out.println(i + ">" + shit[i] + "< - ascii - >" + getASCIIChar(shit[i]) + "<"); +// } +// +// public void dumpHexBytes(byte[] abyte) { +// byte shit[] = abyte; +// for (int i = 0;i < shit.length;i++) +// System.out.println(i + ">" + shit[i] + "< hex >" + Integer.toHexString((shit[i] & 0xff))); +// } + +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/KbdTypesCodePages.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/KbdTypesCodePages.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,112 @@ +package org.tn5250j.framework.tn5250; + +/** + * IBM i 7.1 Information Center > Programmierung > i5/OS globalization > Globalization reference information > Keyboard reference information + * + * @see National language keyboard types and SBCS code pages + */ +public enum KbdTypesCodePages { + + ALI("Albanian","ALI","697","500","500"), + CLB("Arabic","CLB","235","420","420"), + AGB("Austrian/ German","AGB","697","273","273"), + AGE("Austrian/ German","AGB","695","1141","1141"), + AGI("Austrian/German (MNCS)","AGI","697","500","500"), + BLI("Belgian MNCS","BLI","697","500","500"), + BRB("Brazilian Portuguese","BRB","697","37","37"), + BGB("Bulgarian","BGB","1150","1025","1025"), + CAB("Canadian French","CAB","341","260","65535"), + CAI("Canadian French MNCS","CAI","697","500","500"), +// YGI("Croatian","YGI","959","870","870"), + CYB("Cyrillic","CYB","960","880","880"), + CSB("Czech","CSB","959","870","870"), + DMB("Danish","DMB","697","277","277"), + DMI("Danish MNCS","DMI","697","500","500"), + FNB("Finnish/Swedish","FNB","697","278","278"), + FNI("Finnish/Swedish MNCS","FNI","697","500","500"), + FAB("French (Azerty)","FAB","697","297","297"), + FAI("French (Azerty) MNCS","FAI","697","500","500"), + FQB("French (Qwerty)","FQB","697","297","297"), + FQI("French (Qwerty) MNCS","FQI","697","500","500"), + GNB("Greek (See note 2.)","GNB","925","875","875"), + NCB("Hebrew","NCB","941","424","424"), + HNB("Hungarian","HNB","959","870","870"), + ICB("Icelandic","ICB","697","871","871"), + ICI("Icelandic MNCS","ICI","697","500","500"), + INB("International","INB","697","500","500"), + INBX("International-X","INB","697","500","500-ch"), +// INB("International MNCS","INB","697","500","500"), + IRB("Farsi (Iran)","IRB","1219","1097","1097"), + ITB("Italian","ITB","697","280","280"), + ITI("Italian MNCS","ITI","697","500","500"), + JEB("Japanese-English","JEB","697","281","65535"), + JEI("Japanese- English MNCS","JEI","697","500","500"), + JKB("Japanese Kanji and Katakana","JKB","1172","290","5026"), +// JUB("Japanese Kanji and US English","JUB","697","37","See note 3."), + KAB("Japanese Katakana","KAB","332","290","290"), + JPB("Japanese Latin Extended","JPB","1172","1027","1027"), + KOB("Korean","KOB","1173","833","833"), + ROB("Latin 2","ROB","959","870","870"), + MKB("Macedonian","MKB","1150","1025","1025"), + NEB("Dutch (Netherlands)","NEB","697","37","37"), + NEI("Dutch (Netherlands) MNCS","NEI","697","500","500"), + NWB("Norwegian","NWB","697","277","277"), + NWI("Norwegian MNCS","NWI","697","500","500"), + PLB("Polish","PLB","959","870","870"), + PLBX("Polish 870-pl","PLB","959","870","870-pl"), // Workaround, to catch up Java codepage '870-pl' + PRB("Portuguese","PRB","697","37","37"), + PRI("Portuguese MNCS","PRI","697","500","500"), + RMB("Romanian","RMB","959","870","870"), + RUB("Russian","RUB","1150","1025","1025"), + SQB("Serbian, Cyrillic","SQB","1150","1025","1025"), + YGI("Serbian, Latin","YGI","959","870","870"), + RCB("Simplified Chinese","RCB","1174","836","836"), + SKB("Slovakian","SKB","959","870","870"), + SKBX("Slovakian 870-sk","SKB","959","870","870-sk"), // Workaround, to catch up Java codepage '870-sk' +// YGI("Slovenian","YGI","959","870","870"), + SPB("Spanish","SPB","697","284","284"), + SPI("Spanish MNCS","SPI","697","500","500"), + SSB("Spanish Speaking","SSB","697","284","284"), + SSI("Spanish Speaking MNCS","SSI","697","500","500"), + SWB("Swedish","SWB","697","278","278"), + SWI("Swedish MNCS","SWI","697","500","500"), + SFI("French (Switzerland) MNCS","SFI","697","500","500"), + SGI("German (Switzerland) MNCS","SGI","697","500","500"), + THB("Thai","THB","1176","838","838"), + TAB("Traditional Chinese","TAB","1175","37","937"), + TKB("Turkish (Qwerty)","TKB","1152","1026","1026"), + TRB("Turkish (F)","TRB","1152","1026","1026"), + UKB("English (United Kingdom)","UKB","697","285","285"), + UKI("English (United Kingdom) MNCS","UKI","697","500","500"), + USB("English (United States and Canada)","USB","697","37","37"), + USI("English (United States and Canada) MNCS","USI","697","500","500"); + + public final String description; + public final String kbdType; + public final String charset; + public final String codepage; + public final String ccsid; + + /** + * @param description + * @param kbdType + * @param charset + * @param codepage + * @param ccsid + */ + private KbdTypesCodePages(String description, String kbdType, String charset, String codepage, String ccsid) { + this.description = description; + this.kbdType = kbdType; + this.charset = charset; + this.codepage = codepage; + this.ccsid = ccsid; + } + + @Override + public String toString() { + return "[description=" + description + ", kbdType=" + kbdType + + ", charset=" + charset + ", codepage=" + codepage + + ", ccsid=" + ccsid + "]"; + } + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/KeyStrokenizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/KeyStrokenizer.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,158 @@ +/* + * @(#)KeyStrokenizer.java + * Copyright: Copyright (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ + +package org.tn5250j.framework.tn5250; + +import org.tn5250j.tools.logging.TN5250jLogFactory; +import org.tn5250j.tools.logging.TN5250jLogger; + + +public class KeyStrokenizer { + + private StringBuffer keyStrokes; + private StringBuffer sb; + private int index; + private int length; + + private final TN5250jLogger log = TN5250jLogFactory.getLogger(this.getClass()); + + public KeyStrokenizer() { + + sb = new StringBuffer(); + setKeyStrokes(null); + } + + public void setKeyStrokes (String strokes) { + + if (strokes != null) { + keyStrokes.setLength(0); + log.debug("set "+ keyStrokes); + length = strokes.length(); + } + else { + + keyStrokes = new StringBuffer(); + length = 0; + + } + keyStrokes.append(strokes); + index = 0; + + } + + public boolean hasMoreKeyStrokes() { + return length > index; + } + + public String nextKeyStroke() { + + String s = ""; + boolean gotOne = false; + if(length > index) { + sb.setLength(0); + + char c = keyStrokes.charAt(index); + switch(c) { + case '[': + sb.append(c); + index++; + + // we need to throw an error here + if(index >= length) { + log.warn(" mnemonic key was incomplete :1 " + + "at position " + index + " len " + length ); + } + else { + c = keyStrokes.charAt(index); + + if(c == '[') + index++; + else { + while(!gotOne) { + + if(c == ']') { // did we find an ending + sb.append(c); + index++; + gotOne = true; + } + else { + sb.append(c); + index++; + // we need to throw an error here because we did not + // find an ending for the potential mnemonic + if(index >= length) { + log.warn( + " mnemonic key was incomplete ending not found :2 " + + "at position " + index); + } + c = keyStrokes.charAt(index); + } + } + } + } + break; + + case ']': + index++; + if(index >= length) { + log.warn( + " mnemonic key was incomplete ending not found :3 " + + "at position " + index); + sb.append(c); + index++; + + } + else { + c = keyStrokes.charAt(index); + if(c == ']') { + sb.append(c); + index++; + } + else { + log.warn( + " mnemonic key was incomplete beginning not found :4 " + + "at position " + index); + } + } + break; + default: + sb.append(c); + index++; + break; + } + if(sb != null) { + s = new String(sb); + } + + } + log.debug("next "+ keyStrokes); + + return s; + } + + public String getUnprocessedKeyStroked() { + if(index >= length) { + return null; + } + return keyStrokes.substring(index); + } + +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/Rect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/Rect.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,61 @@ +/** + * $Id: Rect.java 1092 2011-01-16 20:27:56Z master_jaf $ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + + +/** + * Simplified rectangle class. Very much similar like java.awt.Rectangle, + * but we want to decouple the packages ... + */ +public class Rect { + + /* default */ int x; + /* default */ int y; + /* default */ int height; + /* default */ int width; + + /** + * @param rect + */ + public void setBounds(Rect rect) { + setBounds(rect.x, rect.y, rect.width, rect.height); + } + + /** + * @param x the new X coordinate for the upper-left corner of this rectangle + * @param y the new Y coordinate for the upper-left corner of this rectangle + * @param width the new width for this rectangle + * @param height the new height for this rectangle + */ + public void setBounds(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/Screen5250.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/Screen5250.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,3999 @@ +/** + * Title: Screen5250.java + * Copyright: Copyright (c) 2001 - 2004 + * Company: + * @author Kenneth J. Pouncey + * @version 0.5 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +import static org.tn5250j.TN5250jConstants.*; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Vector; + +import org.tn5250j.TN5250jConstants; +import org.tn5250j.event.ScreenListener; +import org.tn5250j.tools.logging.TN5250jLogFactory; +import org.tn5250j.tools.logging.TN5250jLogger; + +public class Screen5250 { + + private ScreenFields screenFields; + private int lastAttr; + private int lastPos; + private int lenScreen; + private KeyStrokenizer strokenizer; + private tnvt sessionVT; + private int numRows = 0; + private int numCols = 0; + protected static final int initAttr = 32; + protected static final char initChar = 0; + public boolean cursorActive = false; + public boolean cursorShown = false; + protected boolean insertMode = false; + private boolean keyProcessed = false; + private Rect dirtyScreen = new Rect(); + + public int homePos = 0; + public int saveHomePos = 0; + private String bufferedKeys; + public boolean pendingInsert = false; + + public final static byte STATUS_SYSTEM = 1; + public final static byte STATUS_ERROR_CODE = 2; + public final static byte STATUS_VALUE_ON = 1; + public final static byte STATUS_VALUE_OFF = 2; + + private StringBuffer hsMore = new StringBuffer("More..."); + private StringBuffer hsBottom = new StringBuffer("Bottom"); + + // error codes to be sent to the host on an error + private final static int ERR_CURSOR_PROTECTED = 0x05; + private final static int ERR_INVALID_SIGN = 0x11; + private final static int ERR_NO_ROOM_INSERT = 0x12; + private final static int ERR_NUMERIC_ONLY = 0x09; + private final static int ERR_DUP_KEY_NOT_ALLOWED = 0x19; + private final static int ERR_NUMERIC_09 = 0x10; + private final static int ERR_FIELD_MINUS = 0x16; + private final static int ERR_FIELD_EXIT_INVALID = 0x18; + private final static int ERR_ENTER_NO_ALLOWED = 0x20; + private final static int ERR_MANDITORY_ENTER = 0x21; + + private boolean guiInterface = false; + private boolean resetRequired = true; + private boolean backspaceError = true; + private boolean feError; + + // vector of listeners for changes to the screen. + Vector listeners = null; + + // Operator Information Area + private ScreenOIA oia; + + // screen planes + protected ScreenPlanes planes; + + //Added by Barry + private StringBuffer keybuf; + + private TN5250jLogger log = TN5250jLogFactory.getLogger(this.getClass()); + + public Screen5250() { + + //Added by Barry + this.keybuf = new StringBuffer(); + + try { + jbInit(); + } catch (Exception ex) { + log.warn("In constructor: ", ex); + } + } + + void jbInit() throws Exception { + + lastAttr = 32; + + // default number of rows and columns + numRows = 24; + numCols = 80; + + setCursor(1, 1); // set initial cursor position + + oia = new ScreenOIA(this); + oia.setKeyBoardLocked(true); + + lenScreen = numRows * numCols; + + planes = new ScreenPlanes(this,numRows); + + screenFields = new ScreenFields(this); + strokenizer = new KeyStrokenizer(); + } + + protected ScreenPlanes getPlanes() { + return planes; + } + + public final ScreenOIA getOIA() { + return oia; + } + + protected final void setRowsCols(int rows, int cols) { + + int oldRows = numRows; + int oldCols = numCols; + + // default number of rows and columns + numRows = rows; + numCols = cols; + + lenScreen = numRows * numCols; + + planes.setSize(rows); + + // If they are not the same then we need to inform the listeners that + // the size changed. + if (oldRows != numRows || oldCols != numCols) + fireScreenSizeChanged(); + + } + + + public boolean isCursorActive() { + return cursorActive; + + } + + public boolean isCursorShown() { + return cursorShown; + } + + public void setUseGUIInterface(boolean gui) { + guiInterface = gui; + } + + public void toggleGUIInterface() { + guiInterface = !guiInterface; + } + + public void setResetRequired(boolean reset) { + resetRequired = reset; + } + + public void setBackspaceError(boolean onError) { + backspaceError = onError; + } + + /** + * Copy & Paste support + * + * @see {@link #pasteText(String, boolean)} + * @see {@link #copyTextField(int)} + */ + public final String copyText(Rect area) { + StringBuilder sb = new StringBuilder(); + Rect workR = new Rect(); + workR.setBounds(area); + log.debug("Copying " + workR); + + // loop through all the screen characters to send them to the clip board + int m = workR.x; + int i = 0; + int t = 0; + + while (workR.height-- > 0) { + t = workR.width; + i = workR.y; + while (t-- > 0) { + // only copy printable characters (in this case >= ' ') + char c = planes.getChar(getPos(m - 1, i - 1)); + if (c >= ' ' && (planes.screenExtended[getPos(m - 1, i - 1)] & EXTENDED_5250_NON_DSP) + == 0) + sb.append(c); + else + sb.append(' '); + + i++; + } + sb.append('\n'); + m++; + } + return sb.toString(); + } + + /** + * Copy & Paste support + * + * @param content + * @see {@link #copyText(Rectangle)} + */ + public final void pasteText(String content, boolean special) { + if (log.isDebugEnabled()) { + log.debug("Pasting, special:"+special); + } + setCursorActive(false); + + StringBuilder sb = new StringBuilder(content); + StringBuilder pd = new StringBuilder(); + + // character counters within the string to be pasted. + int nextChar = 0; + int nChars = sb.length(); + + int lr = getRow(lastPos); + int lc = getCol(lastPos); + resetDirty(lastPos); + + int cpos = lastPos; + int length = getScreenLength(); + + char c = 0; + boolean setIt; + + // save our current place within the FFT. + screenFields.saveCurrentField(); + + for (int x = nextChar; x < nChars; x++) { + + c = sb.charAt(x); + + if ((c == '\n') || (c == '\r')) { + + log.info("pasted cr-lf>" + pd + "<"); + pd.setLength(0); + // if we read in a cr lf in the data stream we need to go + // to the starting column of the next row and start from there + cpos = getPos(getRow(cpos)+1,lc); + + // If we go paste the end of the screen then let's start over from + // the beginning of the screen space. + if (cpos > length) + cpos = 0; + } + else { + + // we will default to set the character always. + setIt = true; + + // If we are in a special paste scenario then we check for valid + // characters to paste. + if (special && (!Character.isLetter(c) && !Character.isDigit(c))) + setIt = false; + + // we will only push a character to the screen space if we are in + // a field + if (isInField(cpos) && setIt) { + planes.setChar(cpos, c); + setDirty(cpos); + screenFields.setCurrentFieldMDT(); + } + // If we placed a character then we go to the next position. + if (setIt) + cpos++; + // we will append the information to our debug buffer. + pd.append(c); + } + } + + // if we have anything else not logged then log it out. + if (pd.length() > 0) + log.info("pasted >" + pd + "<"); + + // restore out position within the FFT. + screenFields.restoreCurrentField(); + updateDirty(); + + // restore our cursor position. + setCursor(lr + 1, lc + 1); + + setCursorActive(true); + + } + + /** + * Copy & Paste support + * + * @param position + * @return + * @see {@link #copyText(int)} + */ + public final String copyTextField(int position) { + screenFields.saveCurrentField(); + isInField(position); + String result = screenFields.getCurrentFieldText(); + screenFields.restoreCurrentField(); + return result; + } + + /** + * + * Copy & Paste end code + * + */ + + /** + * Sum them + * + * @param which + * formatting option to use + * @return vector string of numberic values + */ + public final Vector sumThem(boolean which, Rect area) { + + StringBuilder sb = new StringBuilder(); + Rect workR = new Rect(); + workR.setBounds(area); + + // gui.rubberband.reset(); + // gui.repaint(); + + log.debug("Summing"); + + // obtain the decimal format for parsing + DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(); + + DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + + if (which) { + dfs.setDecimalSeparator('.'); + dfs.setGroupingSeparator(','); + } else { + dfs.setDecimalSeparator(','); + dfs.setGroupingSeparator('.'); + } + + df.setDecimalFormatSymbols(dfs); + + Vector sumVector = new Vector(); + + // loop through all the screen characters to send them to the clip board + int m = workR.x; + int i = 0; + int t = 0; + + double sum = 0.0; + + while (workR.height-- > 0) { + t = workR.width; + i = workR.y; + while (t-- > 0) { + + // only copy printable numeric characters (in this case >= ' ') + // char c = screen[getPos(m - 1, i - 1)].getChar(); + char c = planes.getChar(getPos(m - 1, i - 1)); + // if (((c >= '0' && c <= '9') || c == '.' || c == ',' || c == '-') + // && !screen[getPos(m - 1, i - 1)].nonDisplay) { + + // TODO: update me here to implement the nonDisplay check as well + if (((c >= '0' && c <= '9') || c == '.' || c == ',' || c == '-')) { + sb.append(c); + } + i++; + } + + if (sb.length() > 0) { + if (sb.charAt(sb.length() - 1) == '-') { + sb.insert(0, '-'); + sb.deleteCharAt(sb.length() - 1); + } + try { + Number n = df.parse(sb.toString()); + // System.out.println(s + " " + n.doubleValue()); + + sumVector.add(new Double(n.doubleValue())); + sum += n.doubleValue(); + } catch (ParseException pe) { + log.warn(pe.getMessage() + " at " + + pe.getErrorOffset()); + } + } + sb.setLength(0); + m++; + } + log.debug("" + sum); + return sumVector; + } + + /** + * This will move the screen cursor based on the mouse event. + * + * I do not think the checks here for the gui characters should be here but + * will leave them here for now until we work out the interaction. This + * should be up to the gui frontend in my opinion. + * + * @param pos + */ + public boolean moveCursor(int pos) { + + if (!oia.isKeyBoardLocked()) { + + if (pos < 0) + return false; + // because getRowColFromPoint returns offset of 1,1 we need to + // translate to offset 0,0 + // pos -= (numCols + 1); + + int g = planes.getWhichGUI(pos); + + // lets check for hot spots + if (g >= BUTTON_LEFT && g <= BUTTON_LAST) { + StringBuffer aid = new StringBuffer(); + boolean aidFlag = true; + switch (g) { + case BUTTON_RIGHT: + case BUTTON_MIDDLE: + while (planes.getWhichGUI(--pos) != BUTTON_LEFT) { + } + case BUTTON_LEFT: + if (planes.getChar(pos) == 'F') { + pos++; + } else + aidFlag = false; + + if (planes.getChar(pos + 1) != '=' + && planes.getChar(pos + 1) != '.' + && planes.getChar(pos + 1) != '/') { + // System.out.println(" Hotspot clicked!!! we will send + // characters " + + // screen[pos].getChar() + + // screen[pos+1].getChar()); + aid.append(planes.getChar(pos)); + aid.append(planes.getChar(pos + 1)); + } else { + log.debug(" Hotspot clicked!!! we will send character " + + planes.getChar(pos)); + aid.append(planes.getChar(pos)); + } + break; + + } + if (aidFlag) { + switch (g) { + + case BUTTON_LEFT_UP: + case BUTTON_MIDDLE_UP: + case BUTTON_RIGHT_UP: + case BUTTON_ONE_UP: + case BUTTON_SB_UP: + case BUTTON_SB_GUIDE: + sessionVT.sendAidKey(AID_ROLL_UP); + break; + + case BUTTON_LEFT_DN: + case BUTTON_MIDDLE_DN: + case BUTTON_RIGHT_DN: + case BUTTON_ONE_DN: + case BUTTON_SB_DN: + case BUTTON_SB_THUMB: + + sessionVT.sendAidKey(AID_ROLL_DOWN); + break; + case BUTTON_LEFT_EB: + case BUTTON_MIDDLE_EB: + case BUTTON_RIGHT_EB: + StringBuffer eb = new StringBuffer(); + while (planes.getWhichGUI(pos--) != BUTTON_LEFT_EB) + ; + while (planes.getWhichGUI(pos++) != BUTTON_RIGHT_EB) { + eb.append(planes.getChar(pos)); + } + org.tn5250j.tools.system.OperatingSystem.displayURL(eb + .toString()); + // take out the log statement when we are sure it is + // working + log.info("Send to external Browser: " + eb.toString()); + break; + + default: + int aidKey = Integer.parseInt(aid.toString()); + if (aidKey >= 1 && aidKey <= 12) + sessionVT.sendAidKey(0x30 + aidKey); + if (aidKey >= 13 && aidKey <= 24) + sessionVT.sendAidKey(0xB0 + (aidKey - 12)); + } + } else { + if (screenFields.getCurrentField() != null) { + int xPos = screenFields.getCurrentField().startPos(); + for (int x = 0; x < aid.length(); x++) { + // System.out.println(sr + "," + (sc + x) + " " + + // aid.charAt(x)); + planes.setChar(xPos + x , aid.charAt(x)); + } + // System.out.println(aid); + screenFields.setCurrentFieldMDT(); + sessionVT.sendAidKey(AID_ENTER); + } + + } + // return back to the calling routine that the cursor was not moved + // but something else here was done like aid keys or the such + return false; + } + // this is a note to not execute this code here when we + // implement + // the remain after edit function option. + // if (gui.rubberband.isAreaSelected()) { + // gui.rubberband.reset(); + // gui.repaint(); + // } else { + goto_XY(pos); + isInField(lastPos); + + // return back to the calling object that the cursor was indeed + // moved with in the screen object + return true; + // } + } + return false; + } + + public void setVT(tnvt v) { + + sessionVT = v; + } + + /** + * Searches the mnemonicData array looking for the specified string. If it + * is found it will return the value associated from the mnemonicValue + * + * @see #sendKeys + * @param mnem + * string mnemonic value + * @return key value of Mnemonic + */ + private int getMnemonicValue(String mnem) { + + for (int x = 0; x < mnemonicData.length; x++) { + + if (mnemonicData[x].equals(mnem)) + return mnemonicValue[x]; + } + return 0; + + } + + protected void setPrehelpState(boolean setErrorCode, boolean lockKeyboard, + boolean unlockIfLocked) { + if (oia.isKeyBoardLocked() && unlockIfLocked) + oia.setKeyBoardLocked(false); + else + oia.setKeyBoardLocked(lockKeyboard); + bufferedKeys = null; + oia.setKeysBuffered(false); + + + } + + /** + * Activate the cursor on screen + * + * @param activate + */ + public void setCursorActive(boolean activate) { + + // System.out.println("cursor active " + updateCursorLoc + " " + + // cursorActive + " " + activate); + if (cursorActive && !activate) { + setCursorOff(); + cursorActive = activate; + } else { + if (!cursorActive && activate) { + cursorActive = activate; + setCursorOn(); + } + } + } + + /** + * Set the cursor on + */ + public void setCursorOn() { + cursorShown = true; + updateCursorLoc(); + } + + /** + * Set the cursor off + */ + public void setCursorOff() { + + cursorShown = false; + updateCursorLoc(); + // System.out.println("cursor off " + updateCursorLoc + " " + + // cursorActive); + + } + + /** + * + */ + private void updateCursorLoc() { + + if (cursorActive) { + + fireCursorChanged(3); + + } + } + + //Added by Barry + public String getKeys() { + String result = this.keybuf.toString(); + this.keybuf = new StringBuffer(); + return result; + } + + /** + * The sendKeys method sends a string of keys to the virtual screen. This + * method acts as if keystrokes were being typed from the keyboard. The + * keystrokes will be sent to the location given. The string being passed + * can also contain mnemonic values such as [enter] enter key,[tab] tab key, + * [pf1] pf1 etc... + * + * These will be processed as if you had pressed these keys from the + * keyboard. All the valid special key values are contained in the MNEMONIC + * enumeration: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
MNEMONIC_CLEAR[clear]
MNEMONIC_ENTER[enter]
MNEMONIC_HELP[help]
MNEMONIC_PAGE_DOWN[pgdown]
MNEMONIC_PAGE_UP[pgup]
MNEMONIC_PRINT[print]
MNEMONIC_PF1[pf1]
MNEMONIC_PF2[pf2]
MNEMONIC_PF3[pf3]
MNEMONIC_PF4[pf4]
MNEMONIC_PF5[pf5]
MNEMONIC_PF6[pf6]
MNEMONIC_PF7[pf7]
MNEMONIC_PF8[pf8]
MNEMONIC_PF9[pf9]
MNEMONIC_PF10[pf10]
MNEMONIC_PF11[pf11]
MNEMONIC_PF12[pf12]
MNEMONIC_PF13[pf13]
MNEMONIC_PF14[pf14]
MNEMONIC_PF15[pf15]
MNEMONIC_PF16[pf16]
MNEMONIC_PF17[pf17]
MNEMONIC_PF18[pf18]
MNEMONIC_PF19[pf19]
MNEMONIC_PF20[pf20]
MNEMONIC_PF21[pf21]
MNEMONIC_PF22[pf22]
MNEMONIC_PF23[pf23]
MNEMONIC_PF24[pf24]
MNEMONIC_BACK_SPACE[backspace]
MNEMONIC_BACK_TAB[backtab]
MNEMONIC_UP[up]
MNEMONIC_DOWN[down]
MNEMONIC_LEFT[left]
MNEMONIC_RIGHT[right]
MNEMONIC_DELETE[delete]
MNEMONIC_TAB"[tab]
MNEMONIC_END_OF_FIELD[eof]
MNEMONIC_ERASE_EOF[eraseeof]
MNEMONIC_ERASE_FIELD[erasefld]
MNEMONIC_INSERT[insert]
MNEMONIC_HOME[home]
MNEMONIC_KEYPAD0[keypad0]
MNEMONIC_KEYPAD1[keypad1]
MNEMONIC_KEYPAD2[keypad2]
MNEMONIC_KEYPAD3[keypad3]
MNEMONIC_KEYPAD4[keypad4]
MNEMONIC_KEYPAD5[keypad5]
MNEMONIC_KEYPAD6[keypad6]
MNEMONIC_KEYPAD7[keypad7]
MNEMONIC_KEYPAD8[keypad8]
MNEMONIC_KEYPAD9[keypad9]
MNEMONIC_KEYPAD_PERIOD[keypad.]
MNEMONIC_KEYPAD_COMMA[keypad,]
MNEMONIC_KEYPAD_MINUS[keypad-]
MNEMONIC_FIELD_EXIT[fldext]
MNEMONIC_FIELD_PLUS[field+]
MNEMONIC_FIELD_MINUS[field-]
MNEMONIC_BEGIN_OF_FIELD[bof]
MNEMONIC_PA1[pa1]
MNEMONIC_PA2[pa2]
MNEMONIC_PA3[pa3]
MNEMONIC_SYSREQ[sysreq]
MNEMONIC_RESET[reset]
MNEMONIC_ATTN[attn]
MNEMONIC_MARK_LEFT[markleft]
MNEMONIC_MARK_RIGHT[markright]
MNEMONIC_MARK_UP[markup]
MNEMONIC_MARK_DOWN[markdown]
+ * + * @param text + * The string of characters to be sent + * + * @see #sendAid + * + * Added synchronized to fix a StringOutOfBounds error - Luc Gorren LDC + */ + public synchronized void sendKeys(String text) { + + // if (text == null) { + // return; + // } + this.keybuf.append(text); + + if (isStatusErrorCode() && !resetRequired) { + setCursorActive(false); + simulateMnemonic(getMnemonicValue("[reset]")); + setCursorActive(true); + } + + if (oia.isKeyBoardLocked()) { + if (text.equals("[reset]") || text.equals("[sysreq]") + || text.equals("[attn]")) { + setCursorActive(false); + simulateMnemonic(getMnemonicValue(text)); + setCursorActive(true); + + } else { + if (isStatusErrorCode()) { + sessionVT.signalBell(); + return; + } + + oia.setKeysBuffered(true); + + if (bufferedKeys == null) { + bufferedKeys = text; + return; + } + bufferedKeys += text; + return; + } + + } else { + + if (oia.isKeysBuffered()) { + if (bufferedKeys != null) { + text = bufferedKeys + text; + } + // if (text.length() == 0) { + oia.setKeysBuffered(false); + // } + bufferedKeys = null; + + } + // check to see if position is in a field and if it is then change + // current field to that field + isInField(lastPos, true); + if (text.length() == 1 && !text.equals("[") && !text.equals("]")) { + // setCursorOff2(); + setCursorActive(false); + simulateKeyStroke(text.charAt(0)); + setCursorActive(true); + // setCursorOn2(); + // System.out.println(" text one"); + + } else { + + strokenizer.setKeyStrokes(text); + String s; + boolean done = false; + + // setCursorOff2(); + setCursorActive(false); + while (!done) { + // while (strokenizer.hasMoreKeyStrokes() && !keyboardLocked + // && + // !isStatusErrorCode() && !done) { + if (strokenizer.hasMoreKeyStrokes()) { + + // check to see if position is in a field and if it is + // then change + // current field to that field + isInField(lastPos, true); + s = strokenizer.nextKeyStroke(); + if (s.length() == 1) { + // setCursorOn(); + // if (!keysBuffered) { + // System.out.println(" s two" + s); + // setCursorOn(); + // } + + // try { new Thread().sleep(400);} catch + // (InterruptedException ie) {} + simulateKeyStroke(s.charAt(0)); + // System.out.println(" s two " + s + " " + + // cursorActive); + // if (cursorActive && !keysBuffered) { + // System.out.println(" s two" + s); + // setCursorOn(); + // } + } else { + simulateMnemonic(getMnemonicValue(s)); + // if (!cursorActive && !keysBuffered) { + // System.out.println(" m one"); + // setCursorOn(); + // } + } + + if (oia.isKeyBoardLocked()) { + + bufferedKeys = strokenizer + .getUnprocessedKeyStroked(); + if (bufferedKeys != null) { + oia.setKeysBuffered(true); + + } + done = true; + } + + } + + else { + // setCursorActive(true); + // setCursorOn(); + done = true; + } + } + setCursorActive(true); + } + } + } + + /** + * The sendAid method sends an "aid" keystroke to the virtual screen. These + * aid keys can be thought of as special keystrokes, like the Enter key, + * PF1-24 keys or the Page Up key. All the valid special key values are + * contained in the AID_ enumeration: + * + * @param aidKey + * The aid key to be sent to the host + * + * @see #sendKeys + * @see TN5250jConstants#AID_CLEAR + * @see #AID_ENTER + * @see #AID_HELP + * @see #AID_ROLL_UP + * @see #AID_ROLL_DOWN + * @see #AID_ROLL_LEFT + * @see #AID_ROLL_RIGHT + * @see #AID_PRINT + * @see #AID_PF1 + * @see #AID_PF2 + * @see #AID_PF3 + * @see #AID_PF4 + * @see #AID_PF5 + * @see #AID_PF6 + * @see #AID_PF7 + * @see #AID_PF8 + * @see #AID_PF9 + * @see #AID_PF10 + * @see #AID_PF11 + * @see #AID_PF12 + * @see #AID_PF13 + * @see #AID_PF14 + * @see #AID_PF15 + * @see #AID_PF16 + * @see #AID_PF17 + * @see #AID_PF18 + * @see #AID_PF19 + * @see #AID_PF20 + * @see #AID_PF21 + * @see #AID_PF22 + * @see #AID_PF23 + * @see #AID_PF24 + */ + public void sendAid(int aidKey) { + + sessionVT.sendAidKey(aidKey); + } + + /** + * Restores the error line and sets the error mode off. + * + */ + protected void resetError() { + + restoreErrorLine(); + setStatus(STATUS_ERROR_CODE, STATUS_VALUE_OFF, ""); + + } + + protected boolean simulateMnemonic(int mnem) { + + boolean simulated = false; + + switch (mnem) { + + case AID_CLEAR: + case AID_ENTER: + case AID_PF1: + case AID_PF2: + case AID_PF3: + case AID_PF4: + case AID_PF5: + case AID_PF6: + case AID_PF7: + case AID_PF8: + case AID_PF9: + case AID_PF10: + case AID_PF11: + case AID_PF12: + case AID_PF13: + case AID_PF14: + case AID_PF15: + case AID_PF16: + case AID_PF17: + case AID_PF18: + case AID_PF19: + case AID_PF20: + case AID_PF21: + case AID_PF22: + case AID_PF23: + case AID_PF24: + case AID_ROLL_DOWN: + case AID_ROLL_UP: + case AID_ROLL_LEFT: + case AID_ROLL_RIGHT: + + if (!screenFields.isCanSendAid()) { + displayError(ERR_ENTER_NO_ALLOWED); + } else + sendAid(mnem); + simulated = true; + + break; + case AID_HELP: + sessionVT.sendHelpRequest(); + simulated = true; + break; + + case AID_PRINT: + sessionVT.hostPrint(1); + simulated = true; + break; + + case BACK_SPACE: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + if (screenFields.getCurrentField().startPos() == lastPos) { + if (backspaceError) + displayError(ERR_CURSOR_PROTECTED); + else { + gotoFieldPrev(); + goto_XY(screenFields.getCurrentField().endPos()); + updateDirty(); + } + } + else { + screenFields.getCurrentField().getKeyPos(lastPos); + screenFields.getCurrentField().changePos(-1); + resetDirty(screenFields.getCurrentField().getCurrentPos()); + shiftLeft(screenFields.getCurrentField().getCurrentPos()); + updateDirty(); + screenFields.setCurrentFieldMDT(); + + simulated = true; + } + } else { + displayError(ERR_CURSOR_PROTECTED); + + } + break; + case BACK_TAB: + + if (screenFields.getCurrentField() != null + && screenFields.isCurrentFieldHighlightedEntry()) { + resetDirty(screenFields.getCurrentField().startPos); + gotoFieldPrev(); + updateDirty(); + } else + gotoFieldPrev(); + + if (screenFields.isCurrentFieldContinued()) { + do { + gotoFieldPrev(); + } while (screenFields.isCurrentFieldContinuedMiddle() + || screenFields.isCurrentFieldContinuedLast()); + } + isInField(lastPos); + simulated = true; + break; + case UP: + case MARK_UP: + process_XY(lastPos - numCols); + simulated = true; + break; + case DOWN: + case MARK_DOWN: + process_XY(lastPos + numCols); + simulated = true; + break; + case LEFT: + case MARK_LEFT: + process_XY(lastPos - 1); + simulated = true; + break; + case RIGHT: + case MARK_RIGHT: + process_XY(lastPos + 1); + simulated = true; + break; + case NEXTWORD: + gotoNextWord(); + simulated = true; + break; + case PREVWORD: + gotoPrevWord(); + simulated = true; + break; + case DELETE: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + resetDirty(lastPos); + screenFields.getCurrentField().getKeyPos(lastPos); + shiftLeft(screenFields.getCurrentFieldPos()); + screenFields.setCurrentFieldMDT(); + updateDirty(); + simulated = true; + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case TAB: + + if (screenFields.getCurrentField() != null + && !screenFields.isCurrentFieldContinued()) { + if (screenFields.isCurrentFieldHighlightedEntry()) { + resetDirty(screenFields.getCurrentField().startPos); + gotoFieldNext(); + updateDirty(); + } else + gotoFieldNext(); + } else { + do { + gotoFieldNext(); + } while (screenFields.getCurrentField() != null + && (screenFields.isCurrentFieldContinuedMiddle() || screenFields + .isCurrentFieldContinuedLast())); + } + + isInField(lastPos); + simulated = true; + + break; + case EOF: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + int where = endOfField(screenFields.getCurrentField() + .startPos(), true); + if (where > 0) { + setCursor((where / numCols) + 1, (where % numCols) + 1); + } + simulated = true; + } else { + displayError(ERR_CURSOR_PROTECTED); + } + resetDirty(lastPos); + + break; + case ERASE_EOF: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + int where = lastPos; + resetDirty(lastPos); + if (fieldExit()) { + screenFields.setCurrentFieldMDT(); + if (!screenFields.isCurrentFieldContinued()) { + gotoFieldNext(); + } else { + do { + gotoFieldNext(); + if (screenFields.isCurrentFieldContinued()) + fieldExit(); + } while (screenFields.isCurrentFieldContinuedMiddle() + || screenFields.isCurrentFieldContinuedLast()); + } + } + updateDirty(); + goto_XY(where); + simulated = true; + + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case ERASE_FIELD: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + int where = lastPos; + lastPos = screenFields.getCurrentField().startPos(); + resetDirty(lastPos); + if (fieldExit()) { + screenFields.setCurrentFieldMDT(); + if (!screenFields.isCurrentFieldContinued()) { + gotoFieldNext(); + } else { + do { + gotoFieldNext(); + if (screenFields.isCurrentFieldContinued()) + fieldExit(); + } while (screenFields.isCurrentFieldContinuedMiddle() + || screenFields.isCurrentFieldContinuedLast()); + } + } + updateDirty(); + goto_XY(where); + simulated = true; + + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case INSERT: + // we toggle it + oia.setInsertMode(oia.isInsertMode() ? false : true); + break; + case HOME: + // position to the home position set + if (lastPos + numCols + 1 != homePos) { + goto_XY(homePos - numCols - 1); + // now check if we are in a field + isInField(lastPos); + } else + gotoField(1); + break; + case KEYPAD_0: + simulated = simulateKeyStroke('0'); + break; + case KEYPAD_1: + simulated = simulateKeyStroke('1'); + break; + case KEYPAD_2: + simulated = simulateKeyStroke('2'); + break; + case KEYPAD_3: + simulated = simulateKeyStroke('3'); + break; + case KEYPAD_4: + simulated = simulateKeyStroke('4'); + break; + case KEYPAD_5: + simulated = simulateKeyStroke('5'); + break; + case KEYPAD_6: + simulated = simulateKeyStroke('6'); + break; + case KEYPAD_7: + simulated = simulateKeyStroke('7'); + break; + case KEYPAD_8: + simulated = simulateKeyStroke('8'); + break; + case KEYPAD_9: + simulated = simulateKeyStroke('9'); + break; + case KEYPAD_PERIOD: + simulated = simulateKeyStroke('.'); + break; + case KEYPAD_COMMA: + simulated = simulateKeyStroke(','); + break; + case KEYPAD_MINUS: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + int s = screenFields.getCurrentField().getFieldShift(); + if (s == 3 || s == 5 || s == 7) { + planes.setChar(lastPos,'-'); + + resetDirty(lastPos); + advancePos(); + if (fieldExit()) { + screenFields.setCurrentFieldMDT(); + if (!screenFields.isCurrentFieldContinued()) { + gotoFieldNext(); + } else { + do { + gotoFieldNext(); + } while (screenFields + .isCurrentFieldContinuedMiddle() + || screenFields + .isCurrentFieldContinuedLast()); + } + simulated = true; + updateDirty(); + if (screenFields.isCurrentFieldAutoEnter()) + sendAid(AID_ENTER); + + } + } else { + displayError(ERR_FIELD_MINUS); + + } + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case FIELD_EXIT: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + resetDirty(lastPos); + + boolean autoFE = screenFields.isCurrentFieldAutoEnter(); + + if (fieldExit()) { + screenFields.setCurrentFieldMDT(); + if (!screenFields.isCurrentFieldContinued() && + !screenFields.isCurrentFieldAutoEnter()) { + gotoFieldNext(); + } else { + do { + gotoFieldNext(); + if (screenFields.isCurrentFieldContinued()) + fieldExit(); + } while (screenFields.isCurrentFieldContinuedMiddle() + || screenFields.isCurrentFieldContinuedLast()); + } + } + + updateDirty(); + simulated = true; + if (autoFE) + sendAid(AID_ENTER); + + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case FIELD_PLUS: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + resetDirty(lastPos); + + boolean autoFE = screenFields.isCurrentFieldAutoEnter(); + if (fieldExit()) { + screenFields.setCurrentFieldMDT(); + if (!screenFields.isCurrentFieldContinued() && + !screenFields.isCurrentFieldAutoEnter()) { + gotoFieldNext(); + } else { + do { + gotoFieldNext(); + } while (screenFields.isCurrentFieldContinuedMiddle() + || screenFields.isCurrentFieldContinuedLast()); + } + } + updateDirty(); + simulated = true; + + if (autoFE) + sendAid(AID_ENTER); + + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case FIELD_MINUS: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + int s = screenFields.getCurrentField().getFieldShift(); + if (s == 3 || s == 5 || s == 7) { + planes.setChar(lastPos, '-'); + + resetDirty(lastPos); + advancePos(); + + boolean autoFE = screenFields.isCurrentFieldAutoEnter(); + + if (fieldExit()) { + screenFields.setCurrentFieldMDT(); + if (!screenFields.isCurrentFieldContinued() + && !screenFields.isCurrentFieldAutoEnter()) { + gotoFieldNext(); + } + else { + do { + gotoFieldNext(); + } + while (screenFields.isCurrentFieldContinuedMiddle() + || screenFields.isCurrentFieldContinuedLast()); + } + } + updateDirty(); + simulated = true; + if (autoFE) + sendAid(AID_ENTER); + + } + else { + displayError(ERR_FIELD_MINUS); + + } + } + else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case BOF: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + int where = screenFields.getCurrentField().startPos(); + if (where > 0) { + goto_XY(where); + } + simulated = true; + } else { + displayError(ERR_CURSOR_PROTECTED); + } + resetDirty(lastPos); + + break; + case SYSREQ: + sessionVT.systemRequest(); + simulated = true; + break; + case RESET: + if (isStatusErrorCode()) { + resetError(); + isInField(lastPos); + updateDirty(); + } else { + setPrehelpState(false, oia.isKeyBoardLocked(), false); + } + simulated = true; + break; + case ATTN: + sessionVT.sendAttentionKey(); + simulated = true; + break; + case DUP_FIELD: + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + if (screenFields.isCurrentFieldDupEnabled()) { + resetDirty(lastPos); + screenFields.getCurrentField().setFieldChar(lastPos, + (char) 0x1C); + screenFields.setCurrentFieldMDT(); + gotoFieldNext(); + updateDirty(); + simulated = true; + } else { + displayError(ERR_DUP_KEY_NOT_ALLOWED); + } + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + break; + case NEW_LINE: + if (screenFields.getSize() > 0) { + int startRow = getRow(lastPos) + 1; + int startPos = lastPos; + + if (startRow == getRows()) + startRow = 0; + + setCursor(++startRow, 1); + + if (!isInField() && screenFields.getCurrentField() != null + && !screenFields.isCurrentFieldBypassField()) { + while (!isInField() + && screenFields.getCurrentField() != null + && !screenFields.isCurrentFieldBypassField()) { + + // lets keep going + advancePos(); + + // Have we looped the screen? + if (lastPos == startPos) { + // if so then go back to starting point + goto_XY(startPos); + break; + } + } + } + } + simulated = true; + break; + case FAST_CURSOR_DOWN: + int rowNow = (getCurrentRow()-1) + 3; + if (rowNow > getRows()-1) + rowNow = rowNow - getRows(); + this.goto_XY(getPos(rowNow,getCurrentCol()-1)); + simulated = true; + break; + case FAST_CURSOR_UP: + rowNow = (getCurrentRow()-1) - 3; + if (rowNow < 0) + rowNow = (getRows()) + rowNow; + this.goto_XY(getPos(rowNow,getCurrentCol()-1)); + simulated = true; + break; + case FAST_CURSOR_LEFT: + int colNow = (getCurrentCol()-1) - 3; + rowNow = getCurrentRow()-1; + if (colNow <= 0) { + colNow = getColumns() + colNow; + rowNow--; + } + if (rowNow < 0) + rowNow = getRows() - 1; + + process_XY(getPos(rowNow,colNow)); + simulated = true; + break; + case FAST_CURSOR_RIGHT: + colNow = (getCurrentCol()-1) + 3; + rowNow = getCurrentRow()-1; + if (colNow >= getColumns()) { + colNow = colNow - getColumns(); + rowNow++; + } + if (rowNow > getRows() - 1) + rowNow = getRows() - rowNow; + + process_XY(getPos(rowNow,colNow)); + simulated = true; + break; + default: + log.info(" Mnemonic not supported " + mnem); + break; + + } + + return simulated; + } + + protected boolean simulateKeyStroke(char c) { + + if (isStatusErrorCode() && !Character.isISOControl(c) && !keyProcessed) { + if (resetRequired) return false; + resetError(); + } + + boolean updateField = false; + boolean numericError = false; + boolean updatePos = false; + boolean autoEnter = false; + + if (!Character.isISOControl(c)) { + + if (screenFields.getCurrentField() != null + && screenFields.withinCurrentField(lastPos) + && !screenFields.isCurrentFieldBypassField()) { + + if (screenFields.isCurrentFieldFER() + && !screenFields.withinCurrentField(screenFields + .getCurrentFieldPos()) + && lastPos == screenFields.getCurrentField().endPos() + && screenFields.getCurrentFieldPos() > screenFields + .getCurrentField().endPos()) { + + displayError(ERR_FIELD_EXIT_INVALID); + feError = true; + return false; + } + + switch (screenFields.getCurrentFieldShift()) { + case 0: // Alpha shift + case 2: // Numeric Shift + case 4: // Kakana Shift + updateField = true; + break; + case 1: // Alpha Only + if (Character.isLetter(c) || c == ',' || c == '-' + || c == '.' || c == ' ') + updateField = true; + break; + case 3: // Numeric only + if (Character.isDigit(c) || c == '+' || c == ',' + || c == '-' || c == '.' || c == ' ') + updateField = true; + else + numericError = true; + break; + case 5: // Digits only + if (Character.isDigit(c)) + updateField = true; + else + displayError(ERR_NUMERIC_09); + break; + case 7: // Signed numeric + if (Character.isDigit(c) || c == '+' || c == '-') + if (lastPos == screenFields.getCurrentField().endPos() + && (c != '+' && c != '-')) + displayError(ERR_INVALID_SIGN); + else + updateField = true; + else + displayError(ERR_NUMERIC_09); + break; + } + + if (updateField) { + if (screenFields.isCurrentFieldToUpper()) + c = Character.toUpperCase(c); + + updatePos = true; + resetDirty(lastPos); + + if (oia.isInsertMode()) { + if (endOfField(false) != screenFields.getCurrentField() + .endPos()) + shiftRight(lastPos); + else { + + displayError(ERR_NO_ROOM_INSERT); + updatePos = false; + } + + } + + if (updatePos) { + screenFields.getCurrentField().getKeyPos( + getRow(lastPos), getCol(lastPos)); + screenFields.getCurrentField().changePos(1); + + planes.setChar(lastPos,c); + + screenFields.setCurrentFieldMDT(); + + // if we have gone passed the end of the field then goto + // the next field + if (!screenFields.withinCurrentField(screenFields + .getCurrentFieldPos())) { + if (screenFields.isCurrentFieldAutoEnter()) { + autoEnter = true; + } else if (!screenFields.isCurrentFieldFER()) + gotoFieldNext(); + else { + // screenFields.getCurrentField().changePos(1); + // + // if (screenFields. + // cursorPos == endPos) + // System.out.println("end of field"); + // + // feError != feError; + // if (feError) + // displayError(ERR_FIELD_EXIT_INVALID); + } + + } else + setCursor(screenFields.getCurrentField() + .getCursorRow() + 1, screenFields + .getCurrentField().getCursorCol() + 1); + + } + + fireScreenChanged(1); + + if (autoEnter) + sendAid(AID_ENTER); + } else { + if (numericError) { + displayError(ERR_NUMERIC_ONLY); + } + } + } else { + displayError(ERR_CURSOR_PROTECTED); + } + + } + return updatePos; + } + + /** + * Method: endOfField + *

+ * + * convenience method that call endOfField with lastRow lastCol and passes + * the posSpace to that method + * + * @param posSpace + * value of type boolean - specifying to return the position of + * the the last space or not + * @return a value of type int - the screen postion (row * columns) + col + * + */ + private int endOfField(boolean posSpace) { + return endOfField(lastPos, posSpace); + } + + /** + * Method: endOfField + *

+ * + * gets the position of the last character of the current field posSpace + * parameter tells the routine whether to return the position of the last + * space ( <= ' ') or the last non space posSpace == true last occurrence of + * char <= ' ' posSpace == false last occurrence of char > ' ' + * + * @param pos + * value of type int - position to start from + * @param posSpace + * value of type boolean - specifying to return the position of + * the the last space or not + * @return a value of type int - the screen postion (row * columns) + col + * + */ + private int endOfField(int pos, boolean posSpace) { + + int endPos = screenFields.getCurrentField().endPos(); + int fePos = endPos; + // get the number of characters to the right + int count = endPos - pos; + + // first lets get the real ending point without spaces and the such + while (planes.getChar(endPos) <= ' ' && count-- > 0) { + + endPos--; + } + + if (endPos == fePos) { + + return endPos; + + } + screenFields.getCurrentField().getKeyPos(endPos); + if (posSpace) screenFields.getCurrentField().changePos(+1); + return screenFields.getCurrentFieldPos(); + + } + + private boolean fieldExit() { + + int pos = lastPos; + boolean mdt = false; + int end = endOfField(false); // get the ending position of the first + // non blank character in field + + ScreenField sf = screenFields.getCurrentField(); + + if (sf.isMandatoryEnter() && end == sf.startPos()) { + displayError(ERR_MANDITORY_ENTER); + return false; + } + + // save off the current pos of the field for checking field exit required + // positioning. the getKeyPos resets this information so it is useless + // for comparing if we are positioned passed the end of field. + // Maybe this should be changed to not update the current cursor position + // of the field. + int currentPos = sf.getCurrentPos(); + + // get the number of characters to the right + int count = (end - sf.startPos()) - sf.getKeyPos(pos); + + if (count == 0 && sf.isFER()) { + if (currentPos > sf.endPos()) { + mdt = true; + return mdt; + } + } + + for (; count >= 0; count--) { + planes.setChar(pos, initChar); + setDirty(pos); + pos++; + mdt = true; + } + + // This checks for a field minus because a field minus places + // a negative sign and then advances a position. If it is the + // end of the field where the minus is placed then this offset will + // place the count as -1. + if (count == -1) { + int s = sf.getFieldShift(); + if (s == 3 || s == 5 || s == 7) { + mdt = true; + } + } + + int adj = sf.getAdjustment(); + + if (adj != 0) { + + switch (adj) { + + case 5: + rightAdjustField('0'); + sf.setRightAdjusted(); + break; + case 6: + rightAdjustField(' '); + sf.setRightAdjusted(); + + break; + case 7: + sf.setManditoryEntered(); + break; + + } + } + else { + + // we need to right adjust signed numeric fields as well. + if (sf.isSignedNumeric()) { + rightAdjustField(' '); + } + } + + return mdt; + } + + private void rightAdjustField(char fill) { + + int end = endOfField(false); // get the ending position of the first + // non blank character in field + + // get the number of characters to the right + int count = screenFields.getCurrentField().endPos() - end; + + // subtract 1 from count for signed numeric - note for later + if (screenFields.getCurrentField().isSignedNumeric()) { + if (planes.getChar(end -1) != '-') + count--; + } + + int pos = screenFields.getCurrentField().startPos(); + + while (count-- >= 0) { + + shiftRight(pos); + planes.setChar(pos,fill); + + setDirty(pos); + + } + + } + + private void shiftLeft(int sPos) { + + int endPos = 0; + + int pos = sPos; + int pPos = sPos; + + ScreenField sf = screenFields.getCurrentField(); + int end; + int count; + do { + end = endOfField(pPos, false); // get the ending position of the + // first + // non blank character in field + + count = (end - screenFields.getCurrentField().startPos()) + - screenFields.getCurrentField().getKeyPos(pPos); + + // now we loop through and shift the remaining characters to the + // left + while (count-- > 0) { + pos++; + planes.setChar(pPos,planes.getChar(pos)); + setDirty(pPos); + pPos = pos; + + } + + if (screenFields.isCurrentFieldContinued()) { + gotoFieldNext(); + if (screenFields.getCurrentField().isContinuedFirst()) + break; + + pos = screenFields.getCurrentField().startPos(); + planes.setChar(pPos,planes.getChar(pos)); + setDirty(pPos); + + pPos = pos; + + } + } while (screenFields.isCurrentFieldContinued() + && !screenFields.getCurrentField().isContinuedFirst()); + + if (end >= 0 && count >= -1) { + + endPos = end; + } else { + endPos = sPos; + + } + + screenFields.setCurrentField(sf); + planes.setChar(endPos,initChar); + setDirty(endPos); + goto_XY(screenFields.getCurrentFieldPos()); + sf = null; + + } + + private void shiftRight(int sPos) { + + int end = endOfField(true); // get the ending position of the first + // non blank character in field + int pos = end; + int pPos = end; + + int count = end - sPos; + + // now we loop through and shift the remaining characters to the right + while (count-- > 0) { + + pos--; + planes.setChar(pPos, planes.getChar(pos)); + setDirty(pPos); + + pPos = pos; + } + } + + public int getRow(int pos) { + + // if (pos == 0) + // return 1; + + int row = pos / numCols; + + if (row < 0) { + + row = lastPos / numCols; + } + if (row > (lenScreen / numCols) - 1) + row = (lenScreen / numCols) - 1; + + return row; + + } + + public int getCol(int pos) { + int col = pos % (getColumns()); + if (col > 0) return col; + return 0; + } + + /** + * This routine is 0 based offset. So to get row 20,1 then pass row 19,0 + * + * @param row + * @param col + * @return + */ + public int getPos(int row, int col) { + + return (row * numCols) + col; + } + + /** + * Current position is based on offsets of 1,1 not 0,0 of the current + * position of the screen + * + * @return int + */ + public int getCurrentPos() { + + // return lastPos + numCols + 1; + return lastPos + 1; + + } + + /** + * I got this information from a tcp trace of each error. I could not find + * any documenation for this. Maybe there is but I could not find it. If + * anybody finds this documention could you please send me a copy. Please + * note that I did not look that hard either. + *

+ * 0000: 00 50 73 1D 89 81 00 50 DA 44 C8 45 08 00 45 00 .Ps....P.D.E..E. + *

+ *

+ * 0010: 00 36 E9 1C 40 00 80 06 9B F9 C1 A8 33 58 C0 A8 .6..@...k....3X.. + *

+ *

+ * 0020: C0 02 06 0E 00 17 00 52 6E 88 73 40 DE CB 50 18 .......Rn.s@..P. + *

+ *

+ * 0030: 20 12 3C 53 00 00 00 0C 12 A0 00 00 04 01 00 00 . + *

+ * 0040: 00 05 FF EF .... ----------|| The 00 XX is the code to be sent. I + * found the following + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ERR_CURSOR_PROTECTED0x05
ERR_INVALID_SIGN0x11
ERR_NO_ROOM_INSERT0x12
ERR_NUMERIC_ONLY0x09
ERR_NUMERIC_090x10
ERR_FIELD_MINUS0x16
ERR_ENTER_NOT_ALLOWED0x20
ERR_MANDITORY_ENTER0x21
ERR_ENTER_NOT_ALLOWED0x20
I am tired of typing and they should be self explanitory. Finding + * them in the first place was the pain. + *

+ * + * @param ec error code + */ + private void displayError(int ec) { + saveHomePos = homePos; + homePos = lastPos + numCols + 1; + pendingInsert = true; + sessionVT.sendNegResponse2(ec); + + } + + private void process_XY(int pos) { + + if (pos < 0) + pos = lenScreen + pos; + if (pos > lenScreen - 1) + pos = pos - lenScreen; + + // if there was a field exit error then we need to treat the movement + // of the cursor in a special way that equals that of Client Access. + // If the cursor is moved from the field then we need to reset the + // position within the field so that the last character can be typed + // over again instead of sending the field exit error again. + // We also need to reset the field exit error flag. + // + // How we know we have a field exit error is when the field position is + // set beyond the end of the field and a character is then typed we can + // not position that character. To reset this we need to set the next + // position of the field to not be beyond the end of field but to the + // last character. + // + // Now to make it work like Client Access if the cursor is a back space + // then do not move the cursor but place it on the last field. All + // other keys will reset the field position so that entering over the + // last character will not cause an error but replace that character or + // just plain move the cursor if the key was to do that. + + ScreenField sf = screenFields.getCurrentField(); + if (feError) { + feError = false; + sf.changePos(-1); + } else { + if (sf != null&& sf.isFER()){ + if ((sf.getCurrentPos() + > sf.endPos())) { + if (sf.withinField(pos)) { + sf.getKeyPos(pos); + return; + } + sf.getKeyPos(sf.endPos()); + } + } + + goto_XY(pos); + } + } + + public boolean isUsingGuiInterface() { + + return guiInterface; + } + + /** + * Convinience class to return if the cursor is in a field or not. + * + * @return true or false + */ + + protected boolean isInField() { + + return isInField(lastPos, true); + } + + /** + * + * Convinience class to return if the position that is passed is in a field + * or not. If it is then the chgToField parameter will change the current + * field to this field where the position indicates + * + * @param pos + * @param chgToField + * @return true or false + */ + public boolean isInField(int pos, boolean chgToField) { + + return screenFields.isInField(pos, chgToField); + } + + /** + * + * Convinience class to return if the position that is passed is in a field + * or not. If it is then the field at this position becomes the current + * working field + * + * @param pos + * @return true or false + */ + public boolean isInField(int pos) { + + return screenFields.isInField(pos, true); + } + + /** + * Convinience class to return if the position at row and column that is + * passed is in a field or not. If it is then the field at this position + * becomes the current working field. + * + * @param row + * @param col + * @return true or false + */ + public boolean isInField(int row, int col) { + + return isInField(row, col, true); + } + + /** + * + * Convinience class to return if the position at row and column that is + * passed is in a field or not. If it is then the chgToField parameter will + * change the current field to this field where the row and column + * indicates. + * + * @param row + * @param col + * @param chgToField + * @return true or false + */ + public boolean isInField(int row, int col, boolean chgToField) { + return screenFields.isInField((row * numCols) + col, chgToField); + } + + /** + * Gets the length of the screen - number of rows times number of columns + * + * @return int value of screen length + */ + public int getScreenLength() { + + return lenScreen; + } + + /** + * Get the number or rows available. + * + * @return number of rows + */ + public int getRows() { + + return numRows; + + } + + /** + * Get the number of columns available. + * + * @return number of columns + */ + public int getColumns() { + + return numCols; + + } + + /** + * Get the current row where the cursor is + * + * @return the cursor current row position 1,1 based + */ + public int getCurrentRow() { + + return (lastPos / numCols) + 1; + + } + + /** + * Get the current column where the cursor is + * + * @return the cursor current column position 1,1 based + */ + public int getCurrentCol() { + + return (lastPos % numCols) + 1; + + } + + /** + * The last position of the cursor on the screen - Note - position is based + * 0,0 + * + * @return last position + */ + protected int getLastPos() { + + return lastPos; + + } + + /** + * Hotspot More... string + * + * @return string literal of More... + */ + public StringBuffer getHSMore() { + return hsMore; + } + + /** + * Hotspot Bottom string + * + * @return string literal of Bottom + */ + public StringBuffer getHSBottom() { + return hsBottom; + } + + /** + * Return the whole screen represented as a character array + * + * @return character array containing the text + * + * Added by Luc - LDC + * + * Note to KJP - Have to ask what the difference is between this method and + * the other + */ + public char[] getScreenAsAllChars() { + char[] sac = new char[lenScreen]; + char c; + + for (int x = 0; x < lenScreen; x++) { + c = planes.getChar(x); + // only draw printable characters (in this case >= ' ') + if ((c >= ' ') && (!planes.isAttributePlace(x))) { + sac[x] = c; + // TODO: implement the underline check here + // if (screen[x].underLine && c <= ' ') + // sac[x] = '_'; + } else + sac[x] = ' '; + } + + return sac; + } + + /** + * + * Return the screen represented as a character array + * + * @return character array containing the text + */ + public char[] getScreenAsChars() { + char[] sac = new char[lenScreen]; + char c; + + for (int x = 0; x < lenScreen; x++) { + c = planes.getChar(x); + // only draw printable characters (in this case >= ' ') + if ((c >= ' ') && (!planes.isAttributePlace(x))) { + sac[x] = c; + // TODO: implement the underline check here + // if (screen[x].underLine && c <= ' ') + // sac[x] = '_'; + } else + sac[x] = ' '; + } + + return sac; + } + + public char[] getData(int startRow, int startCol, int endRow, int endCol, int plane) { + try { + int from = getPos(startRow,startCol); + int to = getPos(endRow,endCol); + if (from > to) { + + int f = from; + to = f; + from = f; + } + return planes.getPlaneData(from,to,plane); + } + catch (Exception oe) { + return null; + } + + } + + /** + *

+ * GetScreen retrieves the various planes associated with the presentation + * space. The data is returned as a linear array of character values in the + * array provided. The array is not terminated by a null character except + * when data is retrieved from the text plane, in which case a single null + * character is appended. + *

+ *

+ * The application must supply a buffer for the returned data and the length + * of the buffer. Data is returned starting from the beginning of the + * presentation space and continuing until the buffer is full or the entire + * plane has been copied. For text plane data, the buffer must include one + * extra position for the terminating null character. + *

+ * + * @param buffer + * @param bufferLength + * @param plane + * @return The number of characters copied to the buffer + * @throws OhioException + */ + public synchronized int GetScreen(char buffer[], int bufferLength, int plane) + // throws OhioException { + { + return GetScreen(buffer,bufferLength,0,lenScreen,plane); + + } + + /** + *

+ * GetScreen retrieves the various planes associated with the presentation + * space. The data is returned as a linear array of character values in the + * array provided. The array is not terminated by a null character except + * when data is retrieved from the text plane, in which case a single null + * character is appended. + *

+ *

+ * The application must supply a buffer for the returned data and the length + * of the buffer. Data is returned starting from the given position and + * continuing until the specified number of characters have been copied, the + * buffer is full or the entire plane has been copied. For text plane data, + * the buffer must include one extra position for the terminating null character. + *

+ * + * @param buffer + * @param bufferLength + * @param from + * @param length + * @param plane + * @return The number of characters copied to the buffer + * @throws OhioException + */ + public synchronized int GetScreen(char buffer[], int bufferLength, int from, + int length, int plane) + // throws OhioException { + { + + return planes.GetScreen(buffer,bufferLength, from, length, plane); + } + + /** + *

+ * GetScreen retrieves the various planes associated with the presentation + * space. The data is returned as a linear array of character values in the + * array provided. The array is not terminated by a null character except + * when data is retrieved from the text plane, in which case a single null + * character is appended. + *

+ *

+ * The application must supply a buffer for the returned data and the length + * of the buffer. Data is returned starting from the given coordinates and + * continuing until the specified number of characters have been copied, + * the buffer is full, or the entire plane has been copied. For text plane + * data, the buffer must include one extra position for the terminating null + * character. + *

+ * + * @param buffer + * @param bufferLength + * @param row + * @param col + * @param length + * @param plane + * @return The number of characters copied to the buffer. + * @throws OhioException + */ + public synchronized int GetScreen(char buffer[], int bufferLength, int row, + int col, int length, int plane) + // throws OhioException { + { + // Call GetScreen function after converting row and column to + // a position. + return planes.GetScreen(buffer,bufferLength, row, col, length, plane); + } + + /** + *

+ * GetScreenRect retrieves data from the various planes associated with the + * presentation space. The data is returned as a linear array of character + * values in the buffer provided. + *

+ * + *

+ * The application supplies two positions that represent opposing corners of + * a rectangle within the presentation space. The starting and ending + * positions can have any spatial relationship to each other. The data + * returned starts from the row containing the upper-most point to the row + * containing the lower-most point, and from the left-most column to the + * right-most column. + *

+ *

+ * The specified buffer must be at least large enough to contain the number + * of characters in the rectangle. If the buffer is too small, no data is + * copied and zero is returned by the method. Otherwise, the method returns + * the number of characters copied. + *

+ * + * @param buffer + * @param bufferLength + * @param startPos + * @param endPos + * @param plane + * @return The number of characters copied to the buffer + * @throws OhioException + */ + public synchronized int GetScreenRect(char buffer[], int bufferLength, + int startPos, int endPos, int plane) + // throws OhioException { + { + return planes.GetScreenRect(buffer, bufferLength, startPos, endPos, plane); + + } + + /** + *

+ * GetScreenRect retrieves data from the various planes associated with the + * presentation space. The data is returned as a linear array of character + * values in the buffer provided. The buffer is not terminated by a null + * character. + *

+ *

+ * The application supplies two coordinates that represent opposing corners + * of a rectangle within the presentation space. The starting and ending + * coordinates can have any spatial relationship to each other. The data + * returned starts from the row containing the upper-most point to the row + * containing the lower-most point, and from the left-most column to the + * right-most column. + *

+ *

+ * The specified buffer must be at least large enough to contain the number + * of characters in the rectangle. If the buffer is too small, no data is + * copied and zero is returned by the method. Otherwise, the method returns + * the number of characters copied. + *

+ * + * @param buffer + * @param bufferLength + * @param startRow + * @param startCol + * @param endRow + * @param endCol + * @param plane + * @return The number characters copied to the buffer + * @throws OhioException + */ + public synchronized int GetScreenRect(char buffer[], int bufferLength, + int startRow, int startCol, + int endRow, int endCol, int plane) + // throws OhioException { + { + + return planes.GetScreenRect(buffer, bufferLength, startRow, startCol, endRow, + endCol, plane); + } + + public synchronized boolean[] getActiveAidKeys() { + return sessionVT.getActiveAidKeys(); + } + + protected synchronized void setScreenData(String text, int location) { + // throws OhioException { + + if (location < 0 || location > lenScreen) { + return; + // throw new OhioException(sessionVT.getSessionConfiguration(), + // OhioScreen5250.class.getName(), "osohio.screen.ohio00300", 1); + } + + int pos = location; + + int l = text.length(); + boolean updated = false; + boolean flag = false; + int x =0; + for (; x < l; x++) { + if (isInField(pos + x,true)) { + if (!screenFields.getCurrentField().isBypassField()) { + if (!flag) { + screenFields.getCurrentField().setMDT(); + updated = true; + resetDirty(pos + x); + screenFields.setMasterMDT(); + flag = true; + } + + planes.screen[pos + x] = text.charAt(x); + setDirty(pos + x); + } + } + + } + lastPos = pos + x; + if (updated) { + fireScreenChanged(1); + } + + } + + /** + * This routine is based on offset 1,1 not 0,0 it will translate to offset + * 0,0 and call the goto_XY(int pos) it is mostly used from external classes + * that use the 1,1 offset + * + * @param row + * @param col + */ + public void setCursor(int row, int col) { + goto_XY(((row - 1) * numCols) + (col - 1)); + } + + // this routine is based on offset 0,0 not 1,1 + protected void goto_XY(int pos) { + // setCursorOff(); + updateCursorLoc(); + lastPos = pos; + // setCursorOn(); + updateCursorLoc(); + } + + /** + * Set the current working field to the field number specified. + * + * @param f - + * numeric field number on the screen + * @return true or false whether it was sucessful + */ + public boolean gotoField(int f) { + + int sizeFields = screenFields.getSize(); + + if (f > sizeFields || f <= 0) + return false; + + screenFields.setCurrentField(screenFields.getField(f - 1)); + + while (screenFields.isCurrentFieldBypassField() && f < sizeFields) { + + screenFields.setCurrentField(screenFields.getField(f++)); + + } + return gotoField(screenFields.getCurrentField()); + } + + /** + * Convenience method to set the field object passed as the currect working + * screen field + * + * @param f + * @return true or false whether it was sucessful + * @see org.tn5250j.ScreenField + */ + protected boolean gotoField(ScreenField f) { + if (f != null) { + goto_XY(f.startPos()); + return true; + } + return false; + } + + /** + * Convenience class to position the cursor to the next word on the screen + * + */ + private void gotoNextWord() { + + int pos = lastPos; + + if (planes.getChar(lastPos) > ' ') { + advancePos(); + // get the next space character + while (planes.getChar(lastPos) > ' ' && pos != lastPos) { + advancePos(); + } + } else + advancePos(); + + // now that we are positioned on the next space character get the + // next none space character + while (planes.getChar(lastPos) <= ' ' && pos != lastPos) { + advancePos(); + } + + } + + /** + * Convenience class to position the cursor to the previous word on the + * screen + * + */ + private void gotoPrevWord() { + + int pos = lastPos; + + changePos(-1); + + // position previous white space character + while (planes.getChar(lastPos) <= ' ') { + changePos(-1); + if (pos == lastPos) + break; + } + + changePos(-1); + // get the previous space character + while (planes.getChar(lastPos) > ' ' && pos != lastPos) { + changePos(-1); + } + + // and position one position more should give us the beginning of word + advancePos(); + + } + + /** + * Convinience class to position to the next field on the screen. + * + * @see org.tn5250j.ScreenFields + */ + private void gotoFieldNext() { + + if (screenFields.isCurrentFieldHighlightedEntry()) + unsetFieldHighlighted(screenFields.getCurrentField()); + + screenFields.gotoFieldNext(); + + if (screenFields.isCurrentFieldHighlightedEntry()) + setFieldHighlighted(screenFields.getCurrentField()); + } + + /** + * Convinience class to position to the previous field on the screen. + * + * @see org.tn5250j.ScreenFields + */ + private void gotoFieldPrev() { + + if (screenFields.isCurrentFieldHighlightedEntry()) + unsetFieldHighlighted(screenFields.getCurrentField()); + + screenFields.gotoFieldPrev(); + + if (screenFields.isCurrentFieldHighlightedEntry()) + setFieldHighlighted(screenFields.getCurrentField()); + + } + + /* *** NEVER USED LOCALLY ************************************************** */ + // /** + // * Used to restrict the cursor to a particular position on the screen. Used + // * in combination with windows to restrict the cursor to the active window + // * show on the screen. + // * + // * Not supported yet. Please implement me :-( + // * + // * @param depth + // * @param width + // */ + // protected void setRestrictCursor(int depth, int width) { + // + // restrictCursor = true; + // // restriction + // + // } + + /** + * Creates a window on the screen + * + * @param depth + * @param width + * @param type + * @param gui + * @param monoAttr + * @param colorAttr + * @param ul + * @param upper + * @param ur + * @param left + * @param right + * @param ll + * @param bottom + * @param lr + */ + protected void createWindow(int depth, int width, int type, boolean gui, + int monoAttr, int colorAttr, int ul, int upper, int ur, int left, + int right, int ll, int bottom, int lr) { + + int c = getCol(lastPos); + int w = 0; + width++; + + w = width; + // set leading attribute byte + // screen[lastPos].setCharAndAttr(initChar, initAttr, true); + planes.setScreenCharAndAttr(lastPos, initChar, initAttr, true); + setDirty(lastPos); + + advancePos(); + // set upper left + // screen[lastPos].setCharAndAttr((char) ul, colorAttr, false); + planes.setScreenCharAndAttr(lastPos, (char) ul, colorAttr, false); + if (gui) { + // screen[lastPos].setUseGUI(UPPER_LEFT); + planes.setUseGUI(lastPos, UPPER_LEFT); + } + setDirty(lastPos); + + advancePos(); + + // draw top row + + while (w-- >= 0) { + // screen[lastPos].setCharAndAttr((char) upper, colorAttr, false); + planes.setScreenCharAndAttr(lastPos, (char) upper, colorAttr, false); + if (gui) { + // screen[lastPos].setUseGUI(UPPER); + planes.setUseGUI(lastPos,UPPER); + } + setDirty(lastPos); + advancePos(); + } + + // set upper right + // screen[lastPos].setCharAndAttr((char) ur, colorAttr, false); + planes.setScreenCharAndAttr(lastPos,(char) ur, colorAttr, false); + + if (gui) { + // screen[lastPos].setUseGUI(UPPER_RIGHT); + planes.setUseGUI(lastPos, UPPER_RIGHT); + } + setDirty(lastPos); + advancePos(); + + // set ending attribute byte + planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); + + setDirty(lastPos); + + lastPos = ((getRow(lastPos) + 1) * numCols) + c; + + // now handle body of window + while (depth-- > 0) { + + // set leading attribute byte + planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); + setDirty(lastPos); + advancePos(); + + // set left + planes.setScreenCharAndAttr(lastPos, (char) left, colorAttr, false); + + if (gui) { + planes.setUseGUI(lastPos,GUI_LEFT); + } + setDirty(lastPos); + advancePos(); + + w = width; + // fill it in + while (w-- >= 0) { + // screen[lastPos].setCharAndAttr(initChar, initAttr, true); + planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); + // screen[lastPos].setUseGUI(NO_GUI); + planes.setUseGUI(lastPos,NO_GUI); + setDirty(lastPos); + advancePos(); + } + + // set right + // screen[lastPos].setCharAndAttr((char) right, colorAttr, false); + planes.setScreenCharAndAttr(lastPos,(char) right, colorAttr, false); + if (gui) { + // screen[lastPos].setUseGUI(RIGHT); + planes.setUseGUI(lastPos,GUI_RIGHT); + } + + setDirty(lastPos); + advancePos(); + + // set ending attribute byte + // screen[lastPos].setCharAndAttr(initChar, initAttr, true); + planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); + setDirty(lastPos); + + lastPos = ((getRow(lastPos) + 1) * numCols) + c; + } + + // set leading attribute byte + // screen[lastPos].setCharAndAttr(initChar, initAttr, true); + planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); + setDirty(lastPos); + advancePos(); + + // set lower left + // screen[lastPos].setCharAndAttr((char) ll, colorAttr, false); + planes.setScreenCharAndAttr(lastPos,(char) ll, colorAttr, false); + if (gui) { + // screen[lastPos].setUseGUI(LOWER_LEFT); + planes.setUseGUI(lastPos,LOWER_LEFT); + } + setDirty(lastPos); + advancePos(); + + w = width; + + // draw bottom row + while (w-- >= 0) { + planes.setScreenCharAndAttr(lastPos,(char) bottom, colorAttr, false); + if (gui) { + planes.setUseGUI(lastPos,BOTTOM); + } + setDirty(lastPos); + advancePos(); + } + + // set lower right + planes.setScreenCharAndAttr(lastPos, (char) lr, colorAttr, false); + if (gui) { + planes.setUseGUI(lastPos,LOWER_RIGHT); + } + + setDirty(lastPos); + advancePos(); + + // set ending attribute byte + planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); + setDirty(lastPos); + + } + + /** + * Creates a scroll bar on the screen using the parameters provided. + * ** we only support vertical scroll bars at the time. + * + * @param flag - + * type to draw - vertical or horizontal + * @param totalRowScrollable + * @param totalColScrollable + * @param sliderRowPos + * @param sliderColPos + * @param sbSize + */ + protected void createScrollBar(int flag, int totalRowScrollable, + int totalColScrollable, int sliderRowPos, int sliderColPos, + int sbSize) { + + // System.out.println("Scrollbar flag: " + flag + + // " scrollable Rows: " + totalRowScrollable + + // " scrollable Cols: " + totalColScrollable + + // " thumb Row: " + sliderRowPos + + // " thumb Col: " + sliderColPos + + // " size: " + sbSize + + // " row: " + getRow(lastPos) + + // " col: " + getCol(lastPos)); + + int sp = lastPos; + int size = sbSize - 2; + + int thumbPos = (int) (size * ((float) sliderColPos / (float) totalColScrollable)); + // System.out.println(thumbPos); + planes.setScreenCharAndAttr(sp,' ', 32, false); + planes.setUseGUI(sp,BUTTON_SB_UP); + + int ctr = 0; + while (ctr < size) { + sp += numCols; + planes.setScreenCharAndAttr(sp,' ', 32, false); + if (ctr == thumbPos) + planes.setUseGUI(sp,BUTTON_SB_THUMB); + else + planes.setUseGUI(sp, BUTTON_SB_GUIDE); + ctr++; + } + sp += numCols; + + + planes.setScreenCharAndAttr(sp, ' ', 32, false); + planes.setUseGUI(sp, BUTTON_SB_DN); + } + + /** + * Write the title of the window that is on the screen + * + * @param pos + * @param depth + * @param width + * @param orientation + * @param monoAttr + * @param colorAttr + * @param title + */ + protected void writeWindowTitle(int pos, int depth, int width, + byte orientation, int monoAttr, int colorAttr, StringBuffer title) { + + int len = title.length(); + + // get bit 0 and 1 for interrogation + switch (orientation & 0xc0) { + case 0x40: // right + pos += (4 + width - len); + break; + case 0x80: // left + pos += 2; + break; + default: // center + // this is to place the position to the first text position of the + // window + // the position passed in is the first attribute position, the next + // is the border character and then there is another attribute after + // that. + pos += (3 + ((width / 2) - (len / 2))); + break; + + } + + // if bit 2 is on then this is a footer + if ((orientation & 0x20) == 0x20) + pos += ((depth + 1) * numCols); + + // System.out.println(pos + "," + width + "," + len+ "," + getRow(pos) + // + "," + getCol(pos) + "," + ((orientation >> 6) & 0xf0)); + + for (int x = 0; x < len; x++) { + planes.setChar(pos, title.charAt(x)); + planes.setUseGUI(pos++, NO_GUI); + + } + } + + /** + * Roll the screen up or down. + * + * Byte 1: Bit 0 0 = Roll up 1 = Roll down Bits 1-2 Reserved Bits 3-7 Number + * of lines that the designated area is to be rolled Byte 2: Bits 0-7 Line + * number defining the top line of the area that will participate in the + * roll. Byte 3: Bits 0-7 Line number defining the bottom line of the area + * that will participate in the roll. + * + * @param direction + * @param topLine + * @param bottomLine + */ + protected void rollScreen(int direction, int topLine, int bottomLine) { + + // get the number of lines which are the last 5 bits + /* int lines = direction & 0x7F; */ + // get the direction of the roll which is the first bit + // 0 - up + // 1 - down + int updown = direction & 0x80; + final int lines = direction & 0x7F; + + // calculate the reference points for the move. + int start = this.getPos(topLine - 1, 0); + int end = this.getPos(bottomLine - 1, numCols - 1); + int len = end - start; + + // System.out.println(" starting roll"); + // dumpScreen(); + switch (updown) { + case 0: + // Now round em up and head em UP. + for (int x = start; x < end + numCols; x++) { + if (x + lines * numCols >= lenScreen) { + //Clear at the end + planes.setChar(x, ' '); + } else { + planes.setChar(x, planes.getChar(x + lines * numCols )); + } + } + break; + case 1: + // Now round em up and head em DOWN. + for (int x = end + numCols; x > 0; x--) { + if ((x - lines * numCols ) < 0 ) { + //Do nothing ... tooo small!!! + } else { + planes.setChar(x - lines * numCols, planes.getChar(x)); + //and clear + planes.setChar(x, ' '); + } + } + break; + default: + log.warn(" Invalid roll parameter - please report this"); + } + // System.out.println(" end roll"); + // dumpScreen(); + + } + + public void dumpScreen() { + + StringBuffer sb = new StringBuffer(); + char[] s = getScreenAsChars(); + int c = getColumns(); + int l = getRows() * c; + int col = 0; + for (int x = 0; x < l; x++, col++) { + sb.append(s[x]); + if (col == c) { + sb.append('\n'); + col = 0; + } + } + log.info(sb.toString()); + + } + + /** + * Add a field to the field format table. + * + * @param attr - Field attribute + * @param len - length of field + * @param ffw1 - Field format word 1 + * @param ffw2 - Field format word 2 + * @param fcw1 - Field control word 1 + * @param fcw2 - Field control word 2 + */ + protected void addField(int attr, int len, int ffw1, int ffw2, int fcw1, + int fcw2) { + + lastAttr = attr; + + planes.setScreenCharAndAttr(lastPos, initChar, lastAttr, true); + + setDirty(lastPos); + + advancePos(); + + ScreenField sf = null; + + // from 14.6.12 for Start of Field Order 5940 function manual + // examine the format table for an entry that begins at the current + // starting address plus 1. + if (screenFields.existsAtPos(lastPos)) { + screenFields.setCurrentFieldFFWs(ffw1, ffw2); + } else { + sf = screenFields.setField(attr, getRow(lastPos), getCol(lastPos), + len, ffw1, ffw2, fcw1, fcw2); + lastPos = sf.startPos(); + int x = len; + + boolean gui = guiInterface; + if (sf.isBypassField()) + gui = false; + + while (x-- > 0) { + + if (planes.getChar(lastPos) == 0) + planes.setScreenCharAndAttr(lastPos, ' ', lastAttr, false); + else + planes.setScreenAttr(lastPos,lastAttr); + + if (gui) { + planes.setUseGUI(lastPos,FIELD_MIDDLE); + } + + // now we set the field plane attributes + planes.setScreenFieldAttr(lastPos,ffw1); + + advancePos(); + + } + + if (gui) + if (len > 1) { + planes.setUseGUI(sf.startPos(), FIELD_LEFT); + + if (lastPos > 0) + planes.setUseGUI(lastPos - 1, FIELD_RIGHT); + else + planes.setUseGUI(lastPos,FIELD_RIGHT); + + } + else { + planes.setUseGUI(lastPos - 1,FIELD_ONE); + } + + // screen[lastPos].setCharAndAttr(initChar,initAttr,true); + setEndingAttr(initAttr); + + lastPos = sf.startPos(); + } + + // if (fcw1 != 0 || fcw2 != 0) { + + // System.out.println("lr = " + lastRow + " lc = " + lastCol + " " + + // sf.toString()); + // } + sf = null; + + } + + + // public void addChoiceField(int attr, int len, int ffw1, int ffw2, int + // fcw1, int fcw2) { + // + // lastAttr = attr; + // + // screen[lastPos].setCharAndAttr(initChar,lastAttr,true); + // setDirty(lastPos); + // + // advancePos(); + // + // boolean found = false; + // ScreenField sf = null; + // + // // from 14.6.12 for Start of Field Order 5940 function manual + // // examine the format table for an entry that begins at the current + // // starting address plus 1. + // for (int x = 0;x < sizeFields; x++) { + // sf = screenFields[x]; + // + // if (lastPos == sf.startPos()) { + // screenFields.getCurrentField() = sf; + // screenFields.getCurrentField().setFFWs(ffw1,ffw2); + // found = true; + // } + // + // } + // + // if (!found) { + // sf = + // setField(attr,getRow(lastPos),getCol(lastPos),len,ffw1,ffw2,fcw1,fcw2); + // + // lastPos = sf.startPos(); + // int x = len; + // + // boolean gui = guiInterface; + // if (sf.isBypassField()) + // gui = false; + // + // while (x-- > 0) { + // + // if (screen[lastPos].getChar() == 0) + // screen[lastPos].setCharAndAttr(' ',lastAttr,false); + // else + // screen[lastPos].setAttribute(lastAttr); + // + // if (gui) + // screen[lastPos].setUseGUI(FIELD_MIDDLE); + // + // advancePos(); + // + // } + // + // if (gui) + // if (len > 1) { + // screen[sf.startPos()].setUseGUI(FIELD_LEFT); + // if (lastPos > 0) + // screen[lastPos-1].setUseGUI(FIELD_RIGHT); + // else + // screen[lastPos].setUseGUI(FIELD_RIGHT); + // + // } + // else + // screen[lastPos-1].setUseGUI(FIELD_ONE); + // + // setEndingAttr(initAttr); + // + // lastPos = sf.startPos(); + // } + // + // // if (fcw1 != 0 || fcw2 != 0) { + // // + // // System.out.println("lr = " + lastRow + " lc = " + lastCol + " " + + // sf.toString()); + // // } + // sf = null; + // + // } + + /** + * Return the fields that are contained in the Field Format Table + * + * @return ScreenFields object + * @see org.tn5250j.ScreenFields + */ + public ScreenFields getScreenFields() { + return screenFields; + } + + /** + * Redraw the fields on the screen. Used for gui enhancement to redraw the + * fields when toggling + * + */ + protected void drawFields() { + + ScreenField sf; + + int sizeFields = screenFields.getSize(); + for (int x = 0; x < sizeFields; x++) { + + sf = screenFields.getField(x); + + if (!sf.isBypassField()) { + int pos = sf.startPos(); + + int l = sf.length; + + boolean f = true; + + if (l >= lenScreen) + l = lenScreen - 1; + + if (l > 1) { + while (l-- > 0) { + + if (guiInterface && f) { + planes.setUseGUI(pos,FIELD_LEFT); + f = false; + } else { + + planes.setUseGUI(pos,FIELD_MIDDLE); + + } + + if (guiInterface && l == 0) { + planes.setUseGUI(pos,FIELD_RIGHT); + } + + setDirty(pos++); + } + } else { + planes.setUseGUI(pos,FIELD_ONE); + } + } + } + + //updateDirty(); + } + + /** + * Draws the field on the screen. Used to redraw or change the attributes of + * the field. + * + * @param sf - + * Field to be redrawn + * @see org.tn5250j.ScreenField.java + */ + protected void drawField(ScreenField sf) { + + int pos = sf.startPos(); + + int x = sf.length; + + while (x-- > 0) { + setDirty(pos++); + } + + updateDirty(); + + } + + /** + * Set the field to be displayed as highlighted. + * + * @param sf - + * Field to be highlighted + */ + protected void setFieldHighlighted(ScreenField sf) { + + int pos = sf.startPos(); + + int x = sf.length; + int na = sf.getHighlightedAttr(); + + while (x-- > 0) { + planes.setScreenAttr(pos,na); + setDirty(pos++); + } + fireScreenChanged(1); + + } + + /** + * Draw the field as un higlighted. This is used to reset the field + * presentation on the screen after the field is exited. + * + * @param sf - + * Field to be unhighlighted + */ + protected void unsetFieldHighlighted(ScreenField sf) { + + int pos = sf.startPos(); + + int x = sf.length; + int na = sf.getAttr(); + + while (x-- > 0) { + planes.setScreenAttr(pos,na); + setDirty(pos++); + } + fireScreenChanged(1); + + } + + public boolean checkHotSpots() { + + return planes.checkHotSpots(); + } + + protected void setChar(int cByte) { + if (lastPos > 0) { + lastAttr = planes.getCharAttr(lastPos - 1); + } + if (cByte > 0 && (char)cByte < ' ') { + planes.setScreenCharAndAttr(lastPos, (char) 0x00, 33, false); + setDirty(lastPos); + advancePos(); + } else { + planes.setScreenCharAndAttr(lastPos, (char) cByte, lastAttr, false); + setDirty(lastPos); + if (guiInterface && !isInField(lastPos, false)) { + planes.setUseGUI(lastPos, NO_GUI); + } + advancePos(); + } + } + + protected void setEndingAttr(int cByte) { + int attr = lastAttr; + setAttr(cByte); + lastAttr = attr; + } + + protected void setAttr(int cByte) { + lastAttr = cByte; + + // int sattr = screen[lastPos].getCharAttr(); + // System.out.println("changing from " + sattr + " to attr " + lastAttr + // + + // " at " + (this.getRow(lastPos) + 1) + "," + (this.getCol(lastPos) + + // 1)); + planes.setScreenCharAndAttr(lastPos, initChar, lastAttr, true); + setDirty(lastPos); + + advancePos(); + int pos = lastPos; + + int times = 0; + // sattr = screen[lastPos].getCharAttr(); + // System.out.println(" next position after change " + sattr + " last + // attr " + lastAttr + + // " at " + (this.getRow(lastPos) + 1) + "," + (this.getCol(lastPos) + + // 1) + + // " attr place " + screen[lastPos].isAttributePlace()); + + while (planes.getCharAttr(lastPos) != lastAttr + && !planes.isAttributePlace(lastPos)) { + + planes.setScreenAttr(lastPos, lastAttr); + if (guiInterface && !isInField(lastPos, false)) { + int g = planes.getWhichGUI(lastPos); + if (g >= FIELD_LEFT && g <= FIELD_ONE) + planes.setUseGUI(lastPos,NO_GUI); + } + setDirty(lastPos); + + times++; + advancePos(); + } + + // sanity check for right now + // if (times > 200) + // System.out.println(" setAttr = " + times + " start = " + (sr + 1) + + // "," + (sc + 1)); + + lastPos = pos; + } + + protected void setScreenCharAndAttr(char right, int colorAttr, boolean isAttr) { + + planes.setScreenCharAndAttr(lastPos,right, colorAttr, isAttr); + setDirty(lastPos); + advancePos(); + + } + + protected void setScreenCharAndAttr(char right, int colorAttr, + int whichGui, boolean isAttr) { + + planes.setScreenCharAndAttr(lastPos,right, colorAttr, isAttr); + planes.setUseGUI(lastPos,whichGui); + + setDirty(lastPos); + advancePos(); + + } + + /** + * Draw or redraw the dirty parts of the screen and display them. + * + * Rectangle dirty holds the dirty area of the screen to be updated. + * + * If you want to change the screen in anyway you need to set the screen + * attributes before calling this routine. + */ + protected void updateDirty() { + + fireScreenChanged(1); + + } + + protected void setDirty(int pos) { + + int minr = Math.min(getRow(pos),getRow(dirtyScreen.x)); + int minc = Math.min(getCol(pos),getCol(dirtyScreen.x)); + + int maxr = Math.max(getRow(pos),getRow(dirtyScreen.y)); + int maxc = Math.max(getCol(pos),getCol(dirtyScreen.y)); + + int x1 = getPos(minr,minc); + int x2 = getPos(maxr,maxc); + + dirtyScreen.setBounds(x1,x2,0,0); + + } + + /* *** NEVER USED LOCALLY ************************************************** */ + // private void setDirty(int row, int col) { + // + // setDirty(getPos(row, col)); + // + // } + + private void resetDirty(int pos) { + + dirtyScreen.setBounds(pos,pos,0,0); + + } + + /** + * Change the screen position by one column + */ + protected void advancePos() { + changePos(1); + } + + /** + * Change position of the screen by the increment of parameter passed. + * + * If the position change is under the minimum of the first screen position + * then the position is moved to the last row and column of the screen. + * + * If the position change is over the last row and column of the screen then + * cursor is moved to first position of the screen. + * + * @param i + */ + protected void changePos(int i) { + + lastPos += i; + if (lastPos < 0) + lastPos = lenScreen + lastPos; + if (lastPos > lenScreen - 1) + lastPos = lastPos - lenScreen; + + // System.out.println(lastRow + "," + ((lastPos) / numCols) + "," + + // lastCol + "," + ((lastPos) % numCols) + "," + + // ((lastRow * numCols) + lastCol) + "," + + // (lastPos)); + + } + + protected void goHome() { + + // now we try to move to first input field according to + // 14.6 WRITE TO DISPLAY Command + // ? If the WTD command is valid, after the command is processed, + // the cursor moves to one of three locations: + // - The location set by an insert cursor order (unless control + // character byte 1, bit 1 is equal to B'1'.) + // - The start of the first non-bypass input field defined in the + // format table + // - A default starting address of row 1 column 1. + + if (pendingInsert && homePos > 0) { + setCursor(getRow(homePos), getCol(homePos)); + isInField(); // we now check if we are in a field + } else { + if (!gotoField(1)) { + homePos = getPos(1, 1); + setCursor(1, 1); + isInField(0, 0); // we now check if we are in a field + } else { + homePos = getPos(getCurrentRow(), getCurrentCol()); + } + } + } + + protected void setPendingInsert(boolean flag, int icX, int icY) { + pendingInsert = flag; + if (pendingInsert) { + homePos = getPos(icX, icY); + } + + if (!isStatusErrorCode()) { + setCursor(icX, icY); + } + } + + protected void setPendingInsert(boolean flag) { + if (homePos != -1) + pendingInsert = flag; + } + + /** + * Set the error line number to that of number passed. + * + * @param line + */ + protected void setErrorLine(int line) { + + planes.setErrorLine(line); + } + + /** + * Returns the current error line number + * + * @return current error line number + */ + protected int getErrorLine() { + return planes.getErrorLine(); + } + + /** + * Saves off the current error line characters to be used later. + * + */ + protected void saveErrorLine() { + planes.saveErrorLine(); + } + + /** + * Restores the error line characters from the save buffer. + * + * @see #saveErrorLine() + */ + protected void restoreErrorLine() { + + if (planes.isErrorLineSaved()) { + planes.restoreErrorLine(); + fireScreenChanged(1,planes.getErrorLine()-1,0,planes.getErrorLine()-1,numCols - 1); + } + } + + protected void setStatus(byte attr, byte value, String s) { + + // set the status area + switch (attr) { + + case STATUS_SYSTEM: + if (value == STATUS_VALUE_ON) { + oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT,ScreenOIA.OIA_LEVEL_INPUT_INHIBITED, s); + } + else { + oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED,ScreenOIA.OIA_LEVEL_NOT_INHIBITED,s); + } + break; + + case STATUS_ERROR_CODE: + if (value == STATUS_VALUE_ON) { + setPrehelpState(true, true, false); + oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_ERROR,s); + + sessionVT.signalBell(); + } else { + oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED, + ScreenOIA.OIA_LEVEL_NOT_INHIBITED); + setPrehelpState(false, true, true); + homePos = saveHomePos; + saveHomePos = 0; + pendingInsert = false; + } + break; + + } + } + + protected boolean isStatusErrorCode() { + + return oia.getLevel() == ScreenOIA.OIA_LEVEL_INPUT_ERROR; + + } + + /** + * This routine clears the screen, resets row and column to 0, resets the + * last attribute to 32, clears the fields, turns insert mode off, + * clears/initializes the screen character array. + */ + protected void clearAll() { + + lastAttr = 32; + lastPos = 0; + + clearTable(); + clearScreen(); + planes.setScreenAttr(0, initAttr); + oia.setInsertMode(false); + } + + /** + * Clear the fields table + */ + protected void clearTable() { + + oia.setKeyBoardLocked(true); + screenFields.clearFFT(); + planes.initalizeFieldPlanes(); + pendingInsert = false; + homePos = -1; + } + + /** + * Clear the gui constructs + * + */ + protected void clearGuiStuff() { + + for (int x = 0; x < lenScreen; x++) { + planes.setUseGUI(x,NO_GUI); + } + dirtyScreen.setBounds(0,lenScreen - 1,0,0); + } + + /** + * Clear the screen by setting the initial character and initial attribute + * to all the positions on the screen + */ + protected void clearScreen() { + + planes.initalizePlanes(); + + dirtyScreen.setBounds(0,lenScreen - 1,0,0); + + oia.clearScreen(); + + } + + protected void restoreScreen() { + + lastAttr = 32; + dirtyScreen.setBounds(0,lenScreen - 1,0,0); + updateDirty(); + } + + /** + * Notify all registered listeners of the onScreenChanged event. + * + */ + private void fireScreenChanged(int which, int startRow, int startCol, + int endRow, int endCol) { + if (listeners != null) { + // Patch below contributed by Mitch Blevins + //int size = listeners.size(); + Vector lc = new Vector(listeners); + int size = lc.size(); + for (int i = 0; i < size; i++) { + //ScreenListener target = + // (ScreenListener)listeners.elementAt(i); + ScreenListener target = lc.elementAt(i); + target.onScreenChanged(1,startRow,startCol,endRow,endCol); + } + } + dirtyScreen.setBounds(lenScreen,0,0,0); + } + + /** + * Notify all registered listeners of the onScreenChanged event. + * + */ + private synchronized void fireScreenChanged(int update) { + if (dirtyScreen.x > dirtyScreen.y) { + // log.info(" x < y " + dirtyScreen); + return; + } + + fireScreenChanged(update, getRow(dirtyScreen.x), getCol(dirtyScreen.x), + getRow(dirtyScreen.y), getCol(dirtyScreen.y)); + + } + + /** + * Notify all registered listeners of the onScreenChanged event. + * + */ + private synchronized void fireCursorChanged(int update) { + int startRow = getRow(lastPos); + int startCol = getCol(lastPos); + + if (listeners != null) { + Vector lc = new Vector(listeners); + //int size = listeners.size(); + int size = lc.size(); + for (int i = 0; i < size; i++) { + ScreenListener target = + lc.elementAt(i); + target.onScreenChanged(update,startRow,startCol,startRow,startCol); + } + } + } + + /** + * Notify all registered listeners of the onScreenSizeChanged event. + * + */ + private void fireScreenSizeChanged() { + + if (listeners != null) { + Vector lc = new Vector(listeners); + //int size = listeners.size(); + int size = lc.size(); + for (int i = 0; i < size; i++) { + ScreenListener target = + lc.elementAt(i); + target.onScreenSizeChanged(numRows,numCols); + } + } + } + + /** + * This method does a complete refresh of the screen. + */ + public final void updateScreen() { + repaintScreen(); + setCursorActive(false); + setCursorActive(true); + } + + /** + * Add a ScreenListener to the listener list. + * + * @param listener The ScreenListener to be added + */ + public void addScreenListener(ScreenListener listener) { + + if (listeners == null) { + listeners = new java.util.Vector(3); + } + listeners.addElement(listener); + + } + + /** + * Remove a ScreenListener from the listener list. + * + * @param listener The ScreenListener to be removed + */ + public void removeScreenListener(ScreenListener listener) { + + if (listeners == null) { + return; + } + listeners.removeElement(listener); + } + + /** + * Utility method to share the repaint behaviour between setBounds() and + * updateScreen. + */ + public void repaintScreen() { + + setCursorOff(); + dirtyScreen.setBounds(0,lenScreen - 1,0,0); + updateDirty(); + // restore statuses that were on the screen before resize + if (oia.getLevel() == ScreenOIA.OIA_LEVEL_INPUT_ERROR) { + oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_ERROR); + } + + if (oia.getLevel() == ScreenOIA.OIA_LEVEL_INPUT_INHIBITED) { + oia.setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + } + + if (oia.isMessageWait()) + oia.setMessageLightOn(); + setCursorOn(); + } + + // ADDED BY BARRY - changed by Kenneth to use the character plane + // This should be replaced with the getPlane methods when they are implemented + public char[] getCharacters() { + return planes.screen; + } + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/ScreenField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/ScreenField.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,606 @@ +/** + * Title: tn5250J + * Copyright: Copyright (c) 2001 + * Company: + * @author Kenneth J. Pouncey + * @version 0.4 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +public class ScreenField { + + protected ScreenField(Screen5250 s) { + + this.s = s; + + } + + protected ScreenField setField(int attr, int len, int ffw1, int ffw2, + int fcw1, int fcw2) { + + return setField(attr, + s.getCurrentRow() - 1, + s.getCurrentCol() - 1, + len, + ffw1, + ffw2, + fcw1, + fcw2); + } + + protected ScreenField setField(int attr, int row, int col, int len, int ffw1, int ffw2, + int fcw1, int fcw2) { + +// startRow = row; +// startCol = col; + startPos = (row * s.getColumns()) + col; + endPos = startPos + length -1; + cursorProg = 0; + fieldId = 0; + length = len; + endPos = startPos + length -1; + this.attr = attr; + setFFWs(ffw1,ffw2); + setFCWs(fcw1,fcw2); + + next = null; + prev = null; + + return this; + + } + + public int getAttr(){ + return attr; + } + + public int getHighlightedAttr(){ + return (fcw2 & 0x0f) | 0x20; + } + + public int getLength(){ + return length; + } + + protected boolean setFFWs(int ffw1, int ffw2) { + + this.ffw1 = ffw1; + this.ffw2 = ffw2; + + int adj = getAdjustment(); + + if (adj > 0) { + checkCanSend = true; + + switch (adj) { + + case 5: + case 6: + rightAdjd = false; + break; + case 7: + manditoried = false; + break; + } + + } + mdt = (ffw1 & 0x8 ) == 0x8; +// if (mdt) +// s.masterMDT = true; + return mdt; + } + + + public int getFFW1(){ + return ffw1; + } + public int getFFW2(){ + return ffw2; + } + + protected void setFCWs(int fcw1, int fcw2) { + + this.fcw1 = fcw1; + this.fcw2 = fcw2; + +// if ((fcw1 & 0x88) == 0x88) { + if (fcw1 == 0x88) { + + cursorProg = fcw2; + } + } + + public int getFCW1(){ + return fcw1; + } + + public int getFCW2(){ + return fcw2; + } + + public int getFieldLength(){ + return length; + } + + public int getCursorProgression() { + return cursorProg; + } + + public int getFieldId() { + return fieldId; + } + + protected void setFieldId(int fi) { + fieldId = fi; + } + + public int getCursorRow() { + + return cursorPos / s.getColumns(); + } + + public int getCursorCol() { + + return cursorPos % s.getColumns(); + } + + protected void changePos(int i) { + + cursorPos += i; + + } + + protected String getText() { + + + StringBuffer text = new StringBuffer(); + getKeyPos(endPos); + int x = length; + text.setLength(x); + while (x-- > 0) { + + // here we manipulate the unicode characters a little for attributes + // that are imbedded in input fields. We will offset them by unicode + // \uff00. All routines that process these fields will have to + // return them to their proper offsets. + // example: + // if we read an attribute byte of 32 for normal display the unicode + // character for this is \u0020 and the unicode character for + // a space is also \u0020 thus the offset. + if (s.planes.isAttributePlace(cursorPos)) { + text.setCharAt(x,(char)('\uff00' + s.planes.getCharAttr(cursorPos))); + } + else { + text.setCharAt(x,s.planes.getChar(cursorPos)); + } + changePos(-1); + + } + + // Since only the mdt of the first continued field is set we will get + // the text of the next continued field if we are dealing with continued + // fields. See routine setMDT for the whys of this. This is only + // executed if this is the first field of a continued field. + if (isContinued() && isContinuedFirst()) { + ScreenField sf = this; + do { + sf = sf.next; + text.append(sf.getText()); + } + while (!sf.isContinuedLast()); + + sf = null; + } + + return text.toString(); + + } + + public String getString() { + + + StringBuffer text = new StringBuffer(); + getKeyPos(endPos); + int x = length; + text.setLength(x); + while (x-- > 0) { + + // here we manipulate the unicode characters a little for attributes + // that are imbedded in input fields. We will offset them by unicode + // \uff00. All routines that process these fields will have to + // return them to their proper offsets. + // example: + // if we read an attribute byte of 32 for normal display the unicode + // character for this is \u0020 and the unicode character for + // a space is also \u0020 thus the offset. + if (s.planes.isAttributePlace(cursorPos)) { + text.setCharAt(x,(char)('\uff00' + s.planes.getCharAttr(cursorPos))); + } + else { + if (s.planes.getChar(cursorPos) < ' ') + text.setCharAt(x,' '); + else + text.setCharAt(x,s.planes.getChar(cursorPos)); + } + changePos(-1); + + } + + // Since only the mdt of the first continued field is set we will get + // the text of the next continued field if we are dealing with continued + // fields. See routine setMDT for the whys of this. This is only + // executed if this is the first field of a continued field. + if (isContinued() && isContinuedFirst()) { + ScreenField sf = this; + do { + sf = sf.next; + text.append(sf.getString()); + } + while (!sf.isContinuedLast()); + + sf = null; + } + + return text.toString(); + + } + + public void setFieldChar(char c) { + + int x = length; + cursorPos = startPos; + while (x-- > 0) { + s.planes.setChar(cursorPos,c); + changePos(1); + } + + } + + public void setFieldChar(int lastPos, char c) { + + int x = endPos - lastPos + 1; + cursorPos = lastPos; + while (x-- > 0) { + s.planes.setChar(cursorPos,c); + s.setDirty(cursorPos); + changePos(1); + } + } + + protected void setRightAdjusted() { + rightAdjd = true; + } + + protected void setManditoryEntered() { + + manditoried = true; + } + + protected void resetMDT() { + mdt = false; + + } + + protected void setMDT() { + + // get the first field of a continued edit field if it is continued + if (isContinued() && !isContinuedFirst()) { + ScreenField sf = prev; + while (sf.isContinued() && !sf.isContinuedFirst()) { + + sf = sf.prev; + + } + sf.setMDT(); + sf = null; + } + else { + mdt = true; + } + + } + + public boolean isBypassField() { + + return (ffw1 & 0x20) == 0x20; + + } + + public int getAdjustment () { + + return (ffw2 & 0x7); + } + + // is field exit required + public boolean isFER () { + + return (ffw2 & 0x40) == 0x40; + } + + // is field manditory enter + public boolean isMandatoryEnter() { + + return (ffw2 & 0x8) == 0x8; + + } + + public boolean isToUpper() { + + return (ffw2 & 0x20) == 0x20; + + } + + // bits 5 - 7 + public int getFieldShift () { + + return (ffw1 & 0x7); + + } + + public boolean isHiglightedEntry() { + + return (fcw1 == 0x89); + + } + + public boolean isAutoEnter() { + + return (ffw2 & 0x80) == 0x80; + + } + + public boolean isSignedNumeric () { + + return (getFieldShift() == 7); + + } + + public boolean isRightToLeft() { + return (getFieldShift() == 0x04); + } + + public boolean isNumeric () { + + return (getFieldShift() == 3); + + } + + public boolean isDupEnabled() { + + return (ffw1 & 0x10) == 0x10; + + } + + public boolean isContinued() { + + return (fcw1 & 0x86) == 0x86 && (fcw2 >= 1 && fcw2 <= 3) ; + + } + + public boolean isContinuedFirst() { + + return (fcw1 & 0x86) == 0x86 && (fcw2 == 1); + + } + + public boolean isContinuedMiddle() { + + return (fcw1 & 0x86) == 0x86 && (fcw2 == 3); + + } + + public boolean isContinuedLast() { + + return (fcw1 & 0x86) == 0x86 && (fcw2 == 2); + + } + + protected boolean isCanSend() { + + int adj = getAdjustment(); + + // here we need to check the Field Exit Required value first before checking + // the adjustments. If the last character has been entered and we are + // now setting past the last position then we are allowed to process the + // the field without continuing. + if (isFER() && cursorPos > endPos) { + return true; + } + + // signed numeric fields need to be checked as well. + if (isSignedNumeric() && cursorPos < endPos - 1) { + return false; + } + + if (adj > 0) { + + switch (adj) { + + case 5: + case 6: + return rightAdjd; + case 7: + return manditoried; + default: + return true; + } + + } + return true; + } + + public boolean isSelectionField() { + + return isSelectionField; + + } + + public void setSelectionFieldInfo(int type, int index, int position) { + + selectionFieldType = type; + selectionIndex = index; + selectionPos = position; + isSelectionField = true; + + } + + protected int getKeyPos(int row1, int col1) { + + int x = ((row1 * s.getColumns()) + col1); + int y = x - startPos(); + cursorPos = x; + + return y; + } + + protected int getKeyPos(int pos) { + + int y = pos - startPos(); + cursorPos = pos; + + return y; + } + + public int getCurrentPos() { + + return cursorPos; + } + + public boolean withinField (int pos) { + + if (pos >= startPos && pos <= endPos) + return true; + return false; + + } + + public int startPos() { + + return startPos; + } + + /** + * Get the starting row of the field. Offset is 0 so row 6 returned + * is row 7 mapped to screen + * @return int starting row of the field offset 0 + */ + public int startRow() { + + return startPos / s.getColumns(); + + } + + /** + * Get the starting column of the field. Offset is 0 so column 6 returned + * is column 7 mapped to screen + * @return int starting column of the field offset 0 + */ + public int startCol() { + + return startPos % s.getColumns(); + + } + + public int endPos() { + + return endPos; + + } + + /** + * Sets the field's text plane to the specified string. If the string is + * shorter than the length of the field, the rest of the field is cleared. + * If the string is longer than the field, the text is truncated. A subsequent + * call to getText on this field will not show the changed text. To see the + * changed text, do a refresh on the iOhioFields collection and retrieve the + * refreshed field object. + * + * @param text - The text to be placed in the field's text plane. + */ + public void setString(String text) { + + int y = length; + cursorPos = startPos; + int len = text.length(); + char[] c = text.toCharArray(); + char tc = ' '; + + for (int x = 0; x < y; x++) { + tc = ' '; + if (x < len) { + tc = c[x]; + } + s.getPlanes().setChar(cursorPos,tc); + changePos(1); + } + setMDT(); + s.getScreenFields().setMasterMDT(); + } + + public String toString() { + int fcw = (fcw1 & 0xff) << 8 | fcw2 & 0xff; + return "startRow = " + startRow() + " startCol = " + startCol() + + " length = " + length + " ffw1 = (0x" + Integer.toHexString(ffw1) + + ") ffw2 = (0x" + Integer.toHexString(ffw2) + + ") fcw1 = (0x" + Integer.toHexString(fcw1) + + ") fcw2 = (0x" + Integer.toHexString(fcw2) + + ") fcw = (" + Integer.toBinaryString(fcw) + + ") fcw hex = (0x" + Integer.toHexString(fcw) + + ") is bypass field = " + isBypassField() + + ") is autoenter = " + isAutoEnter() + + ") is manditoryenter = " + isMandatoryEnter() + + ") is field exit required = " + isFER() + + ") is Numeric = " + isNumeric() + + ") is Signed Numeric = " + isSignedNumeric() + + ") is cursor progression = " + (fcw1 == 0x88) + + ") next progression field = " + fcw2 + + ") field id " + fieldId + + " continued edit field = " + isContinued() + + " first continued edit field = " + isContinuedFirst() + + " middle continued edit field = " + isContinuedMiddle() + + " last continued edit field = " + isContinuedLast() + + " mdt = " + mdt; + } + + int startPos = 0; + int endPos = 0; + boolean mdt = false; + protected boolean checkCanSend; + protected boolean rightAdjd; + protected boolean manditoried; + boolean canSend = true; + int attr = 0; + int length = 0; + int ffw1 = 0; + int ffw2 = 0; + int fcw1 = 0; + int fcw2 = 0; + int cursorPos = 0; + Screen5250 s; + int cursorProg = 0; + int fieldId = 0; + ScreenField next = null; + ScreenField prev = null; + boolean isSelectionField; + int selectionFieldType; + int selectionIndex; + int selectionPos; +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/ScreenFields.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/ScreenFields.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,724 @@ +/** + * Title: tn5250J + * Copyright: Copyright (c) 2001 + * Company: + * @author Kenneth J. Pouncey + * @version 0.5 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +import static org.tn5250j.TN5250jConstants.CMD_READ_INPUT_FIELDS; +import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_FIELDS; +import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_IMMEDIATE_ALT; + +import java.io.ByteArrayOutputStream; + +import org.tn5250j.encoding.ICodePage; + +public class ScreenFields { + + private ScreenField[] screenFields; + private ScreenField currentField; + private ScreenField saveCurrent; + private int sizeFields; + private boolean cpfExists; + private int nextField; + private int fieldIds; + private Screen5250 screen; + private boolean masterMDT; + protected boolean currentModified; + + public ScreenFields(Screen5250 s) { + + screen = s; + screenFields = new ScreenField[256]; + } + + protected void clearFFT() { + + sizeFields = nextField = fieldIds = 0; + cpfExists = false; // clear the cursor progression fields flag + currentField = null; + masterMDT = false; + + } + + protected boolean existsAtPos(int lastPos) { + + ScreenField sf = null; + + // from 14.6.12 for Start of Field Order 5940 function manual + // examine the format table for an entry that begins at the current + // starting address plus 1. + for (int x = 0;x < sizeFields; x++) { + sf = screenFields[x]; + + if (lastPos == sf.startPos()) { + currentField = sf; + currentModified = false; + return true; + } + + } + + return false; + } + + public boolean isMasterMDT() { + return masterMDT; + } + + protected void setMasterMDT() { + masterMDT = true; + } + + public boolean isCurrentField() { + return currentField == null; + } + + public boolean isCurrentFieldFER() { + return currentField.isFER(); + } + + public boolean isCurrentFieldDupEnabled() { + return currentField.isDupEnabled(); + } + + public boolean isCurrentFieldToUpper() { + return currentField.isToUpper(); + } + + public boolean isCurrentFieldBypassField() { + return currentField.isBypassField(); + } + + public boolean isCurrentFieldHighlightedEntry() { + if (currentField != null) + return currentField.isHiglightedEntry(); + else + return false; + } + + public boolean isCurrentFieldAutoEnter() { + return currentField.isAutoEnter(); + } + + public boolean withinCurrentField(int pos) { + return currentField.withinField(pos); + } + + public boolean isCurrentFieldContinued() { + return currentField.isContinued(); + } + + public boolean isCurrentFieldContinuedFirst() { + return currentField.isContinuedFirst(); + } + + public boolean isCurrentFieldContinuedMiddle() { + return currentField.isContinuedMiddle(); + } + + public boolean isCurrentFieldContinuedLast() { + return currentField.isContinuedLast(); + } + + public boolean isCurrentFieldModified() { + return currentModified; + } + + /** + * This routine is used to check if we can send the Aid key to the host + * + * Taken from Section 16.2.1.2 Enter/Rec Adv Key + * + * In the normal unlocked state, when the workstation operator presses the + * Enter/Rec Adv key: + * + * 1. The 5494 checks for the completion of mandatory-fill, self-check, and + * right-adjust fields when in an active field. (An active field is one in + * which the workstation operator has begun entering data.) If the + * requirements of the field have not been satisfied, an error occurs. + * + * @return + * + */ + public boolean isCanSendAid() { + + // We also have to check if we are still in the field. + if (currentField != null && + (currentField.getAdjustment() > 0 || currentField.isSignedNumeric()) + && currentModified && isInField() + && !currentField.isCanSend()) + + return false; + else + return true; + + } + + protected void saveCurrentField() { + saveCurrent = currentField; + } + + protected void restoreCurrentField() { + currentField = saveCurrent; + } + + protected void setCurrentField(ScreenField sf) { + currentField = sf; + } + + protected void setCurrentFieldMDT() { + currentField.setMDT(); + currentModified = true; + masterMDT = true; + } + + protected void setCurrentFieldFFWs(int ffw1, int ffw2) { + + masterMDT = currentField.setFFWs(ffw1,ffw2); + + } + + + protected ScreenField setField(int attr, int row, int col, int len, int ffw1, + int ffw2, int fcw1, int fcw2) { + + ScreenField sf = null; + screenFields[nextField] = new ScreenField(screen); + screenFields[nextField].setField(attr,row,col,len,ffw1,ffw2,fcw1,fcw2); + sf = screenFields[nextField++]; + + sizeFields++; + + + // set the field id if it is not a bypass field + // this is used for cursor progression + // changed this because of problems not allocating field id's for + // all fields. kjp 2002/10/21 +// if (!sf.isBypassField()) + sf.setFieldId(++fieldIds); + + // check if the cursor progression field flag should be set. +// if ((fcw1 & 0x88) == 0x88) + if (fcw1 == 0x88) + cpfExists = true; + + if (currentField != null) { + currentField.next = sf; + sf.prev = currentField; + } + + currentField = sf; + + // check if the Modified Data Tag was set while creating the field + if (!masterMDT) + masterMDT = currentField.mdt; + + currentModified = false; + + return currentField; + + } + + public ScreenField getField(int index) { + + return screenFields[index]; + } + + public ScreenField getCurrentField() { + return currentField; + } + + public int getCurrentFieldPos() { + return currentField.getCurrentPos(); + } + + protected int getCurrentFieldShift() { + return currentField.getFieldShift(); + } + + public String getCurrentFieldText() { + + return currentField.getText(); + } + + public int getCurrentFieldHighlightedAttr(){ + return currentField.getHighlightedAttr(); + } + + public int getSize() { + + return sizeFields; + } + + public int getFieldCount() { + + return sizeFields; + } + + protected boolean isInField(int pos) { + return isInField(pos,true); + } + + protected boolean isInField() { + return isInField(screen.getLastPos(),true); + } + + protected boolean isInField(int pos, boolean chgToField) { + + ScreenField sf; + + for (int x = 0;x < sizeFields; x++) { + sf = screenFields[x]; + + if (sf.withinField(pos)) { + + if (chgToField) { + if (!currentField.equals(sf)) + currentModified = false; + currentField = sf; + } + return true; + } + } + return false; + + } + + /** + * Searches the collection for the target string and returns the iOhioField + * object containing that string. The string must be totally contained + * within the field to be considered a match. + * + * @param targetString The target string. + * @param startPos The row and column where to start the search. The position + * is inclusive (for example, row 1, col 1 means that + * position 1,1 will be used as the starting location and + * 1,1 will be included in the search). + * @param length The length from startPos to include in the search. + * @param dir An OHIO_DIRECTION value: + * + * + * + * + * + * + * + * + *
Constant ValueDescription
OS_OHIO_DIRECTION_FORWARD 0Forward (beginning towards end)
OS_OHIO_DIRECTION_BACKWARD 1Backward (end towards beginning)
+ * Constant Value Description + * ignoreCase - Indicates whether the search is case sensitive. + * True means that case will be ignored. False means the search will + * be case sensitive. + * @return If found, an iOhioField object containing the target string. If + * not found, returns a null. + */ + public ScreenField findByString (String targetString, + int startPos, + int length, + int dir, + boolean ignoreCase) { + + // first lets check if the string exists in the screen space +// iOhioPosition pos = screen.findString(targetString, startPos, length, +// dir, ignoreCase); + + // if it does exist then lets search the fields by the position that + // was found and return the results of that search. +// if (pos != null) { + return findByPosition(startPos); +// } + + //return null; + + } + + /** + * Searches the collection for the target position and returns the ScreenField + * object containing that position. + * + * @param targetPosition The target row and column expressed as a linear + * position within the presentation space. + * + * @return If found, a ScreenField object containing the target position. + * If not found, returns a null. + */ + public ScreenField findByPosition(int targetPosition) { + + ScreenField sf = null; + + for (int x = 0;x < sizeFields; x++) { + + sf = screenFields[x]; + + if (sf.withinField(targetPosition)) { + return sf; + } + + } + + return null; + } + + /** + * Searches the collection for the target position and returns the ScreenField + * object containing that position. + * + * @param row The beginning row to start search with in the presentation space. + * @param col The beginning column to start search with in the presentation space. + * + * @return If found, a ScreenField object containing the target position. + * If not found, returns a null. + */ + public ScreenField findByPosition(int row, int col) { + + return findByPosition(screen.getPos(row,col)); + } + + public ScreenField[] getFields () { + + ScreenField[] fields = new ScreenField[sizeFields]; + for (int x = 0; x < sizeFields; x++) { + + fields[x] = screenFields[x]; + } + + return fields; + } + + public ScreenField getFirstInputField() { + + if (sizeFields <= 0) + return null; + + int f = 0; + ScreenField sf = screenFields[f]; + + while (sf.isBypassField() && f++ < sizeFields) { + sf = screenFields[f]; + } + + if (sf.isBypassField()) + return null; + else + return sf; + + } + + public void gotoFieldNext() { + + // sanity check - we where getting null pointers after a restore of screen + // and cursor was not positioned on a field when returned + // *** Note *** to myself + // maybe this is fixed I will have to check this some time + int lastPos = screen.getLastPos(); + + if (currentField == null && (sizeFields != 0) && !isInField(lastPos,true)) { + int pos = lastPos; + screen.setCursorOff(); + screen.advancePos(); + lastPos = screen.getLastPos(); + while (!isInField() && pos != lastPos) { + screen.advancePos(); + } + screen.setCursorOn(); + } + + // if we are still null do nothing + if (currentField == null) + return; + + ScreenField sf = currentField; + + if (!sf.withinField(lastPos)) { + screen.setCursorOff(); + + if (sizeFields > 0) { + + // lets get the current position so we can test if we have looped + // the screen and not found a valid field. + int pos = lastPos; + int savPos = lastPos; + boolean done = false; + do { + screen.advancePos(); + lastPos = screen.getLastPos(); + if (isInField(lastPos) + || pos==lastPos) { + if (!currentField.isBypassField()) { + screen.gotoField(currentField); + done = true; + } + } + } while ( !done && lastPos != savPos); + } + currentModified = false; + screen.setCursorOn(); + + } + else { + if (!cpfExists) { + do { + + sf = sf.next; + } + while ( sf != null && sf.isBypassField()); + + } + else { + int f = 0; + int cp = sf.getCursorProgression(); + + if (cp == 0) { + do { + + sf = sf.next; + } + while ( sf != null && sf.isBypassField()); + + } + else { + ScreenField sf1 = null; + boolean found = false; + while (!found && f < sizeFields) { + + sf1 = screenFields[f++]; + if (sf1.getFieldId() == cp) + found = true; + } + if (found) + sf = sf1; + else { + do { + sf = sf.next; + } + while ( sf != null && sf.isBypassField()); + + } + sf1 = null; + } + } + if (sf == null) + screen.gotoField(1); + else { + currentField = sf; + screen.gotoField(currentField); + } + + currentModified = false; + + } + } + + public void gotoFieldPrev() { + + ScreenField sf = currentField; + int lastPos = screen.getLastPos(); + + if (!sf.withinField(lastPos)) { + screen.setCursorOff(); + + if (sizeFields > 0) { + // lets get the current position so we can test if we have looped + // the screen and not found a valid field. + int pos = lastPos; + int savPos = lastPos; + boolean done = false; + + do { + screen.changePos(-1); + lastPos = screen.getLastPos(); + + if (isInField(lastPos) + || (pos == lastPos)) { + + if (!currentField.isBypassField()) { + screen.gotoField(currentField); + done = true; + } + } + } while ( !done && lastPos != savPos); + } + screen.setCursorOn(); + + } + else { + + if (sf.startPos() == lastPos) { + if (!cpfExists) { + + do { + sf = sf.prev; + } + while ( sf != null && sf.isBypassField()); + } + else { + + int f = 0; + int cp = sf.getFieldId(); + ScreenField sf1 = null; + boolean found = false; + while (!found && f < sizeFields) { + + sf1 = screenFields[f++]; + if (sf1.getCursorProgression() == cp) + found = true; + } + if (found) + sf = sf1; + else { + do { + sf = sf.prev; + } + while ( sf != null && sf.isBypassField()); + } + sf1 = null; + } + } + + if (sf == null) { + int size = sizeFields; + sf = screenFields[size - 1]; + + while (sf.isBypassField() && size-- > 0) { + sf = screenFields[size]; + + } + } + currentField = sf; + currentModified = false; + screen.gotoField(currentField); + } + } + + protected void readFormatTable(ByteArrayOutputStream baosp,int readType, ICodePage codePage) { + + ScreenField sf; + boolean isSigned = false; + char c; + + if (masterMDT) { + + StringBuffer sb = new StringBuffer(); + for (int x = 0; x < sizeFields; x++) { + isSigned = false; + + sf = screenFields[x]; + + if (sf.mdt || (readType == CMD_READ_INPUT_FIELDS)) { + + sb.setLength(0); + sb.append(sf.getText()); + + + if (readType == CMD_READ_MDT_FIELDS || + readType == CMD_READ_MDT_IMMEDIATE_ALT) { + int len = sb.length() - 1; + + // we strip out all '\u0020' and less + while (len >= 0 && +// (sb.charAt(len) <= ' ' || sb.charAt(len) >= '\uff20' )) { + (sb.charAt(len) < ' ' || sb.charAt(len) >= '\uff20')) { + + // if we have the dup character and dup is enabled then we + // stop here + if (sb.charAt(len) == 0x1C && sf.isDupEnabled()) + break; + + sb.deleteCharAt(len--); + } + + } + +// System.out.println("field " + sf.toString()); +// System.out.println(">" + sb.toString() + "<"); +// System.out.println(" field is all nulls"); + if (sf.isSignedNumeric() && sb.length() > 0 && sb.charAt(sb.length() - 1) == '-') { + isSigned = true; + sb.setLength(sb.length() - 1); + } + + int len3 = sb.length(); + + if (len3 > 0 || (readType == CMD_READ_MDT_FIELDS || + readType == CMD_READ_MDT_IMMEDIATE_ALT)) { + + if ((readType == CMD_READ_MDT_FIELDS || + readType == CMD_READ_MDT_IMMEDIATE_ALT)) { + + baosp.write(17); // start of field data + if (sf.isSelectionField()) { + baosp.write(screen.getRow(sf.selectionPos)+1); + baosp.write(screen.getCol(sf.selectionPos)+1); + } + else { + baosp.write(sf.startRow()+1); + baosp.write(sf.startCol()+1); + } + + } +// int len = sb.length(); + if (sf.isSelectionField()) { + baosp.write(0); + baosp.write(sf.selectionIndex + 0x1F); + + } + else { + for (int k = 0; k < len3; k++) { + c = sb.charAt(k); + // here we have to check for special instances of the + // characters in the string field. Attribute bytes + // are encoded with an offset of \uff00 + // This is a hack !!!!!!!!!!! + // See ScreenField object for a description + if (c < ' ' || c >= '\uff20') { + + // if it is an offset attribute byte we just pass + // it straight on to the output stream + if (c >= '\uff20' && c <= '\uff3f') { + baosp.write(c - '\uff00'); + } + else + // check for dup character + if (c == 0x1C) + baosp.write(c); + else + baosp.write(codePage.uni2ebcdic(' ')); + } + else { + if (isSigned && k == len3 - 1) { + baosp.write(0xd0 | (0x0f & c)); + } + else + baosp.write(codePage.uni2ebcdic(c)); + + } + } + } + } + } + } + } + } + +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/ScreenOIA.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/ScreenOIA.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,294 @@ +/** + *

Title: ScreenOIA.java

+ *

Description: Main interface to control Operator information area screen

+ *

Copyright: Copyright (c) 2000 - 2002

+ *

+ * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + *

+ * @author Kenneth J. Pouncey + * @version 0.5 + */ +package org.tn5250j.framework.tn5250; + +import java.util.Vector; + +import org.tn5250j.event.ScreenOIAListener; + +/** + * The operator information area of a host session. This area is used to provide + * status information regarding the state of the host session and location of + * the cursor. A ScreenOIA object can be obtained using the GetOIA() method on + * an instance of Screen5250. + * + * + */ +public class ScreenOIA + { + // OIA_LEVEL + public static final int OIA_LEVEL_INPUT_INHIBITED = 1; + public static final int OIA_LEVEL_NOT_INHIBITED = 2; + public static final int OIA_LEVEL_MESSAGE_LIGHT_ON = 3; + public static final int OIA_LEVEL_MESSAGE_LIGHT_OFF = 4; + public static final int OIA_LEVEL_AUDIBLE_BELL = 5; + public static final int OIA_LEVEL_INSERT_MODE = 6; + public static final int OIA_LEVEL_KEYBOARD = 7; + public static final int OIA_LEVEL_CLEAR_SCREEN = 8; + public static final int OIA_LEVEL_SCREEN_SIZE = 9; + public static final int OIA_LEVEL_INPUT_ERROR = 10; + public static final int OIA_LEVEL_KEYS_BUFFERED = 11; + public static final int OIA_LEVEL_SCRIPT = 12; + + // INPUTINHIBITED + public static final int INPUTINHIBITED_NOTINHIBITED = 0; + public static final int INPUTINHIBITED_SYSTEM_WAIT = 1; + public static final int INPUTINHIBITED_COMMCHECK = 2; + public static final int INPUTINHIBITED_PROGCHECK = 3; + public static final int INPUTINHIBITED_MACHINECHECK = 4; + public static final int INPUTINHIBITED_OTHER = 5; + + public ScreenOIA (Screen5250 screen) { + + source = screen; + + } + + public boolean isInsertMode() { + + return insertMode; + } + + protected void setInsertMode(boolean mode) { + + level = OIA_LEVEL_INSERT_MODE; + insertMode = mode; + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_INSERT_MODE); + } + + public int getCommCheckCode() { + + return commCheck; + } + + public int getInputInhibited() { + + return inputInhibited; + } + + public int getMachineCheckCode() { + + return machineCheck; + } + + public int getOwner() { + return owner; + } + + public int getProgCheckCode() { + return 0; + } + + /** + * Is the keyboard locked or not + * + * @return locked or not + */ + public boolean isKeyBoardLocked() { + return locked; + } + + public boolean isKeysBuffered() { + return keysBuffered; + } + + public void setKeysBuffered(boolean kb) { + level = OIA_LEVEL_KEYS_BUFFERED; + boolean oldKB = keysBuffered; + keysBuffered = kb; + if (keysBuffered != oldKB) + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_KEYS_BUFFERED); + } + + protected void setKeyBoardLocked(boolean lockIt) { + level = OIA_LEVEL_KEYBOARD; + boolean oldLocked = locked; + locked = lockIt; + if (!lockIt) { + + if (isKeysBuffered()) { + source.sendKeys(""); + } + } + + if (locked != oldLocked) + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_KEYBOARD_LOCKED); + } + + public boolean isMessageWait() { + return messageWait; + } + + protected void setMessageLightOn() { + level = OIA_LEVEL_MESSAGE_LIGHT_ON; + messageWait = true; + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_MESSAGELIGHT); + } + + protected void setMessageLightOff() { + level = OIA_LEVEL_MESSAGE_LIGHT_OFF; + messageWait = false; + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_MESSAGELIGHT); + } + + public void setScriptActive(boolean running) { + level = OIA_LEVEL_SCRIPT; + scriptRunning = running; + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_SCRIPT); + } + + public boolean isScriptActive() { + return scriptRunning; + } + + public void setAudibleBell() { + level = OIA_LEVEL_AUDIBLE_BELL; + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_BELL); + } + + protected void clearScreen() { + level = OIA_LEVEL_CLEAR_SCREEN; + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_CLEAR_SCREEN); + } + + /** + * Add a ScreenOIAListener to the listener list. + * + * @param listener The ScreenOIAListener to be added + */ + public void addOIAListener(ScreenOIAListener listener) { + + if (listeners == null) { + listeners = new java.util.Vector(3); + } + listeners.addElement(listener); + + } + + /** + * Remove a iOhioSessionListener from the listener list. + * + * @param listener The iOhioSessionListener to be removed + */ + public void removeOIAListener(ScreenOIAListener listener) { + + if (listeners == null) { + return; + } + listeners.removeElement(listener); + } + + // object methods + public Screen5250 getSource() { + + return source; + } + + + public void setSource(Screen5250 screen) { + + source = screen; + + } + + public void setOwner(int newOwner) { + + owner = newOwner; + + } + + public int getLevel() { + + return level; + } + + public String getInhibitedText() { + return inhibitedText; + } + + public void setInputInhibited(int inhibit , int whatCode) { + setInputInhibited(inhibit, whatCode, null); + } + + public void setInputInhibited(int inhibit , int whatCode, String message) { + + inputInhibited = inhibit; + level = OIA_LEVEL_INPUT_INHIBITED; + inhibitedText = message; + +// if (saveInhibit != inhibit || saveInhibitLevel != whatCode) { + switch(inhibit) { + + case INPUTINHIBITED_COMMCHECK : + commCheck = whatCode; + break; + case INPUTINHIBITED_PROGCHECK : +// progCheck = whatCode; // never used + break; + case INPUTINHIBITED_MACHINECHECK : + machineCheck = whatCode; + break; + case INPUTINHIBITED_SYSTEM_WAIT : + level = whatCode; + break; + case INPUTINHIBITED_NOTINHIBITED : + level = whatCode; + break; + } + + fireOIAChanged(ScreenOIAListener.OIA_CHANGED_INPUTINHIBITED); +// } + } + + /** + * Notify all registered listeners of the onOIAChanged event. + * + */ + private void fireOIAChanged(int change) { + + if (listeners != null) { + int size = listeners.size(); + for (int i = 0; i < size; i++) { + ScreenOIAListener target = + listeners.elementAt(i); + target.onOIAChanged(this, change); + } + } + } + + private Vector listeners = null; + private boolean insertMode; + private boolean locked; + private boolean keysBuffered; + private int owner = 0; + private int level = 0; + private Screen5250 source = null; + private int commCheck = 0; + private int machineCheck = 0; + private boolean messageWait; + private boolean scriptRunning; + private int inputInhibited = INPUTINHIBITED_NOTINHIBITED; + private String inhibitedText; + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/ScreenPlanes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/ScreenPlanes.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,1173 @@ +/** + * Title: ScreenPlanes.java + * Copyright: Copyright (c) 2001 + * Company: + * @author Kenneth J. Pouncey + * @version 0.5 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +import static org.tn5250j.TN5250jConstants.*; + +import java.util.Properties; + +import org.tn5250j.ExternalProgramConfig; + +public class ScreenPlanes { + + private final Screen5250 scr; + private int screenSize; + private int numRows; + private int numCols; + private int errorLineNum; + + private static final int initAttr = 32; + private static final char initChar = 0; + + protected char[] screen; // text plane + private char[] screenAttr; // attribute plane + private char[] screenGUI; // gui plane + private char[] screenIsAttr; + private char[] fieldExtended; + private char[] screenField; + private char[] screenColor; // color plane + protected char[] screenExtended; // extended plane + private char[] screenIsChanged; + + private char[] initArray; + + private char[] errorLine; + private char[] errorLineAttr; + private char[] errorLineIsAttr; + private char[] errorLineGui; + + public ScreenPlanes(Screen5250 s5250, int size) { + + scr = s5250; + setSize(size); + } + + protected void setSize(int newSize) { + + screenSize = newSize; + + numCols = 80; + switch (newSize) { + case 24: + numRows = 24; + break; + case 27: + numRows = 27; + numCols = 132; + break; + + } + + // this is used here when size changes + setErrorLine(numRows); + + screenSize = numRows * numCols; + screen = new char[screenSize]; + screenAttr = new char[screenSize]; + screenIsAttr = new char[screenSize]; + screenGUI = new char[screenSize]; + screenColor = new char[screenSize]; + screenExtended = new char[screenSize]; + fieldExtended = new char[screenSize]; + screenIsChanged = new char[screenSize]; + screenField = new char[screenSize]; + + initArray = new char[screenSize]; + + initalizePlanes(); + } + + protected void setErrorLine (int line) { + + // * NOTE * for developers I have changed the send qry to pass different + // parameters to the host so check setsize for setting error line as well. + // + if (line == 0 || line > numRows) + errorLineNum = numRows; + else + errorLineNum = line; + } + + /** + * Returns the current error line number + * + * @return current error line number + */ + protected int getErrorLine() { + return errorLineNum; + } + + protected void saveErrorLine() { + + // if there is already an error line saved then do not save it again + // This signifies that there was a previous error and the original error + // line was not restored yet. + if (errorLine == null) { + errorLine = new char[numCols]; + errorLineAttr = new char[numCols]; + errorLineIsAttr = new char[numCols]; + errorLineGui = new char[numCols]; + + int r = scr.getPos(errorLineNum-1,0); + + for (int x = 0;x < numCols; x++) { + errorLine[x] = screen[r+x]; + errorLineAttr[x] = screenAttr[r+x]; + errorLineIsAttr[x] = screenIsAttr[r+x]; + errorLineGui[x] = screenGUI[r+x]; + } + } + } + + /** + * Restores the error line characters from the save buffer. + * + * @see #saveErrorLine() + */ + protected void restoreErrorLine() { + + if (errorLine != null) { + int r = scr.getPos(errorLineNum - 1, 0); + + for (int x = 0; x < numCols - 1; x++) { + setScreenCharAndAttr(r+x,errorLine[x],errorLineAttr[x], + (errorLineIsAttr[x] == '1' ? true : false)); + screenGUI[x] = errorLineGui[x]; + } + + errorLine = null; + errorLineAttr = null; + errorLineIsAttr = null; + errorLineGui = null; + } + } + + protected boolean isErrorLineSaved() { + return errorLine == null ? false : true; + } + + protected void setScreenCharAndAttr(int pos, char c, int attr, boolean isAttr) { + + screen[pos] = c; + screenAttr[pos] = (char)attr; + disperseAttribute(pos,attr); + screenIsAttr[pos] = (isAttr ? (char)1 : (char)0); + screenGUI[pos] = NO_GUI; + + } + + protected void setScreenAttr(int pos, int attr, boolean isAttr) { + + screenAttr[pos] = (char)attr; + screenIsAttr[pos] = isAttr ? (char)1 : (char)0; + disperseAttribute(pos,attr); + screenGUI[pos] = initChar; + + } + + protected void setScreenAttr(int pos, int attr) { + + screenAttr[pos] = (char)attr; + //screenGUI[pos] = initChar; + disperseAttribute(pos,attr); + + } + + protected void setScreenFieldAttr(int pos, int attr) { + + screenField[pos] = (char)attr; + + } + + protected final void setChar(int pos, char c) { + screenIsChanged[pos] = screen[pos] == c ? '0' : '1'; + screen[pos] = c; + if (screenIsAttr[pos] == 1) + setScreenCharAndAttr(pos,c,32,false); + + } + + protected final char getChar(int pos) { + return screen[pos]; + } + + protected final int getCharAttr(int pos) { + return screenAttr[pos]; + } + + protected final boolean isAttributePlace(int pos) { + return screenIsAttr[pos] == 1 ? true : false; + } + + public final void setUseGUI(int pos, int which) { + + screenIsChanged[pos] = screenGUI[pos] == which ? '0' : '1'; + screenGUI[pos] = (char)which; + } + + private void disperseAttribute(int pos, int attr) { + + char c = 0; + char cs = 0; + char ul = 0; + char nd = 0; + + if(attr == 0) + return; + + switch(attr) { + case 32: // green normal + c = ATTR_32; + break; + + case 33: // green/revers + c = ATTR_33; + break; + + case 34: // white normal + c = ATTR_34; + break; + + case 35: // white/reverse + c = ATTR_35; + break; + + case 36: // green/underline + c = ATTR_36; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 37: // green/reverse/underline + c = ATTR_37; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 38: // white/underline + c = ATTR_38; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 39: + nd = EXTENDED_5250_NON_DSP; + break; + + case 40: + case 42: // red/normal + c = ATTR_40; + break; + + case 41: + case 43: // red/reverse + c = ATTR_41; + break; + + case 44: + case 46: // red/underline + c = ATTR_44; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 45: // red/reverse/underline + c = ATTR_45; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 47: + nd = EXTENDED_5250_NON_DSP; + break; + + case 48: + c = ATTR_48; + cs = EXTENDED_5250_COL_SEP; + break; + + case 49: + c = ATTR_49; + cs = EXTENDED_5250_COL_SEP; + break; + + case 50: + c = ATTR_50; + cs = EXTENDED_5250_COL_SEP; + break; + + case 51: + c = ATTR_51; + cs = EXTENDED_5250_COL_SEP; + break; + + case 52: + c = ATTR_52; + // colSep = true; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 53: + c = ATTR_53; + // colSep = true; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 54: + c = ATTR_54; + // colSep = true; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 55: + nd = EXTENDED_5250_NON_DSP; + break; + + case 56: // pink + c = ATTR_56; + break; + + case 57: // pink/reverse + c = ATTR_57; + break; + + case 58: // blue/reverse + c = ATTR_58; + break; + + case 59: // blue + c = ATTR_59; + break; + + case 60: // pink/underline + c = ATTR_60; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 61: // pink/reverse/underline + c = ATTR_61; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 62: // blue/underline + c = ATTR_62; + ul = EXTENDED_5250_UNDERLINE; + break; + + case 63: // nondisplay + nd = EXTENDED_5250_NON_DSP; + cs = EXTENDED_5250_COL_SEP; + break; + default: + c = ( COLOR_BG_BLACK << 8 & 0xff00) | + ( COLOR_FG_YELLOW & 0xff); + break; + + } + + screenColor[pos] = c; + screenExtended[pos] = (char)(ul | cs | nd); + } + + protected void initalizePlanes () { + + char c = (COLOR_BG_BLACK << 8 & 0xff00) | + (COLOR_FG_GREEN & 0xff); + + for (int y = 0;y < screenSize; y++) { + + screenAttr[y] = initAttr; + screenColor[y] = c; + + } + + // here we will just copy the initialized plane onto the other planes + // using arraycopy which will be faster. I hope. + + System.arraycopy(initArray,0,screen,0,screenSize); + System.arraycopy(initArray,0,screenGUI,0,screenSize); + System.arraycopy(initArray,0,screenIsAttr,0,screenSize); + System.arraycopy(initArray,0,screenExtended,0,screenSize); + System.arraycopy(initArray,0,fieldExtended,0,screenSize); + System.arraycopy(initArray,0,screenField,0,screenSize); + } + + protected void initalizeFieldPlanes () { + System.arraycopy(initArray,0,fieldExtended,0,screenSize); + System.arraycopy(initArray,0,screenField,0,screenSize); + } + + protected final int getWhichGUI(int pos) { + + return screenGUI[pos]; + } + + protected final boolean isChanged(int pos) { + return screenIsChanged[pos] == 0 ? false : true; + } + + protected final boolean isUseGui(int pos) { + return screenGUI[pos] == NO_GUI ? false : true; + } + + /** + * Return the data associated with the plane that is passed. + * + * @param from Position from which to start + * @param to Position to end + * @param plane From which plane to obtain the data + * @return Character array containing the data requested + */ + protected synchronized char[] getPlaneData(int from, int to, int plane) { + + int len = (to - from); + + char[] planeChars = new char[len + 1]; + + switch (plane) { + case PLANE_TEXT: + System.arraycopy(screen, from, planeChars, 0, len); + break; + case PLANE_ATTR: + System.arraycopy(screenAttr, from, planeChars, 0, len); + break; + case PLANE_COLOR: + System.arraycopy(screenColor, from, planeChars, 0, len); + break; + case PLANE_EXTENDED: + System.arraycopy(screenExtended, from, planeChars, 0, len); + break; + case PLANE_EXTENDED_GRAPHIC: + System.arraycopy(screenGUI, from, planeChars, 0, len); + break; + case PLANE_FIELD: + System.arraycopy(screenField, from, planeChars, 0, len); + break; + case PLANE_IS_ATTR_PLACE: + System.arraycopy(screenIsAttr, from, planeChars, 0, len); + break; + default: + System.arraycopy(screen, from, planeChars, 0, len); + + } + return planeChars; + + } + + /** + * Converts a linear presentation space position to its corresponding row. + * + * @param pos The position to be converted + * @return The row which corresponds to the position given + * @throws OhioException + */ + private int convertPosToRow(int pos) { + + return (pos / numCols) + 1; + + } + + /** + * Converts a linear presentation space position to its corresponding column. + * + * @param pos The position to be converted + * @return The column which corresponds to the position given + * @throws OhioException + */ + private int convertPosToColumn(int pos) { + + return (pos % numCols) + 1; + + } + + /** + * + * Converts a row and column coordinate to its corresponding linear position. + * + * @param row - The row of the coordinate + * @param col - The column of the coordinate + * @return The linear position which corresponds to the coordinate given. + * @throws OhioException + */ + private int convertRowColToPos(int row, int col) { + + + return (row - 1) * numCols + col -1; + + } + + + /** + *

+ * GetScreen retrieves the various planes associated with the presentation + * space. The data is returned as a linear array of character values in the + * array provided. The array is not terminated by a null character except + * when data is retrieved from the text plane, in which case a single null + * character is appended. + *

+ *

+ * The application must supply a buffer for the returned data and the length + * of the buffer. Data is returned starting from the beginning of the + * presentation space and continuing until the buffer is full or the entire + * plane has been copied. For text plane data, the buffer must include one + * extra position for the terminating null character. + *

+ * + * @param buffer + * @param bufferLength + * @param plane + * @return The number of characters copied to the buffer + * @throws OhioException + */ + public synchronized int GetScreen(char buffer[], int bufferLength, int plane) { + + return GetScreen(buffer,bufferLength,0,screenSize,plane); + + } + + /** + *

+ * GetScreen retrieves the various planes associated with the presentation + * space. The data is returned as a linear array of character values in the + * array provided. The array is not terminated by a null character except + * when data is retrieved from the text plane, in which case a single null + * character is appended. + *

+ *

+ * The application must supply a buffer for the returned data and the length + * of the buffer. Data is returned starting from the given position and + * continuing until the specified number of characters have been copied, the + * buffer is full or the entire plane has been copied. For text plane data, + * the buffer must include one extra position for the terminating null character. + *

+ * + * @param buffer + * @param bufferLength + * @param from + * @param length + * @param plane + * @return The number of characters copied to the buffer + * @throws OhioException + */ + public synchronized int GetScreen(char buffer[], int bufferLength, int from, + int length, int plane) + { + // if(buffer == null) + // throw new OhioException(sessionVT.getSessionConfiguration(), + // OhioScreen.class.getName(), "osohio.screen.ohio00300", 1); + if(buffer == null) + return 0; + + int min = Math.min(Math.min(buffer.length, bufferLength), screenSize); + if ((from + min) > screenSize) { + min = screenSize - from; + } + + char[] pd = getPlaneData(from,from + min,plane); + if(pd != null) { + System.arraycopy(pd, 0, buffer, 0, min); + return pd.length; + } + + return 0; + } + + /** + *

+ * GetScreen retrieves the various planes associated with the presentation + * space. The data is returned as a linear array of character values in the + * array provided. The array is not terminated by a null character except + * when data is retrieved from the text plane, in which case a single null + * character is appended. + *

+ *

+ * The application must supply a buffer for the returned data and the length + * of the buffer. Data is returned starting from the given coordinates and + * continuing until the specified number of characters have been copied, + * the buffer is full, or the entire plane has been copied. For text plane + * data, the buffer must include one extra position for the terminating null + * character. + *

+ * + * @param buffer + * @param bufferLength + * @param row + * @param col + * @param length + * @param plane + * @return The number of characters copied to the buffer. + * @throws OhioException + */ + public synchronized int GetScreen(char buffer[], int bufferLength, int row, + int col, int length, int plane) + // throws OhioException { + { + // Call GetScreen function after converting row and column to + // a position. + return GetScreen(buffer,bufferLength, convertRowColToPos(row,col), + length, plane); + } + + /** + *

+ * GetScreenRect retrieves data from the various planes associated with the + * presentation space. The data is returned as a linear array of character + * values in the buffer provided. + *

+ * + *

+ * The application supplies two positions that represent opposing corners of + * a rectangle within the presentation space. The starting and ending + * positions can have any spatial relationship to each other. The data + * returned starts from the row containing the upper-most point to the row + * containing the lower-most point, and from the left-most column to the + * right-most column. + *

+ *

+ * The specified buffer must be at least large enough to contain the number + * of characters in the rectangle. If the buffer is too small, no data is + * copied and zero is returned by the method. Otherwise, the method returns + * the number of characters copied. + *

+ * + * @param buffer + * @param bufferLength + * @param startPos + * @param endPos + * @param plane + * @return The number of characters copied to the buffer + * @throws OhioException + */ + protected int GetScreenRect(char buffer[], int bufferLength, + int startPos, int endPos, int plane) + // throws OhioException { + { + // We will use the row,col routine here because it is easier to use + // row colum than it is for position since I wrote the other first and + // am to lazy to implement it here + // Maybe it would be faster to do it the other way? + int startRow = convertPosToRow(startPos); + int startCol = convertPosToColumn(startPos); + int endRow = convertPosToRow(endPos); + int endCol = convertPosToColumn(endPos); + return GetScreenRect(buffer, bufferLength, startRow, startCol, + endRow, endCol, plane); + + } + + /** + *

+ * GetScreenRect retrieves data from the various planes associated with the + * presentation space. The data is returned as a linear array of character + * values in the buffer provided. The buffer is not terminated by a null + * character. + *

+ *

+ * The application supplies two coordinates that represent opposing corners + * of a rectangle within the presentation space. The starting and ending + * coordinates can have any spatial relationship to each other. The data + * returned starts from the row containing the upper-most point to the row + * containing the lower-most point, and from the left-most column to the + * right-most column. + *

+ *

+ * The specified buffer must be at least large enough to contain the number + * of characters in the rectangle. If the buffer is too small, no data is + * copied and zero is returned by the method. Otherwise, the method returns + * the number of characters copied. + *

+ * + * @param buffer + * @param bufferLength + * @param startRow + * @param startCol + * @param endRow + * @param endCol + * @param plane + * @return The number characters copied to the buffer + * @throws OhioException + */ + protected int GetScreenRect(char buffer[], int bufferLength, + int startRow, int startCol, + int endRow, int endCol, int plane) + // throws OhioException { + { + // number of bytes obtained + int numBytes = 0; + + // lets check the row range. If they are reversed then we need to + // place them in the correct order. + if(startRow > endRow) { + int r = startRow; + startRow = endRow; + endRow = r; + } + // lets check the column range. If they are reversed then we need to + // place them in the correct order. + if(startCol > endCol) { + int c = startCol; + startCol = endCol; + endCol = c; + } + int numCols = (endCol - startCol) + 1; + int numRows = (endRow - startRow) + 1; + + // lets make sure it is within the bounds of the character array passed + // if not the return as zero bytes where read as per documentation. + if(numCols * numRows <= bufferLength) { + + // make sure it is one larger. I guess for other languanges to + // reference like in C which is terminated by a zero byte at the end + // of strings. + char cb[] = new char[numCols + 1]; + int charOffset = 0; + int bytes = 0; + + // now let's loop through and get the screen information for + // each row; + for(int row = startRow; row <= endRow;) { + if((bytes = GetScreen(cb, cb.length, row, startCol, numCols, plane)) != 0) { + System.arraycopy(cb, 0, buffer, charOffset, numCols); + } + row++; + charOffset += numCols; + // make sure we count the number of bytes returned + numBytes += bytes; + } + + } + + return numBytes; + } + + protected boolean checkHotSpots () { + + Screen5250 s = scr; + int lenScreen = scr.getScreenLength(); + boolean hs = false; + boolean retHS = false; + StringBuffer hsMore = s.getHSMore(); + StringBuffer hsBottom = s.getHSBottom(); + + for (int x = 0; x < lenScreen; x++) { + + hs =false; + if (s.isInField(x,false)) + continue; + + // First check for PF keys + if (x > 0 && screen[x] == 'F') { + if (screen[x + 1] >= '0' && + screen[x + 1] <= '9' && + screen[x - 1] <= ' ' && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0) { + + if (screen[x + 2] >= '0' && + screen[x + 2] <= '9' && + (screen[x + 3] == '=' || + screen[x + 3] == '-' || + screen[x + 3] == '/') ) + hs = true; + else + if ( screen[x + 2] == '=' || + screen[x + 3] == '-' || + screen[x + 3] == '/') + hs = true; + + if (hs) { + screenGUI[x] = BUTTON_LEFT; + + int ns = 0; + int row = x / numCols; + while (ns < 2 && ++x / numCols == row) { + if (screen[x] <= ' ') + ns++; + else + ns = 0; + if (ns <2) + screenGUI[x] = BUTTON_MIDDLE; + + } + + // now lets go back and take out gui's that do not belong + while (screen[--x] <= ' ') { + screenGUI[x] = NO_GUI; + } + screenGUI[x] = BUTTON_RIGHT; + + } + } + } + + // now lets check for menus + if (!hs && x > 0 && x < lenScreen - 2 && + screen[x] == '.' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_UNDERLINE) == 0 && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + + int os = 0; + if ((os = isOption(screen,x,lenScreen,2,3,'.') )> 0) { + hs = true; + + int stop = x; + int ns = 0; + int row = stop / numCols; + + while (++stop / numCols == row && + (screen[stop] >= ' ' || + screen[stop] == 0x0) ) { + + if (screen[stop] <= ' ') { + ns++; + } + else + ns = 0; + + if (screen[stop] == '.') { + int io = 0; + if ((io = isOption(screen,stop,lenScreen,2,3,'.')) > 0) { + + stop = io; + break; + } + } + + if (ns > 3) + break; + } + + screenGUI[++os] = BUTTON_LEFT; + s.setDirty(os); + + while (++os < stop) { + screenGUI[os] = BUTTON_MIDDLE; + s.setDirty(os); + } + + // now lets go back and take out gui's that do not belong + while (screen[--stop] <= ' ') { + screenGUI[stop] = NO_GUI; + s.setDirty(stop); + } + screenGUI[stop] = BUTTON_RIGHT; + s.setDirty(stop); + + } + } + + // now lets check for options. + if (!hs && x > 0 && x < lenScreen - 2 && + screen[x] == '=' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_UNDERLINE) == 0 && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + + int os = 0; + if ((os = isOption(screen,x,lenScreen,2,2,'=') )> 0) { + hs = true; + + int stop = x; + int ns = 0; + int row = stop / numCols; + + while (++stop / numCols == row && + screen[stop] >= ' ') { + + if (screen[stop] == ' ') { + ns++; + } + else + ns = 0; + + if (screen[stop] == '=') { + int io = 0; + if ((io = isOption(screen,stop,lenScreen,2,2,'=')) > 0) { + + stop = io; + break; + } + } + + if (ns > 2) + break; + } + + screenGUI[++os] = BUTTON_LEFT; + s.setDirty(os); + + while (++os < stop) { + screenGUI[os] = BUTTON_MIDDLE; + s.setDirty(os); + + } + + // now lets go back and take out gui's that do not belong + while (screen[--stop] <= ' ') { + screenGUI[stop] = NO_GUI; + s.setDirty(stop); + + } + screenGUI[stop] = BUTTON_RIGHT; + s.setDirty(stop); + } + } + + // now lets check for More... . + + if (!hs && x > 2 && x < lenScreen - hsMore.length() && + screen[x] == hsMore.charAt(0) && + screen[x - 1] <= ' ' && + screen[x - 2] <= ' ' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + + boolean mFlag = true; + int ms = hsMore.length(); + int mc = 0; + while (++mc < ms) { + if (screen[x+mc] != hsMore.charAt(mc)) { + mFlag = false; + break; + } + + } + + if (mFlag) { + hs = true; + + screenGUI[x] = BUTTON_LEFT_DN; + + while (--ms > 0) { + screenGUI[++x] = BUTTON_MIDDLE_DN; + + } + screenGUI[x] = BUTTON_RIGHT_DN; + } + } + + // now lets check for Bottom . + if (!hs && x > 2 && x < lenScreen - hsBottom.length() && + screen[x] == hsBottom.charAt(0) && + screen[x - 1] <= ' ' && + screen[x - 2] <= ' ' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + + boolean mFlag = true; + int bs = hsBottom.length(); + int bc = 0; + while (++bc < bs) { + if (screen[x+bc] != hsBottom.charAt(bc)) { + mFlag = false; + break; + } + + } + + if (mFlag) { + hs = true; + + screenGUI[x] = BUTTON_LEFT_UP; + + while (--bs > 0) { + screenGUI[++x] = BUTTON_MIDDLE_UP; + + } + screenGUI[x] = BUTTON_RIGHT_UP; + } + } + + // Submitted by Richard Houston of RLH Consulting rhouston@rlhc.net + // now lets check for HTTP:// or HTTPS://. + if (!hs && x > 0 && x < lenScreen - 7 && + Character.toLowerCase(screen[x]) == 'h' && + screen[x - 1] <= ' ' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + + if (Character.toLowerCase(screen[x+1]) == 't' && + Character.toLowerCase(screen[x+2]) == 't' && + Character.toLowerCase(screen[x+3]) == 'p' && + screen[x+4] == ':' && + screen[x+5] == '/' && + screen[x+6] == '/' ) { + + hs = true; + + screenGUI[x] = BUTTON_LEFT_EB; + + while (screen[++x] > ' ') { + screenGUI[x] = BUTTON_MIDDLE_EB; + + } + + screenGUI[--x] = BUTTON_RIGHT_EB; + } + + else if (Character.toLowerCase(screen[x+1]) == 't' && + Character.toLowerCase(screen[x+2]) == 't' && + Character.toLowerCase(screen[x+3]) == 'p' && + Character.toLowerCase(screen[x+4]) == 's' && + screen[x+5] == ':' && + screen[x+6] == '/' && + screen[x+7] == '/' ) { + + hs = true; + + screenGUI[x] = BUTTON_LEFT_EB; + + while (screen[++x] > ' ') { + screenGUI[x] = BUTTON_MIDDLE_EB; + + } + + screenGUI[--x] = BUTTON_RIGHT_EB; + } + + } + // now lets check for MAILTO: . + else if (!hs && x > 0 && x < lenScreen - 7 && + Character.toLowerCase(screen[x]) == 'm' && + screen[x - 1] <= ' ' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + + if (Character.toLowerCase(screen[x+1]) == 'a' && + Character.toLowerCase(screen[x+2]) == 'i' && + Character.toLowerCase(screen[x+3]) == 'l' && + Character.toLowerCase(screen[x+4]) == 't' && + Character.toLowerCase(screen[x+5]) == 'o' && + screen[x+6] == ':') { + + hs = true; + + screenGUI[x] = BUTTON_LEFT_EB; + + while (screen[++x] > ' ') { + screenGUI[x] = BUTTON_MIDDLE_EB; + + } + screenGUI[--x] = BUTTON_RIGHT_EB; + } + } + // now lets check for External Program: . + else if (!hs && x > 0 && x < lenScreen - 7 && + screen[x - 1] <= ' ' && + screenGUI[x] == NO_GUI && + (screenExtended[x] & EXTENDED_5250_NON_DSP) == 0 + ) { + Properties etnProps = ExternalProgramConfig.getInstance().getEtnPgmProps(); + String count = etnProps.getProperty("etn.pgm.support.total.num"); + if(count != null && count.length() > 0){ + int total = Integer.parseInt(count); + for(int i=1;i<=total;i++){ + String program = etnProps.getProperty("etn.pgm."+i+".command.name"); + String key=""; + if(x + program.length() >= screen.length) break; + for(int j=0;j<=program.length();j++){ + key+=screen[x+j]; + } + if(key.toLowerCase().equals(program.toLowerCase()+":")) { + hs = true; + screenGUI[x] = BUTTON_LEFT_EB; + while (screen[++x] > ' ') { + screenGUI[x] = BUTTON_MIDDLE_EB; + } + screenGUI[--x] = BUTTON_RIGHT_EB; + break; + } + } + } + } + + if (!retHS && hs) + retHS = true; + + } + + return retHS; + } + + private int isOption(char[] screen, + int x, + int lenScreen, + int numPref, + int numSuff, + char suff) { + boolean hs =true; + int sp = x; + int os = 0; + // check to the left for option + while (--sp >=0 && screen[sp] <= ' ' ) { + + if (x - sp > numPref || screen[sp] == suff|| + screen[sp] == '.' || + screen[sp] == '*') { + hs =false; + break; + } + } + + // now lets check for how long the option is it has to be numPref or less + os = sp; + while (hs && --os > 0 && screen[os] > ' ' ) { + + if (sp - os >= numPref || screen[os] == suff || + screen[os] == '.' || + screen[os] == '*') { + hs = false; + break; + } + } + if (sp - os > 1 && !Character.isDigit(screen[os+1])) { + hs = false; + } + + sp = x; + + if (Character.isDigit(screen[sp+1])) + hs = false; + // now lets make sure there are no more than numSuff spaces after option + while (hs && (++sp < lenScreen && screen[sp] <= ' ' + || screen[sp] == suff )) { + if (sp - x >= numSuff || screen[sp] == suff || + screen[sp] == '.' || + screen[sp] == '*') { + hs =false; + break; + } + } + if (hs && !Character.isLetterOrDigit(screen[sp])) + hs = false; + if (hs) { + return os; + } + return -1; + } + +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/Stream5250.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/Stream5250.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,173 @@ +/** + * Title: tn5250J + * Copyright: Copyright (c) 2001 + * Company: + * @author Kenneth J. Pouncey + * @version 0.4 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +public class Stream5250 { + + public int streamSize; + public int opCode; + public int dataStart; + public int pos; + public byte buffer[]; + + public Stream5250(byte abyte0[]) { + buffer = abyte0; + // size without end of record 0xFF 0xEF + streamSize = (abyte0[0] & 0xff) << 8 | abyte0[1] & 0xff; + opCode = abyte0[9]; + dataStart = 6 + abyte0[6]; + pos = dataStart; + } + + public Stream5250() { + buffer = null; + streamSize = 0; + opCode = 0; + dataStart = 0; + pos = dataStart; + } + + /** + * This method takes a byte array and initializes the object information + * to be used. + * + * @param abyte0 + */ + public void initialize(byte abyte0[]) { + + buffer = abyte0; + // size without end of record 0xFF 0xEF + streamSize = (abyte0[0] & 0xff) << 8 | abyte0[1] & 0xff; + opCode = abyte0[9]; + dataStart = 6 + abyte0[6]; + pos = dataStart; + + } + + public final int getOpCode() { + return opCode; + } + + public final byte getNextByte() + throws Exception { + if(buffer == null || pos > buffer.length) + throw new Exception("Buffer length exceeded: " + pos); + else + return buffer[pos++]; + } + + public final void setPrevByte() + throws Exception { + if(pos == 0) { + throw new Exception("Index equals zero."); + } + else { + pos--; + return; + } + } + + /** + * Returns where we are in the buffer + * @return position in the buffer + */ + public final int getCurrentPos() { + return pos; + } + + public final byte getByteOffset(int off) + throws Exception { + + if(buffer == null || (pos + off ) > buffer.length) + throw new Exception("Buffer length exceeded: " + pos); + else + return buffer[pos + off]; + + } + + public final boolean size() { + return pos >= streamSize; + } + + + /** + * Determines if any more bytes are available in the buffer to be processed. + * @return yes or no + */ + public final boolean hasNext() { + +// return pos >= buffer.length; + return pos < streamSize; + } + + /** + * This routine will retrieve a segment based on the first two bytes being + * the length of the segment. + * + * @return a new byte array containing the bytes of the segment. + * @throws Exception + */ + public final byte[] getSegment() throws Exception { + + // The first two bytes contain the length of the segment. + int length = ((buffer[pos] & 0xff )<< 8 | (buffer[pos+1] & 0xff)); + // allocate space for it. + byte[] segment = new byte[length]; + + getSegment(segment,length,true); + + return segment; + } + + + /** + * This routine will retrieve a byte array based on the first two bytes being + * the length of the segment. + * + * @param segment - byte array + * @param length - length of segment to return + * @param adjustPos - adjust the position of the buffer to the end of the seg + * ment + * @throws Exception + */ + public final void getSegment(byte[] segment, int length, boolean adjustPos) + throws Exception { + + // If the length is larger than what is available throw an exception + if((pos + length ) > buffer.length) + throw new Exception("Buffer length exceeded: start " + pos + + " length " + length); + // use the system array copy to move the bytes from the buffer + // to the allocated byte array + System.arraycopy(buffer,pos,segment,0,length); + + // update the offset to be after the segment so the next byte can be read + if (adjustPos) + pos +=length; + + } + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/WTDSFParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/WTDSFParser.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,976 @@ +/** + * Title: tn5250J + * Copyright: Copyright (c) 2001 + * Company: + * @author Kenneth J. Pouncey + * @version 0.5 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +import static org.tn5250j.TN5250jConstants.BOTTOM; +import static org.tn5250j.TN5250jConstants.GUI_LEFT; +import static org.tn5250j.TN5250jConstants.GUI_RIGHT; +import static org.tn5250j.TN5250jConstants.LOWER_LEFT; +import static org.tn5250j.TN5250jConstants.LOWER_RIGHT; +import static org.tn5250j.TN5250jConstants.NO_GUI; +import static org.tn5250j.TN5250jConstants.NR_REQUEST_ERROR; +import static org.tn5250j.TN5250jConstants.UPPER; +import static org.tn5250j.TN5250jConstants.UPPER_LEFT; +import static org.tn5250j.TN5250jConstants.UPPER_RIGHT; + +import java.util.ArrayList; +import java.util.List; + +import org.tn5250j.encoding.ICodePage; +import org.tn5250j.tools.logging.TN5250jLogFactory; +import org.tn5250j.tools.logging.TN5250jLogger; + +/** + * + * Write To Display Structured Field: + * + * This module will parse the structured field information for enhanced + * emulation mode. + * + */ +public class WTDSFParser { + + private Screen5250 screen52; + private tnvt vt; + private ICodePage codePage; + int pos; + byte[] segment; + int length; + boolean error; + boolean guiStructsExist; + + private TN5250jLogger log = TN5250jLogFactory.getLogger(this.getClass()); + + private final List guiStructs = new ArrayList(3); + private final List choices = new ArrayList(3); + + + WTDSFParser (tnvt vt) { + + this.vt = vt; + screen52 = vt.screen52; + codePage = vt.codePage; + + } + + protected class ChoiceField { + + int x; + int y; + int row; + int col; + int width; + int height; + char mnemonic; + int fieldId; + int selectIndex; + + ChoiceField(int row, int col, int fldRow, int fldCol) { + x = row; + y = col; + row = fldRow; + col = fldCol; + } + } + + protected class Window { + + byte[] window; + int pos; + + Window(byte[] seg, int pos) { + + //log.info("window created at " + pos); + window = seg; + this.pos = pos; + guiStructsExist = true; + } + + } + + protected void addChoiceField(int row,int col,int fldRow, int fldCol, String text) { + + ChoiceField cf = new ChoiceField(row,col, fldRow, fldCol); + cf.fieldId = screen52.getScreenFields().getCurrentField().getFieldId(); + choices.add(cf); + + } + + protected boolean isGuisExists () { + + return guiStructsExist; + + } + + protected byte[] getSegmentAtPos(int pos) { + int len = guiStructs.size(); + for (int x = 0; x < len; x++) { + Window w = guiStructs.get(x); + if (w.pos == pos) + return w.window; + } + + return null; + + } + + protected void clearGuiStructs() { + + guiStructs.clear(); + } + + protected boolean parseWriteToDisplayStructuredField(byte[] seg) { + +// bk = vt.bk; + + error = false; + boolean done = false; + boolean windowDefined = false; +// int nextone; + pos = 0; + segment = seg; + +// try { + length = (( segment[pos++] & 0xff )<< 8 | (segment[pos++] & 0xff)); + + while (!done) { + int s = segment[pos++] & 0xff; + switch (s) { + + case 0xD9: // Class Type 0xD9 - Create Window + + switch (segment[pos++]) { + case 0x50: // Define Selection Field + + defineSelectionField(length); + done = true; + break; + case 0x51: // Create Window + + guiStructs.add(new Window(segment, screen52.getLastPos())); + + boolean cr = false; + int rows = 0; + int cols = 0; + // pull down not supported yet + if ((segment[pos++] & 0x80) == 0x80) + cr = true; // restrict cursor + pos++; // get reserved field pos 6 + pos++; // get reserved field pos 7 + rows = segment[pos++]; // get window depth rows pos 8 + cols = segment[pos++]; // get window width cols pos 9 + length -= 9; + if (length == 0) { + done = true; +// System.out.println("Create Window"); +// System.out.println(" restrict cursor " + cr); +// System.out.println(" Depth = " + rows + " Width = " + cols); +// screen52.createWindow(rows,cols,1,true,32,58, + createWindow(rows,cols,1,true,32,58, + '.', + '.', + '.', + ':', + ':', + ':', + '.', + ':'); + windowDefined = true; + break; + } + + // pos 10 is Minor Structure + int ml = 0; + int type = 0; + int lastPos = screen52.getLastPos(); +// if (cr) +// screen52.setPendingInsert(true, +// screen52.getCurrentRow(), +// screen52.getCurrentCol()); + int mAttr = 0; + int cAttr = 0; + + while (length > 0) { + + // get minor length + ml = ( segment[pos++] & 0xff ); + length -= ml; + + // only normal windows are supported at this time + type = segment[pos++]; + + switch (type) { + + case 0x01 : // Border presentation + boolean gui = false; + if ((segment[pos++] & 0x80) == 0x80) + gui = true; + mAttr = segment[pos++]; + cAttr = segment[pos++]; + + char ul = '.'; + char upper = '.'; + char ur = '.'; + char left = ':'; + char right = ':'; + char ll = ':'; + char bottom = '.'; + char lr = ':'; + + // if minor length is greater than 5 then + // the border characters are specified + if (ml > 5) { + ul = codePage.ebcdic2uni(segment[pos++]); +// ul = getASCIIChar(segment[pos++]); + if (ul == 0) + ul = '.'; + + upper = codePage.ebcdic2uni(segment[pos++]); +// upper = getASCIIChar(segment[pos++]); + if (upper == 0) + upper = '.'; + + ur = codePage.ebcdic2uni(segment[pos++]); +// ur = getASCIIChar(segment[pos++]); + if (ur == 0) + ur = '.'; + + left = codePage.ebcdic2uni(segment[pos++]); +// left = getASCIIChar(segment[pos++]); + if (left == 0) + left = ':'; + + right = codePage.ebcdic2uni(segment[pos++]); +// right = getASCIIChar(segment[pos++]); + if (right == 0) + right = ':'; + + ll = codePage.ebcdic2uni(segment[pos++]); +// ll = getASCIIChar(segment[pos++]); + if (ll == 0) + ll = ':'; + + bottom = codePage.ebcdic2uni(segment[pos++]); +// bottom = getASCIIChar(segment[pos++]); + if (bottom == 0) + bottom = '.'; + + lr = codePage.ebcdic2uni(segment[pos++]); +// lr = getASCIIChar(segment[pos++]); + if (lr == 0) + lr = ':'; + } + +// System.out.println("Create Window"); +// System.out.println(" restrict cursor " + cr); +// System.out.println(" Depth = " + rows + " Width = " + cols); +// System.out.println(" type = " + type + " gui = " + gui); +// System.out.println(" mono attr = " + mAttr + " color attr = " + cAttr); +// System.out.println(" ul = " + ul + " upper = " + upper + +// " ur = " + ur + +// " left = " + left + +// " right = " + right + +// " ll = " + ll + +// " bottom = " + bottom + +// " lr = " + lr +// ); +// screen52.createWindow(rows,cols,type,gui,mAttr,cAttr, + createWindow(rows,cols,type,gui,mAttr,cAttr, + ul, + upper, + ur, + left, + right, + ll, + bottom, + lr); + windowDefined = true; + break; + // + // The following shows the input for window with a title + // + // +0000 019A12A0 00000400 00020411 00200107 .?.?..?...?..?. + // +0010 00000018 00000011 06131500 37D95180 ........?.?..R?? + // +0020 00000A24 0D018023 23404040 40404040 ..??..??? + // +0030 40211000 000000D7 C2C1D9C4 C5D4D67A \uFFFD.....PBARDEMO: + // +0040 40D79996 879985A2 A2408281 99408485 Progress bar de + // +0050 94961108 1520D5A4 94828599 40968640 mo.???Number of + // +0060 8595A399 8985A24B 4B4B4B4B 4B7A2011 entries......:?. + // +0070 082E2040 404040F5 F0F06BF0 F0F02011 ?.? 500,000?. + // +0080 091520C3 A4999985 95A34085 95A399A8 \uFFFD??Current entry + // +0090 4095A494 8285994B 4B4B7A20 11092E20 number...:?.\uFFFD.? + // +00A0 40404040 4040F56B F0F0F020 110A1520 5,000?.??? + // +00B0 D9859481 89958995 87408595 A3998985 Remaining entrie + // +00C0 A24B4B4B 4B4B4B7A 20110A2E 20404040 s......:?.?.? + // +00D0 40F4F9F5 6BF0F0F0 20110C15 20E2A381 495,000?..??Sta + // +00E0 99A340A3 8994854B 4B4B4B4B 4B4B4B4B rt time......... + // +00F0 4B4B4B4B 7A20110C 2F2040F7 7AF5F37A ....:?...? 7:53: + + case 0x10 : // Window title/footer + if (!windowDefined) { +// screen52.createWindow(rows,cols,1,true,32,58, + guiStructs.add(new Window(segment, screen52.getLastPos())); + createWindow(rows,cols,1,true,32,58, + '.', + '.', + '.', + ':', + ':', + ':', + '.', + ':'); + windowDefined = true; + } + + byte orientation = segment[pos++]; + mAttr = segment[pos++]; + cAttr = segment[pos++]; + + //reserved + pos++; + ml -= 6; + + StringBuffer hfBuffer = new StringBuffer(ml); + while (ml-- > 0) { + //LDC - 13/02/2003 - Convert it to unicode + hfBuffer.append(codePage.ebcdic2uni(segment[pos++])); +// hfBuffer.append(getASCIIChar(segment[pos++])); + + } + + log.debug( + " orientation " + Integer.toBinaryString(orientation) + + " mAttr " + mAttr + + " cAttr " + cAttr + + " Header/Footer " + hfBuffer); + screen52.writeWindowTitle(lastPos, + rows, + cols, + orientation, + mAttr, + cAttr, + hfBuffer); + break; + default: + log.warn("Invalid Window minor structure"); + length = 0; + done = true; + } + + } + + done = true; + + break; + + case 0x53: // Scroll Bar + int sblen = 15; + byte sbflag = segment[pos++]; // flag position 5 + + pos++; // reserved position 6 + + // position 7,8 + int totalRowScrollable = (( segment[pos++] & 0xff )<< 8 + | (segment[pos++] & 0xff)); + + // position 9,10 + int totalColScrollable = (( segment[pos++] & 0xff )<< 8 + | (segment[pos++] & 0xff)); + + // position 11,12 + int sliderRowPos = (( segment[pos++] & 0xff )<< 8 + | (segment[pos++] & 0xff)); + + // position 13,14 + int sliderColPos = (( segment[pos++] & 0xff )<< 8 + | (segment[pos++] & 0xff)); + + // position 15 + int sliderRC = segment[pos++]; + + screen52.createScrollBar(sbflag,totalRowScrollable, + totalColScrollable, + sliderRowPos, + sliderColPos, + sliderRC); + length -= 15; + + done = true; + + break; + + case 0x5B: // Remove GUI ScrollBar field + + pos++; // reserved must be set to off pos 5 + pos++; // reserved must be set to zero pos 6 + + done = true; + break; + + case 0x5F: // Remove All GUI Constructs + log.info("remove all gui contructs"); + clearGuiStructs(); + guiStructsExist = false; + int len = 4; + int d = 0; + length -= s; + while (--len > 0) + d = segment[pos++]; +// if (length > 0) { +// len = (segment[pos++] & 0xff )<< 8; +// +// while (--len > 0) +// d = segment[pos++]; +// } + + screen52.clearGuiStuff(); + // per 14.6.13.4 documentation we should clear the + // format table after this command + screen52.clearTable(); + done = true; + break; + case 0x59: // remove gui window + log.info(" remove window at " + screen52.getCurrentPos()); + done = true; + break; + + case 0x60: // Erase/Draw Grid Lines - not supported + // do not know what they are + // as of 03/11/2002 we should not be getting + // this anymore but I will leave it here + // just in case. +// System.out.println("erase/draw grid lines " + length); + len = 6; + d = 0; + length -= 9; + while (--len > 0) + d = segment[pos++]; + if (length > 0) { + len = (segment[pos++] & 0xff )<< 8; + + while (--len > 0) { + d = segment[pos++]; + } + } + done = true; + break; + default: + vt.sendNegResponse(NR_REQUEST_ERROR,0x03,0x01,0x01,"invalid wtd structured field sub command " + + ( pos - 1)); +// + bk.getByteOffset(-1)); + error = true; + break; + } + break; + + default: + vt.sendNegResponse(NR_REQUEST_ERROR,0x03,0x01,0x01, + "invalid wtd structured field command " + + (pos - 1)); +// + bk.getByteOffset(-1)); + error = true; + break; + } + + if (error) + done = true; + + } +// } +// catch (Exception e) {}; + + return error; + + } + + /** + * Creates a window on the screen + * + * @param depth + * @param width + * @param type + * @param gui + * @param monoAttr + * @param colorAttr + * @param ul + * @param upper + * @param ur + * @param left + * @param right + * @param ll + * @param bottom + * @param lr + */ + protected void createWindow(int depth, int width, int type, boolean gui, + int monoAttr, int colorAttr, int ul, int upper, int ur, int left, + int right, int ll, int bottom, int lr) { + + int lastPos = screen52.getLastPos(); + int numCols = screen52.getColumns(); + + int c = screen52.getCol(lastPos); + int w = 0; + width++; + + w = width; + char initChar = Screen5250.initChar; + int initAttr = Screen5250.initAttr; + + // set leading attribute byte + screen52.setScreenCharAndAttr(initChar, initAttr, true); + + // set upper left + if (gui) { + screen52.setScreenCharAndAttr((char) ul, colorAttr, UPPER_LEFT, false); + } + else { + screen52.setScreenCharAndAttr((char) ul, colorAttr, false); + } + + // draw top row + while (w-- >= 0) { + if (gui) { + screen52.setScreenCharAndAttr((char) upper, colorAttr, UPPER,false); + } + else { + screen52.setScreenCharAndAttr((char) upper, colorAttr, false); + } + } + + // set upper right + if (gui) { + screen52.setScreenCharAndAttr((char) ur, colorAttr, UPPER_RIGHT, false); + } + else { + screen52.setScreenCharAndAttr((char) ur, colorAttr, false); + + } + + // set ending attribute byte + screen52.setScreenCharAndAttr(initChar, initAttr, true); + + lastPos = ((screen52.getRow(lastPos) + 1) * numCols) + c; + screen52.goto_XY(lastPos); + + // now handle body of window + while (depth-- > 0) { + + // set leading attribute byte + screen52.setScreenCharAndAttr(initChar, initAttr, true); + // set left + if (gui) { + screen52.setScreenCharAndAttr((char) left, colorAttr, GUI_LEFT, false); + } + else { + screen52.setScreenCharAndAttr((char) left, colorAttr, false); + + } + + w = width - 2; + screen52.setScreenCharAndAttr(initChar, initAttr, NO_GUI, true); + // fill it in + while (w-- >= 0) { +// if (!planes.isUseGui(screen52.getLastPos())) + screen52.setScreenCharAndAttr(initChar, initAttr, NO_GUI, false); + } + screen52.setScreenCharAndAttr(initChar, initAttr, NO_GUI, true); + + // set right + if (gui) { + screen52.setScreenCharAndAttr((char) right, colorAttr, GUI_RIGHT, false); + + } + else { + screen52.setScreenCharAndAttr((char) right, colorAttr, false); + + } + + screen52.setScreenCharAndAttr(initChar, initAttr, true); + + lastPos = ((screen52.getRow(lastPos) + 1) * numCols) + c; + screen52.goto_XY(lastPos); + } + + // set leading attribute byte + screen52.setScreenCharAndAttr(initChar, initAttr, true); + if (gui) { + screen52.setScreenCharAndAttr((char) ll, colorAttr, LOWER_LEFT, false); + + } + else { + screen52.setScreenCharAndAttr((char) ll, colorAttr, false); + + } + w = width; + + // draw bottom row + while (w-- >= 0) { + if (gui) { + screen52.setScreenCharAndAttr((char) bottom, colorAttr, BOTTOM, false); + } + else { + screen52.setScreenCharAndAttr((char) bottom, colorAttr, false); + + } + } + + // set lower right + if (gui) { + screen52.setScreenCharAndAttr((char) lr, colorAttr, LOWER_RIGHT, false); + } + else { + screen52.setScreenCharAndAttr((char) lr, colorAttr, false); + } + + // set ending attribute byte + screen52.setScreenCharAndAttr(initChar, initAttr, true); + + } + +/* *** NEVER USED LOCALLY ************************************************** */ +// private void clearWindowBody(ScreenPlanes planes, int startPos, int depth, int width) { +// +// int lastPos = startPos; +// char initChar = Screen5250.initChar; +// int initAttr = Screen5250.initAttr; +// +// // now handle body of window +// while (depth-- > 0) { +// +// // set leading attribute byte +//// planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); +//// setDirty(lastPos); +//// advancePos(); +//// +//// // set left +//// planes.setScreenCharAndAttr(lastPos, (char) left, colorAttr, false); +//// +//// if (gui) { +//// planes.setUseGUI(lastPos,GUI_LEFT); +//// } +//// setDirty(lastPos); +//// advancePos(); +// +// int w = width; +// // fill it in +// while (w-- >= 0) { +//// screen[lastPos].setCharAndAttr(initChar, initAttr, true); +// planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); +//// screen[lastPos].setUseGUI(NO_GUI); +// planes.setUseGUI(lastPos,NO_GUI); +//// setDirty(lastPos); +// lastPos++; +// advancePos(); +// } +// +//// // set right +//// // screen[lastPos].setCharAndAttr((char) right, colorAttr, false); +//// planes.setScreenCharAndAttr(lastPos,(char) right, colorAttr, false); +//// if (gui) { +//// // screen[lastPos].setUseGUI(RIGHT); +//// planes.setUseGUI(lastPos,GUI_RIGHT); +//// } +//// +//// setDirty(lastPos); +//// advancePos(); +//// +//// // set ending attribute byte +//// // screen[lastPos].setCharAndAttr(initChar, initAttr, true); +//// planes.setScreenCharAndAttr(lastPos,initChar, initAttr, true); +//// setDirty(lastPos); +// +// lastPos = startPos; +// } +// +// } + +/* *** NEVER USED LOCALLY ************************************************** */ +// private void setDirty(int pos) { +// +// screen52.setDirty(pos); +// +// } + +/* *** NEVER USED LOCALLY ************************************************** */ +// private void advancePos() { +// +// screen52.advancePos(); +// } + + private void defineSelectionField(int majLen) { + + // 0030: 20 00 2C 3E 00 00 00 69 12 A0 00 00 04 00 00 03 .,>...i........ + // 0040: 04 40 04 11 00 28 01 07 00 00 00 19 00 00 04 11 .@...(.......... + // 0050: 14 19 15 00 48 D9 50 00 60 00 11 01 84 84 00 00 ....H.P.`....... + // 0060: 05 03 01 01 00 00 00 13 01 E0 00 21 00 21 00 3B ...........!.!.; + // 0070: 22 20 20 20 20 3A 24 20 20 3A 0B 10 08 00 E0 00 " :$ :...... + // 0080: D6 95 85 40 40 0B 10 08 00 E0 00 E3 A6 96 40 40 ...@@.........@@ + // 0090: 0B 10 08 00 E0 00 E3 88 99 85 85 04 52 00 00 FF ............R... + // 00A0: EF . + try { + int flag1 = segment[pos++]; // Flag byte 1 - byte 5 + int flag2 = segment[pos++]; // Flag byte 2 - byte 6 + int flag3 = segment[pos++]; // Flag byte 3 - byte 7 + int typeSelection = segment[pos++]; // Type of selection Field - byte 8 + + // GUI Device Characteristics: + // This byte is used if the target device is a GUI PWS or a GUI-like + // NWS. If neigher of these WS are the targets, this byte is ignored + int guiDevice = segment[pos++]; // byte 9 + int withMnemonic = segment[pos++]; // byte 10 + int noMnemonic = segment[pos++]; // byte 11 + + pos++; // Reserved - byte 12 + pos++; // Reserved - byte 13 + + int cols = segment[pos++]; // Text Size - byte 14 + int rows = segment[pos++]; // Rows - byte 15 + + int maxColChoice = segment[pos++]; // byte 16 num of column choices + int padding = segment[pos++]; // byte 17 + int numSepChar = segment[pos++]; // byte 18 + int ctySepChar = segment[pos++]; // byte 19 + int cancelAID = segment[pos++]; // byte 20 + + int cnt = 0; + int minLen = 0; + majLen -= 21; + log.debug(" row: " + screen52.getCurrentRow() + + " col: " + screen52.getCurrentCol() + + " type " + typeSelection + + " gui " + guiDevice + + " withMnemonic " + Integer.toHexString(withMnemonic & 0xf0) + + " noMnemonic " + Integer.toHexString(noMnemonic & 0xf0) + + " noMnemonic " + Integer.toBinaryString(noMnemonic) + + " noMnemonicType " + Integer.toBinaryString((noMnemonic & 0xf0)) + + " noMnemonicSel " + Integer.toBinaryString((noMnemonic & 0x0f)) + + " maxcols " + maxColChoice + + " cols " + cols + + " rows " + rows); + int rowCtr = 0; + int colCtr = 0; + int chcRowStart = screen52.getCurrentRow(); + int chcColStart = screen52.getCurrentCol(); + int chcRow = chcRowStart; + int chcCol = chcColStart; + int chcPos = screen52.getPos(chcRow-1,chcCol); + +// client access +//0000 00 04 ac 9e b9 35 00 01 02 32 bb 4e 08 00 45 00 .....5...2.N..E. +//0010 00 3c 4f 8e 40 00 80 06 00 00 c1 a8 33 58 c1 a8 .= maxColChoice) { + + rowCtr++; + colCtr=0; + chcColStart = chcCol; + chcRowStart = chcRow + rowCtr; + if (rowCtr > rows) { + chcRowStart = chcRow; + rowCtr = 0; + chcColStart = chcColStart + 3 + cols + padding; + } + } + else { + chcColStart = chcColStart + padding + cols + 3; +// + } + + break; + default: + for (cnt = 2;cnt < minLen; cnt++) { + + pos++; + } + + } + + majLen -= minLen; + + } while (majLen > 0); + } + catch (Exception exc) { + log.warn(" defineSelectionField :", exc); + exc.printStackTrace(); + } + } + + // negotiating commands +// private static final byte IAC = (byte)-1; // 255 FF +// private static final byte DONT = (byte)-2; //254 FE +// private static final byte DO = (byte)-3; //253 FD +// private static final byte WONT = (byte)-4; //252 FC +// private static final byte WILL = (byte)-5; //251 FB +// private static final byte SB = (byte)-6; //250 Sub Begin FA +// private static final byte SE = (byte)-16; //240 Sub End F0 +// private static final byte EOR = (byte)-17; //239 End of Record EF +// private static final byte TERMINAL_TYPE = (byte)24; // 18 +// private static final byte OPT_END_OF_RECORD = (byte)25; // 19 +// private static final byte TRANSMIT_BINARY = (byte)0; // 0 +// private static final byte QUAL_IS = (byte)0; // 0 +// private static final byte TIMING_MARK = (byte)6; // 6 +// private static final byte NEW_ENVIRONMENT = (byte)39; // 27 +// private static final byte IS = (byte)0; // 0 +// private static final byte SEND = (byte)1; // 1 +// private static final byte INFO = (byte)2; // 2 +// private static final byte VAR = (byte)0; // 0 +// private static final byte VALUE = (byte)1; // 1 +// private static final byte NEGOTIATE_ESC = (byte)2; // 2 +// private static final byte USERVAR = (byte)3; // 3 + + // miscellaneous +// private static final byte ESC = 0x04; // 04 +// private static final char char0 = 0; + +// private static final byte CMD_READ_IMMEDIATE_ALT = (byte)0x83; // 131 + + +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/tn5250/tnvt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/tn5250/tnvt.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,2844 @@ +/** + * Title: tnvt.java + * Copyright: Copyright (c) 2001 Company: + * + * @author Kenneth J. Pouncey + * @version 0.5 + * + * Description: + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later version. + * + * This program 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 General Public License for more + * details. + * + * You should have received a copy of the GNU 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 + * + */ +package org.tn5250j.framework.tn5250; + +import static org.tn5250j.TN5250jConstants.AID_HELP; +import static org.tn5250j.TN5250jConstants.AID_PRINT; +import static org.tn5250j.TN5250jConstants.CMD_CLEAR_FORMAT_TABLE; +import static org.tn5250j.TN5250jConstants.CMD_CLEAR_UNIT; +import static org.tn5250j.TN5250jConstants.CMD_CLEAR_UNIT_ALTERNATE; +import static org.tn5250j.TN5250jConstants.CMD_READ_INPUT_FIELDS; +import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_FIELDS; +import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_IMMEDIATE_ALT; +import static org.tn5250j.TN5250jConstants.CMD_READ_SCREEN_IMMEDIATE; +import static org.tn5250j.TN5250jConstants.CMD_READ_SCREEN_TO_PRINT; +import static org.tn5250j.TN5250jConstants.CMD_RESTORE_SCREEN; +import static org.tn5250j.TN5250jConstants.CMD_ROLL; +import static org.tn5250j.TN5250jConstants.CMD_SAVE_SCREEN; +import static org.tn5250j.TN5250jConstants.CMD_WRITE_ERROR_CODE; +import static org.tn5250j.TN5250jConstants.CMD_WRITE_ERROR_CODE_TO_WINDOW; +import static org.tn5250j.TN5250jConstants.CMD_WRITE_STRUCTURED_FIELD; +import static org.tn5250j.TN5250jConstants.CMD_WRITE_TO_DISPLAY; +import static org.tn5250j.TN5250jConstants.NR_REQUEST_ERROR; +import static org.tn5250j.TN5250jConstants.PF1; +import static org.tn5250j.TN5250jConstants.PF10; +import static org.tn5250j.TN5250jConstants.PF11; +import static org.tn5250j.TN5250jConstants.PF12; +import static org.tn5250j.TN5250jConstants.PF13; +import static org.tn5250j.TN5250jConstants.PF14; +import static org.tn5250j.TN5250jConstants.PF15; +import static org.tn5250j.TN5250jConstants.PF16; +import static org.tn5250j.TN5250jConstants.PF17; +import static org.tn5250j.TN5250jConstants.PF18; +import static org.tn5250j.TN5250jConstants.PF19; +import static org.tn5250j.TN5250jConstants.PF2; +import static org.tn5250j.TN5250jConstants.PF20; +import static org.tn5250j.TN5250jConstants.PF21; +import static org.tn5250j.TN5250jConstants.PF22; +import static org.tn5250j.TN5250jConstants.PF23; +import static org.tn5250j.TN5250jConstants.PF24; +import static org.tn5250j.TN5250jConstants.PF3; +import static org.tn5250j.TN5250jConstants.PF4; +import static org.tn5250j.TN5250jConstants.PF5; +import static org.tn5250j.TN5250jConstants.PF6; +import static org.tn5250j.TN5250jConstants.PF7; +import static org.tn5250j.TN5250jConstants.PF8; +import static org.tn5250j.TN5250jConstants.PF9; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Arrays; +import java.util.Properties; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +import javax.net.ssl.SSLSocket; +import javax.swing.SwingUtilities; + +import org.tn5250j.Session5250; +import org.tn5250j.TN5250jConstants; +import org.tn5250j.encoding.CharMappings; +import org.tn5250j.encoding.ICodePage; +import org.tn5250j.framework.transport.SocketConnector; +import org.tn5250j.tools.logging.TN5250jLogFactory; +import org.tn5250j.tools.logging.TN5250jLogger; + +public final class tnvt implements Runnable { + + + // negotiating commands + private static final byte IAC = (byte) -1; // 255 FF + private static final byte DONT = (byte) -2; //254 FE + private static final byte DO = (byte) -3; //253 FD + private static final byte WONT = (byte) -4; //252 FC + private static final byte WILL = (byte) -5; //251 FB + private static final byte SB = (byte) -6; //250 Sub Begin FA + private static final byte SE = (byte) -16; //240 Sub End F0 + private static final byte EOR = (byte) -17; //239 End of Record EF + private static final byte TERMINAL_TYPE = (byte) 24; // 18 + private static final byte OPT_END_OF_RECORD = (byte) 25; // 19 + private static final byte TRANSMIT_BINARY = (byte) 0; // 0 + private static final byte QUAL_IS = (byte) 0; // 0 + private static final byte TIMING_MARK = (byte) 6; // 6 + private static final byte NEW_ENVIRONMENT = (byte) 39; // 27 + private static final byte IS = (byte) 0; // 0 + private static final byte SEND = (byte) 1; // 1 + private static final byte INFO = (byte) 2; // 2 + private static final byte VAR = (byte) 0; // 0 + private static final byte VALUE = (byte) 1; // 1 + private static final byte NEGOTIATE_ESC = (byte) 2; // 2 + private static final byte USERVAR = (byte) 3; // 3 + + // miscellaneous + private static final byte ESC = 0x04; // 04 + + private Socket sock; + private BufferedInputStream bin; + private BufferedOutputStream bout; + private final BlockingQueue dsq = new ArrayBlockingQueue(25); + private Stream5250 bk; + private DataStreamProducer producer; + protected Screen5250 screen52; + private boolean waitingForInput; + private boolean invited; + private boolean negotiated = false; + private Thread me; + private Thread pthread; + private int readType; + private boolean enhanced = true; + private Session5250 controller; + private boolean cursorOn = false; + private String session = ""; + private int port = 23; + private boolean connected = false; + private boolean support132 = true; + private ByteArrayOutputStream baosp = null; + private ByteArrayOutputStream baosrsp = null; + private int devSeq = -1; + private String devName; + private String devNameUsed; + private KbdTypesCodePages kbdTypesCodePage; + // WVL - LDC : TR.000300 : Callback scenario from 5250 + private boolean scan; // = false; + private static int STRSCAN = 1; + // WVL - LDC : 05/08/2005 : TFX.006253 - support STRPCCMD + private boolean strpccmd; // = false; + private String user; + private String password; + private String library; + private String initialMenu; + private String program; + private boolean keepTrucking = true; + private boolean pendingUnlock = false; + private boolean[] dataIncluded; + protected ICodePage codePage; + private boolean firstScreen; + private String sslType; + private WTDSFParser sfParser; + + private final TN5250jLogger log = TN5250jLogFactory.getLogger(this.getClass()); + + /** + * @param session + * @param screen52 + * @param type + * @param support132 + */ + public tnvt(Session5250 session, Screen5250 screen52, boolean type, boolean support132) { + + controller = session; + if (log.isInfoEnabled()) { + log.info(" new session -> " + controller.getSessionName()); + } + + enhanced = type; + this.support132 = support132; + setCodePage("37"); + this.screen52 = screen52; + dataIncluded = new boolean[24]; + + if (System.getProperties().containsKey("SESSION_CONNECT_USER")) { + user = System.getProperties().getProperty("SESSION_CONNECT_USER"); + if (System.getProperties().containsKey("SESSION_CONNECT_PASSWORD")) + password = System.getProperties().getProperty( + "SESSION_CONNECT_PASSWORD"); + if (System.getProperties().containsKey("SESSION_CONNECT_LIBRARY")) + library = System.getProperties().getProperty( + "SESSION_CONNECT_LIBRARY"); + if (System.getProperties().containsKey("SESSION_CONNECT_MENU")) + initialMenu = System.getProperties().getProperty( + "SESSION_CONNECT_MENU"); + if (System.getProperties().containsKey("SESSION_CONNECT_PROGRAM")) + program = System.getProperties().getProperty( + "SESSION_CONNECT_PROGRAM"); + } + + baosp = new ByteArrayOutputStream(); + baosrsp = new ByteArrayOutputStream(); + } + + public String getHostName() { + + return session; + } + + + public void setSSLType(String type) { + sslType = type; + } + + public void setDeviceName(String name) { + + devName = name; + + } + + public String getDeviceName() { + return devName; + } + + public String getAllocatedDeviceName() { + return devNameUsed; + } + + public boolean isConnected() { + + return connected; + } + + /** + * @return true when SSL is used and socket is connected. + * @see {@link #isConnected()} + */ + public boolean isSslSocket() { + if (this.connected && this.sock != null && this.sock instanceof SSLSocket) { + return true; + } else { + return false; + } + } + + public final void setProxy(String proxyHost, String proxyPort) { + + Properties systemProperties = System.getProperties(); + systemProperties.put("socksProxySet", "true"); + systemProperties.put("socksProxyHost", proxyHost); + systemProperties.put("socksProxyPort", proxyPort); + + System.setProperties(systemProperties); + log.info(" socks set "); + } + + public final boolean connect() { + + return connect(session, port); + + } + + + public final boolean connect(String s, int port) { + + // We will now see if there are any bypass signon parameters to be + // processed. The system properties override these parameters so + // have precidence if specified. + Properties props = controller.getConnectionProperties(); + if (user == null && props.containsKey("SESSION_CONNECT_USER")) { + user = props.getProperty("SESSION_CONNECT_USER"); + log.info(" user -> " + user + " " + controller.getSessionName()); + if (props.containsKey("SESSION_CONNECT_PASSWORD")) + password = props.getProperty("SESSION_CONNECT_PASSWORD"); + if (props.containsKey("SESSION_CONNECT_LIBRARY")) + library = props.getProperty("SESSION_CONNECT_LIBRARY"); + if (props.containsKey("SESSION_CONNECT_MENU")) + initialMenu = props.getProperty("SESSION_CONNECT_MENU"); + if (props.containsKey("SESSION_CONNECT_PROGRAM")) + program = props.getProperty("SESSION_CONNECT_PROGRAM"); + } + + + try { + session = s; + this.port = port; + + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED,"X - Connecting"); + } + }); + + } catch (Exception exc) { + log.warn("setStatus(ON) " + exc.getMessage()); + + } + + // sock = new Socket(s, port); + //smk - For SSL compability + SocketConnector sc = new SocketConnector(); + if (sslType != null) + sc.setSSLType(sslType); + sock = sc.createSocket(s, port); + + if (sock == null) { + log.warn("I did not get a socket"); + disconnect(); + return false; + } + + connected = true; + // used for JDK1.3 + sock.setKeepAlive(true); + sock.setTcpNoDelay(true); + sock.setSoLinger(false, 0); + InputStream in = sock.getInputStream(); + OutputStream out = sock.getOutputStream(); + + bin = new BufferedInputStream(in, 8192); + bout = new BufferedOutputStream(out); + + byte abyte0[]; + while (negotiate(abyte0 = readNegotiations())); + negotiated = true; + try { + screen52.setCursorActive(false); + } catch (Exception excc) { + log.warn("setCursorOff " + excc.getMessage()); + + } + + producer = new DataStreamProducer(this, bin, dsq, abyte0); + pthread = new Thread(producer); + // pthread.setPriority(pthread.MIN_PRIORITY); + pthread.setPriority(Thread.NORM_PRIORITY); + // pthread.setPriority(Thread.NORM_PRIORITY / 2); + pthread.start(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + } + }); + + } catch (Exception exc) { + log.warn("setStatus(OFF) " + exc.getMessage()); + } + + keepTrucking = true; + me = new Thread(this); + me.start(); + + } catch (Exception exception) { + if (exception.getMessage() == null) + exception.printStackTrace(); + log.warn("connect() " + exception.getMessage()); + + if (sock == null) + log.warn("I did not get a socket"); + + disconnect(); + return false; + } + return true; + + } + + public final boolean disconnect() { + + // Added by LUC - LDC to fix a null pointer exception. + if (!connected) { + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED,"X - Disconnected"); + return false; + } + + if (me != null && me.isAlive()) { + me.interrupt(); + keepTrucking = false; + pthread.interrupt(); + } + + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED,"X - Disconnected"); + screen52.getOIA().setKeyBoardLocked(false); + pendingUnlock = false; + + try { + if (sock != null) { + log.info("Closing socket"); + sock.close(); + } + if (bin != null) + bin.close(); + if (bout != null) + bout.close(); + connected = false; + firstScreen = false; + + // WVL - LDC : TR.000345 : properly disconnect and clear screen + // Is this the right place to set screen realestate on disconnect? + //controller.getScreen().clearAll(); + screen52.goto_XY(0); + screen52.setCursorActive(false); + screen52.clearAll(); + screen52.restoreScreen(); + + controller.fireSessionChanged(TN5250jConstants.STATE_DISCONNECTED); + + } catch (Exception exception) { + log.warn(exception.getMessage()); + connected = false; + devSeq = -1; + return false; + + } + devSeq = -1; + return true; + } + + private final ByteArrayOutputStream appendByteStream(byte abyte0[]) { + ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); + for (int i = 0; i < abyte0.length; i++) { + bytearrayoutputstream.write(abyte0[i]); + if (abyte0[i] == -1) + bytearrayoutputstream.write(-1); + } + + return bytearrayoutputstream; + } + + private final byte[] readNegotiations() throws IOException { + int i = bin.read(); + if (i < 0) { + throw new IOException("Connection closed."); + } else { + int j = bin.available(); + byte abyte0[] = new byte[j + 1]; + abyte0[0] = (byte) i; + bin.read(abyte0, 1, j); + return abyte0; + } + } + + private final void writeByte(byte abyte0[]) throws IOException { + + bout.write(abyte0); + bout.flush(); + } + + // private final void writeByte(byte byte0) throws IOException { + // + // bout.write(byte0); + // bout.flush(); + // } + + public final void sendHeartBeat() throws IOException { + + byte[] b = { (byte) 0xff, (byte) 0xf1 }; + bout.write(b); + bout.flush(); + } + + private final void readImmediate(int readType) { + + if (screen52.isStatusErrorCode()) { + screen52.restoreErrorLine(); + screen52.setStatus(Screen5250.STATUS_ERROR_CODE, + Screen5250.STATUS_VALUE_OFF, null); + } + + if (!enhanced) { + screen52.setCursorActive(false); + } + // screen52.setStatus(Screen5250.STATUS_SYSTEM, + // Screen5250.STATUS_VALUE_ON, null); + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + + screen52.getOIA().setKeyBoardLocked(true); + pendingUnlock = false; + invited = false; + + screen52.getScreenFields().readFormatTable(baosp, readType, codePage); + + try { + + writeGDS(0, 3, baosp.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + baosp.reset(); + } + baosp.reset(); + + } + + public final boolean sendAidKey(int aid) { + + if (screen52.isStatusErrorCode()) { + screen52.restoreErrorLine(); + screen52.setStatus(Screen5250.STATUS_ERROR_CODE, + Screen5250.STATUS_VALUE_OFF, null); + } + + if (!enhanced) { + screen52.setCursorActive(false); + } + // screen52.setStatus(Screen5250.STATUS_SYSTEM, + // Screen5250.STATUS_VALUE_ON, null); + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + + screen52.getOIA().setKeyBoardLocked(true); + pendingUnlock = false; + invited = false; + baosp.write(screen52.getCurrentRow()); + baosp.write(screen52.getCurrentCol()); + baosp.write(aid); + + if (dataIncluded(aid)) + + screen52.getScreenFields().readFormatTable(baosp, readType, + codePage); + + try { + + writeGDS(0, 3, baosp.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + baosp.reset(); + return false; + } + baosp.reset(); + return true; + + } + + private boolean dataIncluded(int aid) { + + switch (aid) { + + case PF1: + return !dataIncluded[0]; + case PF2: + return !dataIncluded[1]; + case PF3: + return !dataIncluded[2]; + case PF4: + return !dataIncluded[3]; + case PF5: + return !dataIncluded[4]; + case PF6: + return !dataIncluded[5]; + case PF7: + return !dataIncluded[6]; + case PF8: + return !dataIncluded[7]; + case PF9: + return !dataIncluded[8]; + case PF10: + return !dataIncluded[9]; + case PF11: + return !dataIncluded[10]; + case PF12: + return !dataIncluded[11]; + case PF13: + return !dataIncluded[12]; + case PF14: + return !dataIncluded[13]; + case PF15: + return !dataIncluded[14]; + case PF16: + return !dataIncluded[15]; + case PF17: + return !dataIncluded[16]; + case PF18: + return !dataIncluded[17]; + case PF19: + return !dataIncluded[18]; + case PF20: + return !dataIncluded[19]; + case PF21: + return !dataIncluded[20]; + case PF22: + return !dataIncluded[21]; + case PF23: + return !dataIncluded[22]; + case PF24: + return !dataIncluded[23]; + + default: + return true; + + } + + } + + /** + * Help request - + * + * + * See notes inside method + */ + public final void sendHelpRequest() { + + // Client sends header 000D12A0000004000003####F3FFEF + // operation code 3 + // row - first ## + // column - second ## + // F3 - Help Aid Key + // System.out.println("Help request sent"); + baosp.write(screen52.getCurrentRow()); + baosp.write(screen52.getCurrentCol()); + baosp.write(AID_HELP); + + try { + writeGDS(0, 3, baosp.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + baosp.reset(); + } + + /** + * Attention Key - + * + * + * See notes inside method + */ + public final void sendAttentionKey() { + + // Client sends header 000A12A000004400000FFEF + // 0x40 -> 01000000 + // + // flags + // bit 0 - ERR + // bit 1 - ATN Attention + // bits 2-4 - reserved + // bit 5 - SRQ system request + // bit 6 - TRQ Test request key + // bit 7 - HLP + + // System.out.println("Attention key sent"); + + try { + writeGDS(0x40, 0, null); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + } + + /** + * Opens a dialog and asks the user before sending a request + * + * @see {@link #systemRequest(String)} + */ + public final void systemRequest() { + final String sysreq = this.controller.showSystemRequest(); + systemRequest(sysreq); + } + + /** + * @param sr - system request option + * @see {@link #systemRequest(String)} + */ + public final void systemRequest(char sr) { + systemRequest(Character.toString(sr)); + } + + /** + * System request, taken from the rfc1205, 5250 Telnet interface section 4.3 + * + * @param sr system request option (allowed to be null, but than nothing happens) + */ + public final void systemRequest(String sr) { + byte[] bytes = null; + + if ( (sr != null) && (sr.length() > 0)) { + // XXX: Not sure, if this is a sufficient check for 'clear dataq' + if (sr.charAt(0) == '2') { + dsq.clear(); + } + for (int i = 0, l = sr.length(); i < l; i++) { + baosp.write(codePage.uni2ebcdic(sr.charAt(i))); + } + bytes = baosp.toByteArray(); + } + + try { + writeGDS(4, 0, bytes); + } catch (IOException ioe) { + log.info(ioe.getMessage()); + } + baosp.reset(); + } + + /** + * Cancel Invite - taken from the rfc1205 - 5250 Telnet interface section + * 4.3 + * + * See notes inside method + */ + public final void cancelInvite() { + + // screen52.setStatus(Screen5250.STATUS_SYSTEM, + // Screen5250.STATUS_VALUE_ON, null); + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + + // from rfc1205 section 4.3 + // Server: Sends header with the 000A12A0 00000400 000AFFEF + // Opcode = Cancel Invite. + + // Client: sends header with the 000A12A0 00000400 000AFFEF + // Opcode = Cancel Invite to + // indicate that the work station is + // no longer invited. + try { + writeGDS(0, 10, null); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + + } + + public final void hostPrint(int aid) { + + if (screen52.isStatusErrorCode()) { + screen52.restoreErrorLine(); + screen52.setStatus(Screen5250.STATUS_ERROR_CODE, + Screen5250.STATUS_VALUE_OFF, null); + } + + screen52.setCursorActive(false); + // screen52.setStatus(Screen5250.STATUS_SYSTEM, + // Screen5250.STATUS_VALUE_ON, null); + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + + // From client access ip capture + // it seems to use an operation code of 3 and 4 + // also note that the flag field that says reserved is being sent as + // well + // with a value of 0x80 + // + // I have tried with not setting these flags and sending with 3 or 1 + // there is no effect and I still get a host print screen. Go figure + //0000: 000D 12A0 0000 0400 8003 1407 F6FFEF + //0000: 000D 12A0 0000 0400 8001 110E F6FFEF + // + // Client sends header 000D12A0000004000003####F6FFEF + // operation code 3 + // row - first ## + // column - second ## + // F6 - Print Aid Key + + baosp.write(screen52.getCurrentRow()); + baosp.write(screen52.getCurrentCol()); + baosp.write(AID_PRINT); // aid key + + try { + writeGDS(0, 3, baosp.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + baosp.reset(); + } + + public final void toggleDebug() { + producer.toggleDebug(codePage); + } + + // write gerneral data stream + private final void writeGDS(int flags, int opcode, byte abyte0[]) + throws IOException { + + // Added to fix for JDK 1.4 this was null coming from another method. + // There was a weird keyRelease event coming from another panel when + // using a key instead of the mouse to select button. + // The other method was fixed as well but this check should be here + // anyway. + if (bout == null) + return; + + int length; + if (abyte0 != null) + length = abyte0.length + 10; + else + length = 10; + + // refer to rfc1205 - 5250 Telnet interface + // Section 3. Data Stream Format + + // Logical Record Length - 16 bits + baosrsp.write(length >> 8); // Length LL + baosrsp.write(length & 0xff); // LL + + // Record Type - 16 bits + // It should always be set to '12A0'X to indicate the + // General Data Stream (GDS) record type. + baosrsp.write(18); // 0x12 + baosrsp.write(160); // 0xA0 + + // the next 16 bits are not used + baosrsp.write(0); // 0x00 + baosrsp.write(0); // 0x00 + + // The second part is meant to be variable in length + // currently this portion is 4 octets long (1 byte or 8 bits for us ;-O) + baosrsp.write(4); // 0x04 + + baosrsp.write(flags); // flags + // bit 0 - ERR + // bit 1 - ATN Attention + // bits 2-4 - reserved + // bit 5 - SRQ system request + // bit 6 - TRQ Test request key + // bit 7 - HLP + baosrsp.write(0); // reserved - set to 0x00 + baosrsp.write(opcode); // opcode + + if (abyte0 != null) + baosrsp.write(abyte0, 0, abyte0.length); + + baosrsp = appendByteStream(baosrsp.toByteArray()); + + // make sure we indicate no more to be sent + baosrsp.write(IAC); + baosrsp.write(EOR); + + baosrsp.writeTo(bout); + + // byte[] b = new byte[baosrsp.size()]; + // b = baosrsp.toByteArray(); + // dump(b); + bout.flush(); + // baos = null; + baosrsp.reset(); + } + + protected final int getOpCode() { + + return bk.getOpCode(); + } + + // private final void sendNotify() throws IOException { + // + // writeGDS(0, 0, null); + // } + + protected boolean[] getActiveAidKeys() { + boolean aids[] = new boolean[dataIncluded.length]; + System.arraycopy(dataIncluded,0,aids,0,dataIncluded.length); + return aids; + } + + private final void setInvited() { + + log.debug("invited"); + if (!screen52.isStatusErrorCode()) + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + + invited = true; + } + + // WVL - LDC : 05/08/2005 : TFX.006253 - Support STRPCCMD + private void strpccmd() + { + try + { + int str = 11; + char c; + ScreenPlanes planes = screen52.getPlanes(); + c = planes.getChar(str); + boolean waitFor = !(c == 'a'); + + StringBuffer command = new StringBuffer(); + for (int i = str+1; i < 132; i++) + { + c = planes.getChar(i); + if (Character.isISOControl(c)) + c = ' '; + command.append(c); + } + + String cmd = command.toString().trim(); + + run(cmd, waitFor); + } + finally + { + strpccmd = false; + screen52.sendKeys(TN5250jConstants.MNEMONIC_ENTER); + } + } + + // WVL - LDC : 05/08/2005 : TFX.006253 - Support STRPCCMD + private void run(String cmd, boolean waitFor) + { + try + { + log.debug("RUN cmd = " + cmd); + log.debug("RUN wait = " + waitFor); + + Runtime r = Runtime.getRuntime(); + Process p = r.exec(cmd); + if (waitFor) + { + int result = p.waitFor(); + log.debug("RUN result = " + result); + } + } + catch (Throwable t) + { + log.error(t); + } + } + + + // WVL - LDC : TR.000300 : Callback scenario from 5250 + /** + * Activate or deactivate the command scanning behaviour. + * + * @param scan + * if true, scanning is enabled; disabled otherwise. + * + * @see scan4Cmd() + */ + public void setScanningEnabled(boolean scan) { + this.scan = scan; + } + + // WVL - LDC : TR.000300 : Callback scenario from 5250 + /** + * Checks whether command scanning is enabled. + * + * @return true is command scanning is enabled; false otherwise. + */ + public boolean isScanningEnabled() { + return this.scan; + } + + // WVL - LDC : TR.000300 : Callback scenario from 5250 + /** + * When command scanning is activated, the terminal reads the first and + * second character in the datastream (the zero position allows to + * devisualize the scan stream). If the sequence #! is + * encountered and if this sequence is not followed by a + * blank character, the {@link parseCommand(ScreenChar[])}is called. + */ + private void scan() { + // System.out.println("Checking command : " + + // screen52.screen[1].getChar() + screen52.screen[2].getChar()); + + // ScreenChar[] screen = screen52.screen; + ScreenPlanes planes = screen52.getPlanes(); + + if ((planes.getChar(STRSCAN) == '#') + && (planes.getChar(STRSCAN + 1) == '!') + && (planes.getChar(STRSCAN + 2) != ' ')) { + try { + parseCommand(); + } catch (Throwable t) { + log.info("Exec cmd: " + t.getMessage()); + t.printStackTrace(); + } + } + } + + // WVL - LDC : TR.000300 : Callback scenario from 5250 + /** + * The screen is parsed starting from second position until a white space is + * encountered. When found the Session#execCommand(String, int) is + * called with the parsed string. The position immediately following the + * encountered white space, separating the command from the rest of the + * screen, is passed as starting index. + * + * Note that the character at the starting position can potentially be a + * white space itself. The starting position in execCommand + * provided to make the scanning sequence more flexible. We'd like for + * example to embed also a + or - sign to + * indicate whether the tnvt should trigger a repaint or not. This would + * allow the flashing of command sequences without them becoming visible. + * + *
    + *
  • PRE The screen character at position + * STRSCAN + 2 is not a white space.
  • + *
+ */ + private void parseCommand() { + // Search for the command i.e. the first token in the stream + // after the #! sequence separated by a space from the rest + // of the screen. + char[] screen = screen52.getScreenAsAllChars(); + for (int s = STRSCAN + 2, i = s; i < screen.length; i++) { + if (screen[i] == ' ') { + String command = new String(screen, s, i - s); + + // Skip all white spaces between the command and the rest of + // the screen. + //for (; (i < screen.length) && (screen[i] == ' '); i++); + + String remainder = new String(screen, i + 1, screen.length + - (i + 1)); + // System.out.println("Sensing action command in the input! = " + // + command); + controller.fireScanned(command, remainder); + break; + } + } + } + + public void run() { + + if (enhanced) + sfParser = new WTDSFParser(this); + + bk = new Stream5250(); + + while (keepTrucking) { + + try { + bk.initialize((byte[]) dsq.take()); + } catch (InterruptedException ie) { + log.warn(" vt thread interrupted and stopping "); + keepTrucking = false; + continue; + } + + // lets play nicely with the others on the playground + // me.yield(); + + Thread.yield(); + + invited = false; + + screen52.setCursorActive(false); + + // System.out.println("operation code: " + bk.getOpCode()); + if (bk == null) + continue; + + switch (bk.getOpCode()) { + case 00: + log.debug("No operation"); + break; + case 1: + log.debug("Invite Operation"); + parseIncoming(); + // screen52.setKeyboardLocked(false); + pendingUnlock = true; + cursorOn = true; + setInvited(); + break; + case 2: + log.debug("Output Only"); + parseIncoming(); + // System.out.println(screen52.dirty); + screen52.updateDirty(); + + // invited = true; + + break; + case 3: + log.debug("Put/Get Operation"); + parseIncoming(); + // inviteIt =true; + setInvited(); + if (!firstScreen) { + firstScreen = true; + controller.fireSessionChanged(TN5250jConstants.STATE_CONNECTED); + } + break; + case 4: + log.debug("Save Screen Operation"); + parseIncoming(); + break; + + case 5: + log.debug("Restore Screen Operation"); + parseIncoming(); + break; + case 6: + log.debug("Read Immediate"); + sendAidKey(0); + break; + case 7: + log.debug("Reserved"); + break; + case 8: + log.debug("Read Screen Operation"); + try { + readScreen(); + } catch (IOException ex) { + log.warn(ex.getMessage()); + } + break; + + case 9: + log.debug("Reserved"); + break; + + case 10: + log.debug("Cancel Invite Operation"); + cancelInvite(); + break; + + case 11: + log.debug("Turn on message light"); + screen52.getOIA().setMessageLightOn(); + screen52.setCursorActive(true); + + break; + case 12: + log.debug("Turn off Message light"); + screen52.getOIA().setMessageLightOff(); + screen52.setCursorActive(true); + + break; + default: + break; + } + + if (screen52.isUsingGuiInterface()) + screen52.drawFields(); + + // if (screen52.screen[0][1].getChar() == '#' && + // screen52.screen[0][2].getChar() == '!') + // execCmd(); + // else { + + // if (screen52.isHotSpots()) { + // screen52.checkHotSpots(); + // } + + try { + if (!strpccmd) { + // SwingUtilities.invokeAndWait( + // new Runnable () { + // public void run() { + // screen52.updateDirty(); + // } + // } + // ); + screen52.updateDirty(); + // controller.validate(); + // log.debug("update dirty"); + } else { + strpccmd(); + } + } catch (Exception exd) { + log.warn(" tnvt.run: " + exd.getMessage()); + exd.printStackTrace(); + } + + if (pendingUnlock && !screen52.isStatusErrorCode()) { + screen52.getOIA().setKeyBoardLocked(false); + pendingUnlock = false; + } + + if (cursorOn && !screen52.getOIA().isKeyBoardLocked()) { + screen52.setCursorActive(true); + cursorOn = false; + } + + // lets play nicely with the others on the playground + //me.yield(); + Thread.yield(); + + } + } + + public void dumpStuff() { + + if (log.isDebugEnabled()) { + log.debug(" Pending unlock " + pendingUnlock); + log.debug(" Status Error " + screen52.isStatusErrorCode()); + log.debug(" Keyboard Locked " + screen52.getOIA().isKeyBoardLocked()); + log.debug(" Cursor On " + cursorOn); + log.debug(" Cursor Active " + screen52.cursorActive); + } + + } + + // private final void execCmd() { + // String name = ""; + // String argString = ""; + // + // StringBuffer sb = new StringBuffer(); + // sb.append(screen52.screen[0][3].getChar()); + // sb.append(screen52.screen[0][4].getChar()); + // sb.append(screen52.screen[0][5].getChar()); + // sb.append(screen52.screen[0][6].getChar()); + // + // System.out.println("command = " + sb); + // int x = 8; + // sb.setLength(0); + // while (screen52.screen[0][x].getChar() > ' ') { + // sb.append(screen52.screen[0][x].getChar()); + // x++; + // } + // name = sb.toString(); + // System.out.println("name = " + name); + // + // sb.setLength(0); + // x++; + // while (screen52.screen[0][x].getChar() >= ' ') { + // sb.append(screen52.screen[0][x].getChar()); + // x++; + // } + // argString = sb.toString(); + // System.out.println("args = " + argString); + // + // sendAidKey(AID_ENTER); + // + // try { + // + // Class c = Class.forName(name); + // String args1[] = {argString}; + // String args2[] = {}; + // + // Method m = c.getMethod("main", + // new Class[] { args1.getClass() }); + // m.setAccessible(true); + // int mods = m.getModifiers(); + // if (m.getReturnType() != + // void.class || !Modifier.isStatic(mods) || + // !Modifier.isPublic(mods)) { + // + // throw new NoSuchMethodException("main"); + // } + // try { + // if (argString.length() > 0) + // m.invoke(null, new Object[] { args1 }); + // else + // m.invoke(null, new Object[] { args2 }); + // } + // catch (IllegalAccessException e) { + // // This should not happen, as we have + // // disabled access checks + // System.out.println("iae " + e.getMessage()); + // + // } + // } + // catch (ClassNotFoundException cnfe) { + // System.out.println("cnfe " + cnfe.getMessage()); + // } + // catch (NoSuchMethodException nsmf) { + // System.out.println("nsmf " + nsmf.getMessage()); + // } + // catch (InvocationTargetException ite) { + // System.out.println("ite " + ite.getMessage()); + // } + // // catch (IllegalAccessException iae) { + // // System.out.println("iae " + iae.getMessage()); + // // } + // // catch (InstantiationException ie) { + // // System.out.println("ie " + ie.getMessage()); + // // } + // // try { + // // + // // Runtime rt = Runtime.getRuntime(); + // // Process proc = rt.exec("notepad"); + // // int exitVal = proc.exitValue(); + // // } + // // catch (Throwable t) { + // // + // // t.printStackTrace(); + // // } + // } + + private final void readScreen() throws IOException { + + int rows = screen52.getRows(); + int cols = screen52.getColumns(); + byte abyte0[] = new byte[rows * cols]; + fillScreenArray(abyte0, rows, cols); + writeGDS(0, 0, abyte0); + abyte0 = null; + } + + private final void fillScreenArray(byte[] sa, int rows, int cols) { + + int la = 32; + int sac = 0; + int len = rows * cols; + + ScreenPlanes planes = screen52.planes; + + for (int y = 0; y < len; y++) { // save the screen data + + if (planes.isAttributePlace(y)) { + la = planes.getCharAttr(y); + sa[sac++] = (byte) la; + } else { + if (planes.getCharAttr(y) != la) { + la = planes.getCharAttr(y); + sac--; + sa[sac++] = (byte) la; + } + //LDC: Check to see if it is an displayable character. If not, + // do not convert the character. + // The characters on screen are in unicode + //sa[sac++] = + // (byte)codePage.uni2ebcdic(screen52.screen[y].getChar()); + char ch = planes.getChar(y); + byte byteCh = (byte) ch; + if (isDataUnicode(ch)) + byteCh = codePage.uni2ebcdic(ch); + sa[sac++] = byteCh; + } + } + } + + private final void fillRegenerationBuffer(ByteArrayOutputStream sc, int rows, int cols) + throws IOException { + + int la = 32; + int sac = 0; + int len = rows * cols; + + ScreenPlanes planes = screen52.planes; + byte[] sa = new byte[len]; + + try { + boolean guiExists = sfParser != null && sfParser.isGuisExists(); + + + for (int y = 0; y < len; y++) { // save the screen data + + if (guiExists) { + + byte[] guiSeg = sfParser.getSegmentAtPos(y); + if (guiSeg != null) { + //log.info(" gui saved at " + y + " - " + screen52.getRow(y) + "," + + // screen52.getCol(y)); + + byte[] gsa = new byte[sa.length + guiSeg.length + 2]; + System.arraycopy(sa,0,gsa,0,sa.length); + System.arraycopy(guiSeg,0,gsa,sac+2,guiSeg.length); + sa = new byte[gsa.length]; + System.arraycopy(gsa,0,sa,0,gsa.length); + sa[sac++] = (byte)0x04; + sa[sac++] = (byte)0x11; + sac += guiSeg.length; + //y--; + // continue; + } + } + if (planes.isAttributePlace(y)) { + la = planes.getCharAttr(y); + sa[sac++] = (byte) la; + } else { + if (planes.getCharAttr(y) != la) { + la = planes.getCharAttr(y); + sac--; + sa[sac++] = (byte) la; + } + //LDC: Check to see if it is an displayable character. If not, + // do not convert the character. + // The characters on screen are in unicode + //sa[sac++] = + // (byte)codePage.uni2ebcdic(screen52.screen[y].getChar()); + char ch = planes.getChar(y); + byte byteCh = (byte) ch; + if (isDataUnicode(ch)) + byteCh = codePage.uni2ebcdic(ch); + sa[sac++] = byteCh; + } + } + } + catch(Exception exc) { + + log.info(exc.getMessage()); + exc.printStackTrace(); + } + sc.write(sa); + } + + public final void saveScreen() throws IOException { + + ByteArrayOutputStream sc = new ByteArrayOutputStream(); + sc.write(4); + sc.write(0x12); // 18 + sc.write(0); // 18 + sc.write(0); // 18 + + sc.write((byte) screen52.getRows()); // store the current size + sc.write((byte) screen52.getColumns()); // "" + + int cp = screen52.getCurrentPos(); // save off current position + // fix below submitted by Mitch Blevins + //int cp = screen52.getScreenFields().getCurrentFieldPos(); + // save off current position + sc.write((byte) (cp >> 8 & 0xff)); // "" + sc.write((byte) (cp & 0xff)); // "" + + sc.write((byte) (screen52.homePos >> 8 & 0xff)); // save home pos + sc.write((byte) (screen52.homePos & 0xff)); // "" + + int rows = screen52.getRows(); // store the current size + int cols = screen52.getColumns(); // "" + + // byte[] sa = new byte[rows * cols]; + fillRegenerationBuffer(sc,rows,cols); + // fillScreenArray(sa, rows, cols); + // + // sc.write(sa); + // sa = null; + int sizeFields = screen52.getScreenFields().getSize(); + sc.write((byte) (sizeFields >> 8 & 0xff)); // "" + sc.write((byte) (sizeFields & 0xff)); // "" + + if (sizeFields > 0) { + int x = 0; + int s = screen52.getScreenFields().getSize(); + ScreenField sf = null; + while (x < s) { + sf = screen52.getScreenFields().getField(x); + sc.write((byte) sf.getAttr()); // attribute + int sp = sf.startPos(); + sc.write((byte) (sp >> 8 & 0xff)); // "" + sc.write((byte) (sp & 0xff)); // "" + if (sf.mdt) + sc.write((byte) 1); + else + sc.write((byte) 0); + sc.write((byte) (sf.getLength() >> 8 & 0xff)); // "" + sc.write((byte) (sf.getLength() & 0xff)); // "" + sc.write((byte) sf.getFFW1() & 0xff); + sc.write((byte) sf.getFFW2() & 0xff); + sc.write((byte) sf.getFCW1() & 0xff); + sc.write((byte) sf.getFCW2() & 0xff); + log.debug("Saved "); + log.debug(sf.toString()); + + x++; + } + sf = null; + } + + // The following two lines of code looks to have caused all sorts of + // problems so for now we have commented them out. + // screen52.getScreenFields().setCurrentField(null); // set it to null + // for GC ? + // screen52.clearTable(); + + try { + writeGDS(0, 3, sc.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + + sc = null; + log.debug("Save Screen end "); + } + + /** + * + * @throws IOException + */ + public final void restoreScreen() throws IOException { + int which = 0; + + ScreenPlanes planes = screen52.planes; + + try { + log.debug("Restore "); + + bk.getNextByte(); + bk.getNextByte(); + + int rows = bk.getNextByte() & 0xff; + int cols = bk.getNextByte() & 0xff; + int pos = bk.getNextByte() << 8 & 0xff00; // current position + pos |= bk.getNextByte() & 0xff; + int hPos = bk.getNextByte() << 8 & 0xff00; // home position + hPos |= bk.getNextByte() & 0xff; + if (rows != screen52.getRows()) + screen52.setRowsCols(rows, cols); + screen52.clearAll(); // initialize what we currenty have + if (sfParser != null && sfParser.isGuisExists()) + sfParser.clearGuiStructs(); + + int b = 32; + int la = 32; + int len = rows * cols; + for (int y = 0; y < len; y++) { + + b = bk.getNextByte(); + if (b == 0x04) { + + log.info(" gui restored at " + y + " - " + screen52.getRow(y) + "," + + screen52.getCol(y)); + int command = bk.getNextByte(); + byte[] seg = bk.getSegment(); + + if (seg.length > 0) { + screen52.goto_XY(y); + sfParser.parseWriteToDisplayStructuredField(seg); + } + y--; + // screen52.goto_XY(y); + } + else { + // b = bk.getNextByte(); + if (planes.isUseGui(y)) + continue; + if (isAttribute(b)) { + planes.setScreenCharAndAttr(y, planes.getChar(y), b, true); + la = b; + + } + else { + //LDC - 12/02/2003 - Check to see if it is an displayable + // character. If not, + // do not convert the character. + // The characters on screen are in unicode + char ch = (char) b; + if (isDataEBCDIC(b)) + ch = codePage.ebcdic2uni(b); + + planes.setScreenCharAndAttr(y, ch, la, false); + } + } + } + + int numFields = bk.getNextByte() << 8 & 0xff00; + numFields |= bk.getNextByte() & 0xff; + log.debug("number of fields " + numFields); + + if (numFields > 0) { + int x = 0; + int attr = 0; + int fPos = 0; + int fLen = 0; + int ffw1 = 0; + int ffw2 = 0; + int fcw1 = 0; + int fcw2 = 0; + boolean mdt = false; + + ScreenField sf = null; + while (x < numFields) { + + attr = bk.getNextByte(); + fPos = bk.getNextByte() << 8 & 0xff00; + fPos |= bk.getNextByte() & 0xff; + if (bk.getNextByte() == 1) + mdt = true; + else + mdt = false; + fLen = bk.getNextByte() << 8 & 0xff00; + fLen |= bk.getNextByte() & 0xff; + ffw1 = bk.getNextByte(); + ffw2 = bk.getNextByte(); + fcw1 = bk.getNextByte(); + fcw2 = bk.getNextByte(); + + sf = screen52.getScreenFields().setField(attr, + screen52.getRow(fPos), screen52.getCol(fPos), fLen, + ffw1, ffw2, fcw1, fcw2); + + while (fLen-- > 0) { + + // now we set the field plane attributes + planes.setScreenFieldAttr(fPos++,ffw1); + + } + + if (mdt) { + sf.setMDT(); + screen52.getScreenFields().setMasterMDT(); + } + if (log.isDebugEnabled()) { + log.debug("/nRestored "); + log.debug(sf.toString()); + } + x++; + } + } + + // Redraw the gui fields if we are in gui mode + if (screen52.isUsingGuiInterface()) + screen52.drawFields(); + + screen52.restoreScreen(); // display the screen + + // The position was saved with currentPos which 1,1 offset of the + // screen position. + // The setPendingInsert is the where the cursor position will be + // displayed after the restore. + screen52.setPendingInsert(true, screen52.getRow(pos + cols), screen52 + .getCol(pos + cols)); + // We need to offset the pos by -1 since the position is 1,1 based + // and the goto_XY is 0,0 based. + screen52.goto_XY(pos - 1); + screen52.isInField(); + // // Redraw the gui fields if we are in gui mode + // if (screen52.isUsingGuiInterface()) + // screen52.drawFields(); + } catch (Exception e) { + log.warn("error restoring screen " + which + " with " + + e.getMessage()); + } + } + + public final boolean waitingForInput() { + + return waitingForInput; + } + + private void parseIncoming() { + + boolean done = false; + boolean error = false; + + try { + while (bk.hasNext() && !done) { + byte b = bk.getNextByte(); + + switch (b) { + case 0: + case 1: + break; + case CMD_SAVE_SCREEN: // 0x02 2 Save Screen + case 3: // 0x03 3 Save Partial Screen + log.debug("save screen partial"); + saveScreen(); + break; + + case ESC: // ESCAPE + break; + case 7: // audible bell + controller.signalBell(); + bk.getNextByte(); + bk.getNextByte(); + break; + case CMD_WRITE_TO_DISPLAY: // 0x11 17 write to display + error = writeToDisplay(true); + // WVL - LDC : TR.000300 : Callback scenario from 5250 + // Only scan when WRITE_TO_DISPLAY operation (i.e. refill + // screen buffer) + // has been issued! + if (scan) + scan(); + + break; + case CMD_RESTORE_SCREEN: // 0x12 18 Restore Screen + case 13: // 0x13 19 Restore Partial Screen + log.debug("restore screen partial"); + restoreScreen(); + break; + + case CMD_CLEAR_UNIT_ALTERNATE: // 0x20 32 clear unit alternate + int param = bk.getNextByte(); + if (param != 0) { + log.debug(" clear unit alternate error " + + Integer.toHexString(param)); + sendNegResponse(NR_REQUEST_ERROR, 03, 01, 05, + " clear unit alternate not supported"); + done = true; + } else { + if (screen52.getRows() != 27) + screen52.setRowsCols(27, 132); + + screen52.clearAll(); + if (sfParser != null && sfParser.isGuisExists()) + sfParser.clearGuiStructs(); + + + } + break; + + case CMD_WRITE_ERROR_CODE: // 0x21 33 Write Error Code + writeErrorCode(); + error = writeToDisplay(false); + break; + case CMD_WRITE_ERROR_CODE_TO_WINDOW: // 0x22 34 + // Write Error Code to window + writeErrorCodeToWindow(); + error = writeToDisplay(false); + break; + + case CMD_READ_SCREEN_IMMEDIATE: // 0x62 98 + case CMD_READ_SCREEN_TO_PRINT: // 0x66 102 read screen to print + readScreen(); + break; + + case CMD_CLEAR_UNIT: // 64 0x40 clear unit + if (screen52.getRows() != 24) + screen52.setRowsCols(24, 80); + screen52.clearAll(); + if (sfParser != null && sfParser.isGuisExists()) + sfParser.clearGuiStructs(); + + break; + + case CMD_CLEAR_FORMAT_TABLE: // 80 0x50 Clear format table + screen52.clearTable(); + break; + + case CMD_READ_INPUT_FIELDS: //0x42 66 read input fields + case CMD_READ_MDT_FIELDS: // 0x52 82 read MDT Fields + bk.getNextByte(); + bk.getNextByte(); + readType = b; + screen52.goHome(); + // do nothing with the cursor here it is taken care of + // in the main loop. + //////////////// screen52.setCursorOn(); + waitingForInput = true; + pendingUnlock = true; + // screen52.setKeyboardLocked(false); + break; + case CMD_READ_MDT_IMMEDIATE_ALT: // 0x53 83 + readType = b; + // screen52.goHome(); + // waitingForInput = true; + // screen52.setKeyboardLocked(false); + readImmediate(readType); + break; + case CMD_WRITE_STRUCTURED_FIELD: // 243 0xF3 -13 Write + // structured field + writeStructuredField(); + break; + case CMD_ROLL: // 0x23 35 Roll Not sure what it does right now + int updown = bk.getNextByte(); + int topline = bk.getNextByte(); + int bottomline = bk.getNextByte(); + screen52.rollScreen(updown, topline, bottomline); + break; + + default: + done = true; + sendNegResponse(NR_REQUEST_ERROR, 03, 01, 01, + "parseIncoming"); + break; + } + + if (error) + done = true; + } + // BEGIN FRAMEWORK + // I took this out for debugging a problem + // ScreenField[] a = this.screen52.getScreenFields().getFields(); + // if (log.isDebugEnabled()) { + // for (int x = 0; x < a.length; x++) { + // log.debug(a[x].toString()); + // } + // } + // + // String strokes = this.screen52.getKeys(); + // if (!strokes.equals("")) { + // Tn5250jKeyEvents e = new Tn5250jKeyEvents(this.screen52, + // strokes); + // //from the previous screen. + // Tn5250jController.getCurrent().handleEvent(e); + // } + // + // Tn5250jEvent event = new Tn5250jEvent(screen52); + // Tn5250jController.getCurrent().handleEvent(event); + // + // //END FRAMEWORK + } catch (Exception exc) { + log.warn("incoming " + exc.getMessage()); + } + ; + } + + /** + * This routine handles sending negative responses back to the host. + * + * You can find a description of the types of responses to be sent back by + * looking at section 12.4 of the 5250 Functions Reference manual + * + * + * @param cat + * @param modifier + * @param uByte1 + * @param uByte2 + * @param from + * + */ + protected void sendNegResponse(int cat, int modifier, int uByte1, + int uByte2, String from) { + + try { + + int os = bk.getByteOffset(-1) & 0xf0; + int cp = (bk.getCurrentPos() - 1); + log.info("invalid " + from + " command " + os + + " at pos " + cp); + } catch (Exception e) { + + log.warn("Send Negative Response error " + e.getMessage()); + } + + baosp.write(cat); + baosp.write(modifier); + baosp.write(uByte1); + baosp.write(uByte2); + + try { + writeGDS(128, 0, baosp.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + baosp.reset(); + + } + + public void sendNegResponse2(int ec) { + + screen52.setPrehelpState(true, true, false); + baosp.write(0x00); + baosp.write(ec); + + try { + writeGDS(1, 0, baosp.toByteArray()); + } catch (IOException ioe) { + + log.warn(ioe.getMessage()); + } + + baosp.reset(); + } + + private boolean writeToDisplay(boolean controlsExist) { + + boolean error = false; + boolean done = false; + int attr; + byte control0 = 0; + byte control1 = 0; + int saRows = screen52.getRows(); + int saCols = screen52.getColumns(); + + try { + if (controlsExist) { + control0 = bk.getNextByte(); + control1 = bk.getNextByte(); + processCC0(control0); + } + while (bk.hasNext() && !done) { + // pos = bk.getCurrentPos(); + + // int rowc = screen52.getCurrentRow(); + // int colc = screen52.getCurrentCol(); + + byte bytebk = bk.getNextByte(); + + switch (bytebk) { + + case 1: // SOH - Start of Header Order + log.debug("SOH - Start of Header Order"); + error = processSOH(); + + break; + case 02: // RA - Repeat to address + log.debug("RA - Repeat to address"); + int row = screen52.getCurrentRow(); + int col = screen52.getCurrentCol(); + + int toRow = bk.getNextByte(); + int toCol = bk.getNextByte() & 0xff; + if (toRow >= row) { + int repeat = bk.getNextByte(); + + // a little intelligence here I hope + if (row == 1 && col == 2 && toRow == screen52.getRows() + && toCol == screen52.getColumns()) + + screen52.clearScreen(); + else { + if (repeat != 0) { + //LDC - 13/02/2003 - convert it to unicode + repeat = codePage.ebcdic2uni(repeat); + //repeat = getASCIIChar(repeat); + } + + int times = ((toRow * screen52.getColumns()) + toCol) + - ((row * screen52.getColumns()) + col); + while (times-- >= 0) { + screen52.setChar(repeat); + } + + } + } else { + sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x23, + " RA invalid"); + error = true; + } + break; + + case 03: // EA - Erase to address + log.debug("EA - Erase to address"); + int EArow = screen52.getCurrentRow(); + int EAcol = screen52.getCurrentCol(); + + int toEARow = bk.getNextByte(); + int toEACol = bk.getNextByte() & 0xff; + int EALength = bk.getNextByte() & 0xff; + while (--EALength > 0) { + + bk.getNextByte(); + + } + char EAAttr = (char) 0; + + // a little intelligence here I hope + if (EArow == 1 && EAcol == 2 + && toEARow == screen52.getRows() + && toEACol == screen52.getColumns()) + + screen52.clearScreen(); + else { + int times = ((toEARow * screen52.getColumns()) + toEACol) + - ((EArow * screen52.getColumns()) + EAcol); + while (times-- >= 0) { + screen52.setChar(EAAttr); + } + } + break; + case 04: // Command - Escape + log.debug("Command - Escape"); + done = true; + break; + + case 16: // TD - Transparent Data + log.debug("TD - Transparent Data"); + int j = (bk.getNextByte() & 0xff) << 8 | bk.getNextByte() + & 0xff; // length + break; + + case 17: // SBA - set buffer address order (row column) + log.debug("SBA - set buffer address order (row column)"); + int saRow = bk.getNextByte(); + int saCol = bk.getNextByte() & 0xff; + // make sure it is in bounds + if (saRow >= 0 && saRow <= screen52.getRows() && saCol >= 0 + && saCol <= screen52.getColumns()) { + screen52.setCursor(saRow, saCol); // now set screen + // position for output + + } else { + + sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x22, + "invalid row/col order" + " saRow = " + saRow + + " saRows = " + screen52.getRows() + + " saCol = " + saCol); + + error = true; + + } + break; + + case 18: // WEA - Extended Attribute + log.debug("WEA - Extended Attribute"); + bk.getNextByte(); + bk.getNextByte(); + break; + + case 19: // IC - Insert Cursor + log.debug("IC - Insert Cursor"); + int icX = bk.getNextByte(); + int icY = bk.getNextByte() & 0xff; + if (icX >= 0 && icX <= saRows && icY >= 0 && icY <= saCols) { + + log.debug(" IC " + icX + " " + icY); + screen52.setPendingInsert(true, icX, icY); + } else { + sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x22, + " IC/IM position invalid "); + error = true; + } + + break; + + case 20: // MC - Move Cursor + log.debug("MC - Move Cursor"); + int imcX = bk.getNextByte(); + int imcY = bk.getNextByte() & 0xff; + if (imcX >= 0 && imcX <= saRows && imcY >= 0 + && imcY <= saCols) { + + log.debug(" MC " + imcX + " " + imcY); + screen52.setPendingInsert(false, imcX, imcY); + } else { + sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x22, + " IC/IM position invalid "); + error = true; + } + + break; + + case 21: // WTDSF - Write To Display Structured Field order + log + .debug("WTDSF - Write To Display Structured Field order"); + byte[] seg = bk.getSegment(); + error = sfParser.parseWriteToDisplayStructuredField(seg); + + // error = writeToDisplayStructuredField(); + break; + + case 29: // SF - Start of Field + log.debug("SF - Start of Field"); + int fcw1 = 0; + int fcw2 = 0; + int ffw1 = 0; + int ffw0 = bk.getNextByte() & 0xff; // FFW + + if ((ffw0 & 0x40) == 0x40) { + ffw1 = bk.getNextByte() & 0xff; // FFW 1 + + fcw1 = bk.getNextByte() & 0xff; // check for field + // control word + + // check if the first fcw1 is an 0x81 if it is then get + // the + // next pair for checking + if (fcw1 == 0x81) { + bk.getNextByte(); + fcw1 = bk.getNextByte() & 0xff; // check for field + // control word + } + + if (!isAttribute(fcw1)) { + + fcw2 = bk.getNextByte() & 0xff; // FCW 2 + attr = bk.getNextByte() & 0xff; // attribute field + + while (!isAttribute(attr)) { + log.info(Integer.toHexString(fcw1) + " " + + Integer.toHexString(fcw2) + + " "); + log.info(Integer.toHexString(attr) + + " " + + Integer.toHexString(bk + .getNextByte() & 0xff)); + // bk.getNextByte(); + attr = bk.getNextByte() & 0xff; // attribute + // field + } + } else { + attr = fcw1; // attribute of field + fcw1 = 0; + } + } else { + attr = ffw0; + } + + int fLength = (bk.getNextByte() & 0xff) << 8 + | bk.getNextByte() & 0xff; + screen52.addField(attr, fLength, ffw0, ffw1, fcw1, fcw2); + + break; + // WVL - LDC : 05/08/2005 : TFX.006253 - Support STRPCCMD + case -128: //STRPCCMD + // if (screen52.getCurrentPos() == 82) { + log.debug("STRPCCMD got a -128 command at " + screen52.getCurrentPos()); + StringBuffer value = new StringBuffer(); + int b; + char c; + int[] pco = new int[9]; + int[] pcoOk = {0xfc, 0xd7, 0xc3, 0xd6, 0x40, 0x83, 0x80, 0xa1, 0x80}; + + for (int i = 0; i < 9; i++) + { + b = bk.getNextByte(); + pco[i] = ((b & 0xff)); + c = codePage.ebcdic2uni(b); + value.append(c); + } + + // Check "PCO-String" + if (Arrays.equals(pco, pcoOk)) { + strpccmd = true; + } + // we return in the stream to have all chars + // arrive at the screen for later processing + for (int i = 0; i < 9; i++) + bk.setPrevByte(); + //} + // no break: so every chars arrives + // on the screen for later parsing + //break; + + default: // all others must be output to screen + log.debug("all others must be output to screen"); + byte byte0 = bk.getByteOffset(-1); + if (isAttribute(byte0)) { + screen52.setAttr(byte0); + } else { + if (!screen52.isStatusErrorCode()) { + if (!isDataEBCDIC(byte0)) { + // if (byte0 == 255) { + // sendNegResponse(NR_REQUEST_ERROR,0x05,0x01,0x42, + // " Attempt to send FF to screen"); + // } + // else + + screen52.setChar(byte0); + } else + //LDC - 13/02/2003 - Convert it to unicode + //screen52.setChar(getASCIIChar(byte0)); + screen52.setChar(codePage.ebcdic2uni(byte0)); + } else { + if (byte0 == 0) + screen52.setChar(byte0); + else + //LDC - 13/02/2003 - Convert it to unicode + //screen52.setChar(getASCIIChar(byte0)); + screen52.setChar(codePage.ebcdic2uni(byte0)); + } + } + + break; + } + + if (error) + done = true; + } + } + + catch (Exception e) { + log.warn("write to display " + e.getMessage()); + e.printStackTrace(); + } + ; + + processCC1(control1); + + return error; + + } + + private boolean processSOH() throws Exception { + + int l = bk.getNextByte(); // length + log.debug(" byte 0 " + l); + + if (l > 0 && l <= 7) { + bk.getNextByte(); // flag byte 2 + bk.getNextByte(); // reserved + bk.getNextByte(); // resequence fields + + screen52.clearTable(); + + // well that is the first time I have seen this. This fixes a + // problem + // with S/36 command line. Finally got it. + if (l <= 3) + return false; + + screen52.setErrorLine(bk.getNextByte()); // error row + + int byte1 = 0; + if (l >= 5) { + byte1 = bk.getNextByte(); + dataIncluded[23] = (byte1 & 0x80) == 0x80; + dataIncluded[22] = (byte1 & 0x40) == 0x40; + dataIncluded[21] = (byte1 & 0x20) == 0x20; + dataIncluded[20] = (byte1 & 0x10) == 0x10; + dataIncluded[19] = (byte1 & 0x8) == 0x8; + dataIncluded[18] = (byte1 & 0x4) == 0x4; + dataIncluded[17] = (byte1 & 0x2) == 0x2; + dataIncluded[16] = (byte1 & 0x1) == 0x1; + } + + if (l >= 6) { + byte1 = bk.getNextByte(); + dataIncluded[15] = (byte1 & 0x80) == 0x80; + dataIncluded[14] = (byte1 & 0x40) == 0x40; + dataIncluded[13] = (byte1 & 0x20) == 0x20; + dataIncluded[12] = (byte1 & 0x10) == 0x10; + dataIncluded[11] = (byte1 & 0x8) == 0x8; + dataIncluded[10] = (byte1 & 0x4) == 0x4; + dataIncluded[9] = (byte1 & 0x2) == 0x2; + dataIncluded[8] = (byte1 & 0x1) == 0x1; + } + + if (l >= 7) { + byte1 = bk.getNextByte(); + dataIncluded[7] = (byte1 & 0x80) == 0x80; + dataIncluded[6] = (byte1 & 0x40) == 0x40; + dataIncluded[5] = (byte1 & 0x20) == 0x20; + dataIncluded[4] = (byte1 & 0x10) == 0x10; + dataIncluded[3] = (byte1 & 0x8) == 0x8; + dataIncluded[2] = (byte1 & 0x4) == 0x4; + dataIncluded[1] = (byte1 & 0x2) == 0x2; + dataIncluded[0] = (byte1 & 0x1) == 0x1; + } + return false; + } else { + sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x2B, + "invalid SOH length"); + return true; + } + + } + + private void processCC0(byte byte0) { + log.debug(" Control byte0 " + Integer.toBinaryString(byte0 & 0xff)); + boolean lockKeyboard = true; + boolean resetMDT = false; + boolean resetMDTAll = false; + boolean nullMDT = false; + boolean nullAll = false; + + // Bits 3 to 6 are reserved and should be set to '0000' + // 0xE0 = '11100000' - only the first 3 bits are tested + if ((byte0 & 0xE0) == 0x00) { + lockKeyboard = false; + } + + // '00100000' = 0x20 /32 -- just lock keyboard + // '01000000' = 0x40 /64 + // '01100000' = 0x60 /96 + // '10000000' = 0x80 /128 + // '10100000' = 0xA0 /160 + // '11000000' = 0xC0 /192 + // '11100000' = 0xE0 /224 + + switch (byte0 & 0xE0) { + + case 0x40: + resetMDT = true; + break; + case 0x60: + resetMDTAll = true; + break; + case 0x80: + nullMDT = true; + break; + case 0xA0: + resetMDT = true; + nullAll = true; + break; + case 0xC0: + resetMDT = true; + nullMDT = true; + break; + + case 0xE0: + resetMDTAll = true; + nullAll = true; + break; + + } + + if (lockKeyboard) { + screen52.getOIA().setKeyBoardLocked(true); + pendingUnlock = false; + } else + pendingUnlock = false; + + if (resetMDT || resetMDTAll || nullMDT || nullAll) { + ScreenField sf; + + int f = screen52.getScreenFields().getSize(); + for (int x = 0; x < f; x++) { + sf = screen52.getScreenFields().getField(x); + + if (!sf.isBypassField()) { + if ((nullMDT && sf.mdt) || nullAll) { + sf.setFieldChar((char) 0x0); + screen52.drawField(sf); + } + } + if (resetMDTAll || (resetMDT && !sf.isBypassField())) + sf.resetMDT(); + + } + sf = null; + } + + } + + private void processCC1(byte byte1) { + log.debug(" Control byte1 " + Integer.toBinaryString(byte1 & 0xff)); + + if ((byte1 & 0x04) == 0x04) { + controller.signalBell(); + } + if ((byte1 & 0x02) == 0x02) { + screen52.getOIA().setMessageLightOff(); + } + if ((byte1 & 0x01) == 0x01) { + screen52.getOIA().setMessageLightOn(); + } + + if ((byte1 & 0x01) == 0x01 && (byte1 & 0x02) == 0x02) { + screen52.getOIA().setMessageLightOn(); + } + + // reset blinking cursor seems to control whether to set or not set the + // the cursor position. No documentation for this just testing and + // looking at the bit settings of this field. This was a pain in the + // ass! + // + // if it is off '0' then keep existing cursor positioning information + // if it is on '1' then reset the cursor positioning information + // *** Note *** unless we receive bit 4 on at the same time + // this seems to work so far + if ((byte1 & 0x20) == 0x20 && (byte1 & 0x08) == 0x00) { + screen52.setPendingInsert(false); + log.debug(" WTD position no move"); + } else { + + screen52.setPendingInsert(true); + log.debug(" WTD position move to home" + screen52.homePos + " row " + + screen52.getRow(screen52.homePos) + " col " + + screen52.getCol(screen52.homePos)); + + } + // in enhanced mode we sometimes only receive bit 6 turned on which + // is reset blinking cursor + if ((byte1 & 0x20) == 0x20 && enhanced) { + cursorOn = true; + } + + if (!screen52.isStatusErrorCode() && (byte1 & 0x08) == 0x08) { + + // screen52.setStatus(screen52.STATUS_SYSTEM,screen52.STATUS_VALUE_OFF,null); + cursorOn = true; + } + + if ((byte1 & 0x20) == 0x20 && (byte1 & 0x08) == 0x00) { + screen52.setPendingInsert(false, 1, 1); + } + + } + + private boolean isAttribute(int byte0) { + int byte1 = byte0 & 0xff; + return (byte1 & 0xe0) == 0x20; + } + + //LDC - 12/02/2003 - Function name changed from isData to isDataEBCDIC + private boolean isDataEBCDIC(int byte0) { + int byte1 = byte0 & 0xff; + // here it should always be less than 255 + if (byte1 >= 64 && byte1 < 255) + + return true; + else + return false; + + } + + //LDC - 12/02/2003 - Test if the unicode character is a displayable + // character. + // The first 32 characters are non displayable characters + // This is normally the inverse of isDataEBCDIC (That's why there is a + // check on 255 -> 0xFFFF + private boolean isDataUnicode(int byte0) { + return (((byte0 < 0) || (byte0 >= 32)) && (byte0 != 0xFFFF)); + } + + private void writeStructuredField() { + + boolean done = false; + try { + int length = ((bk.getNextByte() & 0xff) << 8 | (bk.getNextByte() & 0xff)); + while (bk.hasNext() && !done) { + switch (bk.getNextByte()) { + + case -39: // SOH - Start of Header Order + + switch (bk.getNextByte()) { + case 112: // 5250 Query + bk.getNextByte(); // get null required field + sendQueryResponse(); + break; + default: + log.debug("invalid structured field sub command " + + bk.getByteOffset(-1)); + break; + } + break; + default: + log.debug("invalid structured field command " + + bk.getByteOffset(-1)); + break; + } + } + } catch (Exception e) { + } + ; + + } + + private final void writeErrorCode() throws Exception { + screen52.setCursor(screen52.getErrorLine(), 1); // Skip the control byte + screen52.setStatus(Screen5250.STATUS_ERROR_CODE, + Screen5250.STATUS_VALUE_ON, null); + screen52.saveErrorLine(); + cursorOn = true; + + } + + private final void writeErrorCodeToWindow() throws Exception { + int fromCol = bk.getNextByte() & 0xff; // from column + int toCol = bk.getNextByte() & 0xff; // to column + screen52.setCursor(screen52.getErrorLine(), fromCol); // Skip the control + // byte + screen52.setStatus(Screen5250.STATUS_ERROR_CODE, + Screen5250.STATUS_VALUE_ON, null); + screen52.saveErrorLine(); + cursorOn = true; + + } + + /** + * Method sendQueryResponse + * + * The query command is used to obtain information about the capabilities of + * the 5250 display. + * + * The Query command must follow an Escape (0x04) and Write Structured Field + * command (0xF3). + * + * This section is modeled after the rfc1205 - 5250 Telnet Interface section + * 5.3 + * + * @throws IOException + */ + private final void sendQueryResponse() throws IOException { + + log.info("sending query response"); + byte abyte0[] = new byte[64]; + abyte0[0] = 0; // Cursor Row/column (set to zero) + abyte0[1] = 0; // "" + abyte0[2] = -120; // X'88' inbound write structure Field aid + if (enhanced == true) { + abyte0[3] = 0; // 0x003D (61) length of query response + abyte0[4] = 64; // "" see note below ????????? + } else { + abyte0[3] = 0; // 0x003A (58) length of query response + abyte0[4] = 58; // "" + // the length between 58 and 64 seems to cause + // different formatting codes to be sent from + // the host ???????????????? why ??????? + // Well the why can be found in the manual if + // read a little more ;-) + } + abyte0[5] = -39; // command class 0xD9 + abyte0[6] = 112; // Command type query 0x70 + abyte0[7] = -128; // 0x80 Flag byte + abyte0[8] = 6; // Controller Hardware Class + abyte0[9] = 0; // 0x0600 - Other WSF or another 5250 Emulator + abyte0[10] = 1; // Controller Code Level + abyte0[11] = 1; // Version 1 Rel 1.0 + abyte0[12] = 0; // "" + + abyte0[13] = 0; // 13 - 28 are reserved so set to 0x00 + abyte0[14] = 0; // "" + abyte0[15] = 0; // "" + abyte0[16] = 0; // "" + abyte0[17] = 0; // "" + abyte0[18] = 0; // "" + abyte0[19] = 0; // "" + abyte0[20] = 0; // "" + abyte0[21] = 0; // "" + abyte0[22] = 0; // "" + abyte0[23] = 0; // "" + abyte0[24] = 0; // "" + abyte0[25] = 0; // "" + abyte0[26] = 0; // "" + abyte0[27] = 0; // "" + abyte0[28] = 0; // "" + abyte0[29] = 1; // Device type - 0x01 5250 Emulator + abyte0[30] = codePage.uni2ebcdic('5'); // Device type character + abyte0[31] = codePage.uni2ebcdic('2'); // "" + abyte0[32] = codePage.uni2ebcdic('5'); // "" + abyte0[33] = codePage.uni2ebcdic('1'); // "" + abyte0[34] = codePage.uni2ebcdic('0'); // "" + abyte0[35] = codePage.uni2ebcdic('1'); // "" + abyte0[36] = codePage.uni2ebcdic('1'); // "" + + abyte0[37] = 2; // Keyboard Id - 0x02 Standard Keyboard + abyte0[38] = 0; // extended keyboard id + abyte0[39] = 0; // reserved + + abyte0[40] = 0; // 40 - 43 Display Serial Number + abyte0[41] = 36; // + abyte0[42] = 36; // + abyte0[43] = 0; // + + abyte0[44] = 1; // Maximum number of display fields - 256 + abyte0[45] = 0; // 0x0100 + abyte0[46] = 0; // 46 -48 Reserved set to 0x00 + abyte0[47] = 0; + abyte0[48] = 0; + abyte0[49] = 1; // 49 - 53 Controller Display Capability + abyte0[50] = 17; // see rfc - tired of typing :-) + abyte0[51] = 0; // "" + abyte0[52] = 0; // "" + + // 53 + // Bit 0-2: B'000' - no graphics capability + // B'001' - 5292-2 style graphics + // Bit 3-7: B '00000' = reserved (it seems for Client access) + + if (enhanced == true) { + // abyte0[53] = 0x5E; // 0x5E turns on ehnhanced mode + // abyte0[53] = 0x27; // 0x5E turns on ehnhanced mode + abyte0[53] = 0x7; // 0x5E turns on ehnhanced mode + log.info("enhanced options"); + } else + abyte0[53] = 0x0; // 0x0 is normal emulation + + abyte0[54] = 24; // 54 - 60 Reserved set to 0x00 + // 54 - I found out is used for enhanced user + // interface level 3. Bit 4 allows headers + // and footers for windows + abyte0[54] = 8; // 54 - 60 Reserved set to 0x00 + // 54 - I found out is used for enhanced user + // interface level 3. Bit 4 allows headers + // and footers for windows + abyte0[55] = 0; + abyte0[56] = 0; + abyte0[57] = 0; + abyte0[58] = 0; + abyte0[59] = 0; + abyte0[60] = 0; + abyte0[61] = 0; // gridlines are not supported + abyte0[62] = 0; // gridlines are not supported + abyte0[63] = 0; + writeGDS(0, 0, abyte0); // now tell them about us + abyte0 = null; + + } + + protected final boolean negotiate(byte abyte0[]) throws IOException { + int i = 0; + + + // from server negotiations + if(abyte0[i] == IAC) { // -1 + + while(i < abyte0.length && abyte0[i++] == -1) + // while(i < abyte0.length && (abyte0[i] == -1 || abyte0[i++] == 0x20)) + switch(abyte0[i++]) { + + // we will not worry about what it WONT do + case WONT: // -4 + default: + break; + + case DO: //-3 + + // not sure why but since moving to V5R2 we are receiving a + // DO with no option when connecting a second session with + // device name. Can not find the cause at all. If anybody + // is interested please debug this until then this works. + if (i < abyte0.length) { + switch(abyte0[i]) { + case TERMINAL_TYPE: // 24 + baosp.write(IAC); + baosp.write(WILL); + baosp.write(TERMINAL_TYPE); + writeByte(baosp.toByteArray()); + baosp.reset(); + + break; + + case OPT_END_OF_RECORD: // 25 + + baosp.write(IAC); + baosp.write(WILL); + baosp.write(OPT_END_OF_RECORD); + writeByte(baosp.toByteArray()); + baosp.reset(); + break; + + case TRANSMIT_BINARY: // 0 + + baosp.write(IAC); + baosp.write(WILL); + baosp.write(TRANSMIT_BINARY); + writeByte(baosp.toByteArray()); + baosp.reset(); + + break; + + case TIMING_MARK: // 6 rfc860 + // System.out.println("Timing Mark Received and notifying " + + // "the server that we will not do it"); + baosp.write(IAC); + baosp.write(WONT); + baosp.write(TIMING_MARK); + writeByte(baosp.toByteArray()); + baosp.reset(); + + break; + + case NEW_ENVIRONMENT: // 39 rfc1572, rfc4777 + // allways send new environment vars ... + baosp.write(IAC); + baosp.write(WILL); + baosp.write(NEW_ENVIRONMENT); + writeByte(baosp.toByteArray()); + baosp.reset(); + break; + + default: // every thing else we will not do at this time + baosp.write(IAC); + baosp.write(WONT); + baosp.write(abyte0[i]); // either + writeByte(baosp.toByteArray()); + baosp.reset(); + + break; + } + } + + i++; + break; + + case WILL: + + switch(abyte0[i]) { + case OPT_END_OF_RECORD: // 25 + baosp.write(IAC); + baosp.write(DO); + baosp.write(OPT_END_OF_RECORD); + writeByte(baosp.toByteArray()); + baosp.reset(); + + break; + + case TRANSMIT_BINARY: // '\0' + baosp.write(IAC); + baosp.write(DO); + baosp.write(TRANSMIT_BINARY); + writeByte(baosp.toByteArray()); + baosp.reset(); + + break; + } + i++; + break; + + case SB: // -6 + + if(abyte0[i] == NEW_ENVIRONMENT && abyte0[i + 1] == 1) { + negNewEnvironment(); + + while (++i < abyte0.length && abyte0[i + 1] != IAC); + } + + if(abyte0[i] == TERMINAL_TYPE && abyte0[i + 1] == 1) { + baosp.write(IAC); + baosp.write(SB); + baosp.write(TERMINAL_TYPE); + baosp.write(QUAL_IS); + if(!support132) + baosp.write("IBM-3179-2".getBytes()); + else + baosp.write("IBM-3477-FC".getBytes()); + baosp.write(IAC); + baosp.write(SE); + writeByte(baosp.toByteArray()); + baosp.reset(); + + i++; + } + i++; + break; + } + return true; + } + else { + return false; + } + } + + /** + * Negotiate new environment string for device name + * + * @throws IOException + */ + private void negNewEnvironment() throws IOException { + + baosp.write(IAC); + baosp.write(SB); + baosp.write(NEW_ENVIRONMENT); + baosp.write(IS); + + // http://tools.ietf.org/html/rfc4777 + + if (kbdTypesCodePage != null) { + baosp.write(USERVAR); + baosp.write("KBDTYPE".getBytes()); + baosp.write(VALUE); + baosp.write(kbdTypesCodePage.kbdType.getBytes()); + + baosp.write(USERVAR); + baosp.write("CODEPAGE".getBytes()); + baosp.write(VALUE); + baosp.write(kbdTypesCodePage.codepage.getBytes()); + + baosp.write(USERVAR); + baosp.write("CHARSET".getBytes()); + baosp.write(VALUE); + baosp.write(kbdTypesCodePage.charset.getBytes()); + } + + if (devName != null) { + baosp.write(USERVAR); + + baosp.write("DEVNAME".getBytes()); + + baosp.write(VALUE); + + baosp.write(negDeviceName().getBytes()); + } + + if (user != null) { + + baosp.write(VAR); + baosp.write("USER".getBytes()); + baosp.write(VALUE); + baosp.write(user.getBytes()); + + if (password != null) { + baosp.write(USERVAR); + baosp.write("IBMRSEED".getBytes()); + baosp.write(VALUE); + baosp.write(NEGOTIATE_ESC); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(0x0); + baosp.write(USERVAR); + baosp.write("IBMSUBSPW".getBytes()); + baosp.write(VALUE); + baosp.write(password.getBytes()); + } + + if (library != null) { + baosp.write(USERVAR); + baosp.write("IBMCURLIB".getBytes()); + baosp.write(VALUE); + baosp.write(library.getBytes()); + } + + if (initialMenu != null) { + baosp.write(USERVAR); + baosp.write("IBMIMENU".getBytes()); + baosp.write(VALUE); + baosp.write(initialMenu.getBytes()); + } + + if (program != null) { + baosp.write(USERVAR); + baosp.write("IBMPROGRAM".getBytes()); + baosp.write(VALUE); + baosp.write(program.getBytes()); + } + } + baosp.write(IAC); + baosp.write(SE); + + writeByte(baosp.toByteArray()); + baosp.reset(); + + } + + /** + * This will negotiate a device name with controller. if the sequence is + * less than zero then it will send the device name as specified. On each + * unsuccessful attempt a sequential number is appended until we find one or + * the controller says no way. + * + * @return String + */ + private String negDeviceName() { + + if (devSeq++ == -1) { + devNameUsed = devName; + return devName; + } else { + StringBuffer sb = new StringBuffer(devName + devSeq); + int ei = 1; + while (sb.length() > 10) { + + sb.setLength(0); + sb.append(devName.substring(0, devName.length() - ei++)); + sb.append(devSeq); + + } + devNameUsed = sb.toString(); + return devNameUsed; + } + } + + public final void setCodePage(String cp) { + codePage = CharMappings.getCodePage(cp); + cp = cp.toLowerCase(); + for (KbdTypesCodePages kbdtyp : KbdTypesCodePages.values()) { + if (("cp"+kbdtyp.codepage).equals(cp) || kbdtyp.ccsid.equals(cp)) { + kbdTypesCodePage = kbdtyp; + break; + } + } + if (log.isInfoEnabled()) { + log.info("Choosed keyboard mapping " + kbdTypesCodePage.toString() + " for code page " + cp); + } + } + + public final ICodePage getCodePage() { + return codePage; + } + + /** + * @see org.tn5250j.Session5250#signalBell() + */ + public void signalBell() { + controller.signalBell(); + } + +} diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/transport/SSL/SSLImplementation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/transport/SSL/SSLImplementation.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,211 @@ +package org.tn5250j.framework.transport.SSL; + +/* + * @(#)SSLImplementation.java + * @author Stephen M. Kennedy + * + * Copyright: Copyright (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.net.Socket; +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import javax.swing.JOptionPane; + +import org.tn5250j.GlobalConfigure; +import org.tn5250j.framework.transport.SSLInterface; +import org.tn5250j.tools.logging.TN5250jLogFactory; +import org.tn5250j.tools.logging.TN5250jLogger; + +/** + *

+ * This class implements the SSLInterface and is used to create SSL socket + * instances. + *

+ * + * @author Stephen M. Kennedy + * + */ +public class SSLImplementation implements SSLInterface, X509TrustManager { + + SSLContext sslContext = null; + + KeyStore userks = null; + private String userKsPath; + private char[] userksPassword = "changeit".toCharArray(); + + KeyManagerFactory userkmf = null; + + TrustManagerFactory usertmf = null; + + TrustManager[] userTrustManagers = null; + + X509Certificate[] acceptedIssuers; + + TN5250jLogger logger; + + public SSLImplementation() { + logger = TN5250jLogFactory.getLogger(getClass()); + } + + public void init(String sslType) { + try { + logger.debug("Initializing User KeyStore"); + userKsPath = System.getProperty("user.home") + File.separator + + GlobalConfigure.TN5250J_FOLDER + File.separator + "keystore"; + File userKsFile = new File(userKsPath); + userks = KeyStore.getInstance(KeyStore.getDefaultType()); + userks.load(userKsFile.exists() ? new FileInputStream(userKsFile) + : null, userksPassword); + logger.debug("Initializing User Key Manager Factory"); + userkmf = KeyManagerFactory.getInstance(KeyManagerFactory + .getDefaultAlgorithm()); + userkmf.init(userks, userksPassword); + logger.debug("Initializing User Trust Manager Factory"); + usertmf = TrustManagerFactory.getInstance(TrustManagerFactory + .getDefaultAlgorithm()); + usertmf.init(userks); + userTrustManagers = usertmf.getTrustManagers(); + logger.debug("Initializing SSL Context"); + sslContext = SSLContext.getInstance(sslType); + sslContext.init(userkmf.getKeyManagers(), new TrustManager[] {this}, null); + } catch (Exception ex) { + logger.error("Error initializing SSL [" + ex.getMessage() + "]"); + } + + } + + public Socket createSSLSocket(String destination, int port) { + if (sslContext == null) + throw new IllegalStateException("SSL Context Not Initialized"); + SSLSocket socket = null; + try { + socket = (SSLSocket) sslContext.getSocketFactory().createSocket( + destination, port); + } catch (Exception e) { + logger.error("Error creating ssl socket [" + e.getMessage() + "]"); + } + return socket; + } + + // X509TrustManager Methods + + /* + * (non-Javadoc) + * + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + public X509Certificate[] getAcceptedIssuers() { + return acceptedIssuers; + } + + /* + * (non-Javadoc) + * + * @see + * javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert. + * X509Certificate[], java.lang.String) + */ + public void checkClientTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException { + throw new SecurityException("checkClientTrusted unsupported"); + + } + + /* + * (non-Javadoc) + * + * @see + * javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert. + * X509Certificate[], java.lang.String) + */ + public void checkServerTrusted(X509Certificate[] chain, String type) + throws CertificateException { + try { + for (int i = 0; i < userTrustManagers.length; i++) { + if (userTrustManagers[i] instanceof X509TrustManager) { + X509TrustManager trustManager = (X509TrustManager) userTrustManagers[i]; + X509Certificate[] calist = trustManager + .getAcceptedIssuers(); + if (calist.length > 0) { + trustManager.checkServerTrusted(chain, type); + } else { + throw new CertificateException( + "Empty list of accepted issuers (a.k.a. root CA list)."); + } + } + } + return; + } catch (CertificateException ce) { + X509Certificate cert = chain[0]; + String certInfo = "Version: " + cert.getVersion() + "\n"; + certInfo = certInfo.concat("Serial Number: " + + cert.getSerialNumber() + "\n"); + certInfo = certInfo.concat("Signature Algorithm: " + + cert.getSigAlgName() + "\n"); + certInfo = certInfo.concat("Issuer: " + + cert.getIssuerDN().getName() + "\n"); + certInfo = certInfo.concat("Valid From: " + cert.getNotBefore() + + "\n"); + certInfo = certInfo + .concat("Valid To: " + cert.getNotAfter() + "\n"); + certInfo = certInfo.concat("Subject DN: " + + cert.getSubjectDN().getName() + "\n"); + certInfo = certInfo.concat("Public Key: " + + cert.getPublicKey().getFormat() + "\n"); + + int accept = JOptionPane + .showConfirmDialog(null, certInfo, "Unknown Certificate - Do you accept it?", + javax.swing.JOptionPane.YES_NO_OPTION); + if (accept != JOptionPane.YES_OPTION) { + throw new java.security.cert.CertificateException( + "Certificate Rejected"); + } + + int save = JOptionPane.showConfirmDialog(null, + "Remember this certificate?", "Save Certificate", + javax.swing.JOptionPane.YES_NO_OPTION); + + if (save == JOptionPane.YES_OPTION) { + try { + userks.setCertificateEntry(cert.getSubjectDN().getName(), + cert); + userks.store(new FileOutputStream(userKsPath), + userksPassword); + } catch (Exception e) { + logger.error("Error saving certificate [" + e.getMessage() + + "]"); + e.printStackTrace(); + } + } + } + + } +} \ No newline at end of file diff -r a01665cb683d -r e8d2a24e85c6 src/org/tn5250j/framework/transport/SSL/X509CertificateTrustManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/framework/transport/SSL/X509CertificateTrustManager.java Thu May 22 12:11:10 2014 -0700 @@ -0,0 +1,102 @@ +package org.tn5250j.framework.transport.SSL; + +/* + * @(#)X509CertificateTrustManager.java + * + * Copyright: Copyright (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + */ +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Arrays; + +import javax.swing.JOptionPane; + +/** + * This class is used to trust certificates exchanged during an SSL socket + * handshake. It allows the user to accept the certificate so that connections + * can be made without requiring the server to have a certificate signed by a + * CA (Verisign, Thawte, etc.). + * + * @author Stephen M. Kennedy + * @deprecated. no longer used. + * + */ +public class X509CertificateTrustManager implements X509TrustManager { + + KeyStore ks = null; + TrustManager[] trustManagers; + //X509TrustManager trustManager = null; + + public X509CertificateTrustManager(TrustManager[] managers, KeyStore keyStore) { + trustManagers = managers; + ks = keyStore; + } + + public void checkClientTrusted(X509Certificate[] chain, String type) throws CertificateException { + throw new SecurityException("checkClientTrusted unsupported"); + } + + + /** + * Checks the server certificate. If it isn't trusted by the trust manager + * passed to the constructor, then the user will be prompted to accept the + * certificate. + */ + public void checkServerTrusted(X509Certificate[] chain, String type) + throws CertificateException { + try { + for (int i=0; i list = new ArrayList(10); + for (int i=0; i(by setSSLType(String)), then + * a plain socket will be created. Otherwise, a new SSL socket of the + * specified type will be created. + * @param destination + * @param port + * @return a new client socket, or null if + */ + public Socket createSocket(String destination, int port) { + + Socket socket = null; + Exception ex = null; + + if (sslType == null || sslType.trim().length() == 0 || + sslType.toUpperCase().equals(TN5250jConstants.SSL_TYPE_NONE)) { + logger.info("Creating Plain Socket"); + try { + // Use Socket Constructor!!! SocketFactory for jdk 1.4 + socket = new Socket(destination,port); + } catch (Exception e) { + ex = e; + } + } else { //SSL SOCKET + + logger.info("Creating SSL ["+sslType+"] Socket"); + + SSLInterface sslIf = null; + + String sslImplClassName = + "org.tn5250j.framework.transport.SSL.SSLImplementation"; + try { + Class c = Class.forName(sslImplClassName); + sslIf = (SSLInterface)c.newInstance(); + } catch (Exception e) { + ex = new Exception("Failed to create SSLInterface Instance. " + + "Message is ["+e.getMessage()+"]"); + } + + if (sslIf != null) { + sslIf.init(sslType); + socket = sslIf.createSSLSocket(destination,port); + } + } + + if (ex != null) { + logger.error(ex); + } + if (socket == null) { + logger.warn("No socket was created"); + } + return socket; + } + + +} \ No newline at end of file