# HG changeset patch # User Carl Byington # Date 1402932240 25200 # Node ID 01d939969b10a1aa576f49755f286d0ced71aca1 # Parent b3d0d806cbe2567100d5df978a5617f0f47bcc32# Parent 044b1a9519257e8ea947b6746e5c1c8e7ba1b879 merge tn5250 branch into default diff -r b3d0d806cbe2 -r 01d939969b10 AndroidManifest.xml --- a/AndroidManifest.xml Tue Jun 03 08:48:14 2014 -0700 +++ b/AndroidManifest.xml Mon Jun 16 08:24:00 2014 -0700 @@ -17,7 +17,7 @@ --> @@ -63,9 +63,10 @@ - + + - + @@ -104,9 +105,10 @@ - + + - + diff -r b3d0d806cbe2 -r 01d939969b10 Makefile --- a/Makefile Tue Jun 03 08:48:14 2014 -0700 +++ b/Makefile Mon Jun 16 08:24:00 2014 -0700 @@ -6,7 +6,11 @@ apk='bin/510Connectbot-$(style).apk' all: - hg pull; hg update; rm -rf gen bin + hg pull; hg update + make builder + +builder: + rm -rf gen bin ndk-build clean; V=1 ndk-build android update project -p . -t android-16 ant $(style) diff -r b3d0d806cbe2 -r 01d939969b10 TODO --- a/TODO Tue Jun 03 08:48:14 2014 -0700 +++ b/TODO Mon Jun 16 08:24:00 2014 -0700 @@ -31,16 +31,19 @@ # reinstall all jsocks and ssh2 patches from vxconnectbot since the split (cd ../vxconnectbot; git diff -w 598fb427f96712191cc264df14688d82db3dd664) | less +================================== + +merge tn5250j +svn checkout svn://svn.code.sf.net/p/tn5250j/code/branches/new-tabs-jse1.6 tn5250j ================================== TODO: +possible merge of irssi? + https://github.com/irssiconnectbot/irssiconnectbot 1.7.1-395 - a year ago -merge tn5250j -svn checkout svn://svn.code.sf.net/p/tn5250j/code/trunk tn5250j -after 5250 merge, go up to version 1.8.0-1 diff -r b3d0d806cbe2 -r 01d939969b10 assets/help/About.html --- a/assets/help/About.html Tue Jun 03 08:48:14 2014 -0700 +++ b/assets/help/About.html Mon Jun 16 08:24:00 2014 -0700 @@ -8,7 +8,7 @@ <carl@five-ten-sg.com>

This is an enhanced version of the popular open-source telnet and -secure shell (SSH) client ConnectBot.

+secure shell (SSH) client ConnectBot. It now includes tn5250 emulation.

It is licensed under the GPLv3 or later @@ -50,6 +50,12 @@

+Based on TN5250J terminal emulator provided under the GPLv2 +license. Copyright © 2001 Kenneth J. Pouncey. +http://tn5250j.sourceforge.net +

+ +

Includes the JSOCKS library, provided under the GNU LGPL license. http://jsocks.sourceforge.net

diff -r b3d0d806cbe2 -r 01d939969b10 res/values/arrays.xml --- a/res/values/arrays.xml Tue Jun 03 08:48:14 2014 -0700 +++ b/res/values/arrays.xml Mon Jun 16 08:24:00 2014 -0700 @@ -27,6 +27,13 @@ screen + + NONE + SSLv2 + SSLv3 + TLS + + @string/list_rotation_default @string/list_rotation_land diff -r b3d0d806cbe2 -r 01d939969b10 res/values/strings.xml --- a/res/values/strings.xml Tue Jun 03 08:48:14 2014 -0700 +++ b/res/values/strings.xml Mon Jun 16 08:24:00 2014 -0700 @@ -119,6 +119,20 @@ "Host %1$s key fingerprint is %2$s" + + "Version: " + "Serial Number: " + "Signature Algorithm: " + "Issuer: " + "Valid From: " + "Valid To: " + "Subject DN: " + "Public Key: " + "The certificate is %1$s" + "Unknown Certificate - Do you accept it?" + "Do you want to save this certificate?" + "Enter sys-request string" + "Passwords do not match!" "Wrong password!" "Private key appears corrupt!" @@ -332,6 +346,13 @@ "Monitor Init String" + + "Emulation mode" + "Override global emulation mode / answerback string" + + + "Host 5250 Encryption" + "X11 forwarding" @@ -501,7 +522,7 @@ "Session will not be started due to host preference." "Enable port forward: %1$s" - "Failure! Local shell is unavailable on this phone." + "Failure! Local shell is unavailable on this device." "%1$s wants your attention." diff -r b3d0d806cbe2 -r 01d939969b10 res/xml/host_prefs.xml --- a/res/xml/host_prefs.xml Tue Jun 03 08:48:14 2014 -0700 +++ b/res/xml/host_prefs.xml Mon Jun 16 08:24:00 2014 -0700 @@ -20,141 +20,156 @@ - + - + - + - + - + - + - + - + - + - + - + + + + + - + - + - + - + - + - - + + - + + - + - + - + - + diff -r b3d0d806cbe2 -r 01d939969b10 res/xml/preferences.xml --- a/res/xml/preferences.xml Tue Jun 03 08:48:14 2014 -0700 +++ b/res/xml/preferences.xml Mon Jun 16 08:24:00 2014 -0700 @@ -52,7 +52,7 @@ android:summary="@string/pref_emulation_summary" android:entries="@array/list_emulation_modes" android:entryValues="@array/list_emulation_modes" - android:defaultValue="screen" + android:defaultValue="xterm-256color" /> parent, View view, int position, long id) { // launch off to console details - HostBean host = (HostBean) parent.getAdapter().getItem(position); + HostBean host = (HostBean) getListView().getItemAtPosition(position); Uri uri = host.getUri(); Intent contents = new Intent(Intent.ACTION_VIEW, uri); contents.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); @@ -205,11 +204,10 @@ } else { // otherwise just launch activity to show this host - HostListActivity.this.startActivity(contents); + startActivity(contents); } } }); - this.registerForContextMenu(list); quickconnect = (TextView) this.findViewById(R.id.front_quickconnect); quickconnect.setVisibility(makingShortcut ? View.GONE : View.VISIBLE); quickconnect.setOnKeyListener(new OnKeyListener() { diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/TerminalView.java --- a/src/com/five_ten_sg/connectbot/TerminalView.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/TerminalView.java Mon Jun 16 08:24:00 2014 -0700 @@ -85,6 +85,8 @@ private Matcher mCodeMatcher = null; private AccessibilityEventSender mEventSender = null; + public static String android_home_directory = ""; + private static final String BACKSPACE_CODE = "\\x08\\x1b\\[K"; private static final String CONTROL_CODE_PATTERN = "\\x1b\\[K[^m]+[m|:]"; @@ -96,6 +98,7 @@ public TerminalView(Context context, TerminalBridge bridge) { super(context); + android_home_directory = context.getApplicationInfo().dataDir; this.context = context; this.bridge = bridge; paint = new Paint(); diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/bean/HostBean.java --- a/src/com/five_ten_sg/connectbot/bean/HostBean.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/bean/HostBean.java Mon Jun 16 08:24:00 2014 -0700 @@ -29,31 +29,33 @@ public static final String BEAN_NAME = "host"; /* Database fields */ - private long id = -1; - private String nickname = null; - private String username = null; - private String hostname = null; - private int port = 22; - private String protocol = "ssh"; - private String hostKeyAlgo = null; - private byte[] hostKey = null; - private long lastConnect = -1; - private String color; + private long id = -1; + private String nickname = null; + private String username = null; + private String hostname = null; + private int port = 22; + private String protocol = "ssh"; + private String hostKeyAlgo = null; + private byte[] hostKey = null; + private long lastConnect = -1; + private String color; private boolean useKeys = true; - private String useAuthAgent = HostDatabase.AUTHAGENT_NO; - private String postLogin = null; - private long pubkeyId = -1; + private String useAuthAgent = HostDatabase.AUTHAGENT_NO; + private String postLogin = null; + private long pubkeyId = -1; private boolean wantSession = true; - private String delKey = HostDatabase.DELKEY_DEL; - private int fontSize = -1; + private String delKey = HostDatabase.DELKEY_DEL; + private int fontSize = -1; private boolean compression = false; - private String httpproxy = null; - private String encoding = HostDatabase.ENCODING_DEFAULT; + private String httpproxy = null; + private String encoding = HostDatabase.ENCODING_DEFAULT; private boolean stayConnected = false; private boolean wantX11Forward = false; - private String x11Host = "localhost"; - private int x11Port = 6000; - private String monitor = null; + private String x11Host = "localhost"; + private int x11Port = 6000; + private String monitor = null; + private String hostemulation = null; + private String encryption5250 = null; public HostBean() { } @@ -252,6 +254,22 @@ this.monitor = monitor; } + public String getHostEmulation() { + return this.hostemulation; + } + + public void setHostEmulation(String hostemulation) { + this.hostemulation = hostemulation; + } + + public String getEncryption5250() { + return this.encryption5250; + } + + public void setEncryption5250(String encryption5250) { + this.encryption5250 = encryption5250; + } + @Override public ContentValues getValues() { ContentValues values = new ContentValues(); @@ -279,6 +297,8 @@ values.put(HostDatabase.FIELD_HOST_X11HOST, x11Host); values.put(HostDatabase.FIELD_HOST_X11PORT, x11Port); values.put(HostDatabase.FIELD_HOST_MONITOR, monitor); + values.put(HostDatabase.FIELD_HOST_EMULATION, hostemulation); + values.put(HostDatabase.FIELD_HOST_ENCRYPTION5250, encryption5250); return values; } diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/service/TerminalBridge.java --- a/src/com/five_ten_sg/connectbot/service/TerminalBridge.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/service/TerminalBridge.java Mon Jun 16 08:24:00 2014 -0700 @@ -95,13 +95,12 @@ private Relay relay; - private final String emulation; - private final int scrollback; + private String emulation; // aka answerback string, aka terminal type public Bitmap bitmap = null; public vt320 buffer = null; - private TerminalView parent = null; + public TerminalView parent = null; private final Canvas canvas = new Canvas(); private boolean disconnected = false; @@ -120,11 +119,10 @@ // TODO add support for the new clipboard API private ClipboardManager clipboard; - public int charWidth = -1; - public int charHeight = -1; - private int charTop = -1; - - private float fontSize = -1; + public int charWidth = -1; + public int charHeight = -1; + private int charTop = -1; + private float fontSize = -1; private final List fontSizeChangedListeners; @@ -160,7 +158,6 @@ manager = null; defaultPaint = new Paint(); selectionArea = new SelectionArea(); - scrollback = 1; localOutput = new LinkedList(); fontSizeChangedListeners = new LinkedList(); transport = null; @@ -169,16 +166,14 @@ } /** - * Create new terminal bridge with following parameters. We will immediately - * launch thread to start SSH connection and handle any hostkey verification - * and password authentication. + * Create new terminal bridge with following parameters. */ public TerminalBridge(final TerminalManager manager, final HostBean host) throws IOException { float hostFontSize; this.manager = manager; this.host = host; - emulation = manager.getEmulation(); - scrollback = manager.getScrollback(); + emulation = host.getHostEmulation(); + if ((emulation == null) || (emulation.length() == 0)) emulation = manager.getEmulation(); // create prompt helper to relay password and hostkey requests up to gui promptHelper = new PromptHelper(this); // create our default paint @@ -191,128 +186,20 @@ Integer defaultFontSize = Integer.parseInt(manager.prefs.getString(PreferenceConstants.DEFAULT_FONT_SIZE, "-1")); Log.i(TAG, "fontSize: " + this.fontSize + ", defaultFontSize: " + defaultFontSize); - if (this.fontSize == -1) { + if (fontSize == -1) { if (defaultFontSize > 0 && host.getFontSize() == -1) hostFontSize = defaultFontSize; else hostFontSize = host.getFontSize(); } else - hostFontSize = this.fontSize; + hostFontSize = fontSize; - if (hostFontSize <= 0) - hostFontSize = DEFAULT_FONT_SIZE; + if (hostFontSize <= 0) hostFontSize = DEFAULT_FONT_SIZE; setFontSize(hostFontSize); - // create terminal buffer and handle outgoing data - // this is probably status reply information - buffer = new vt320() { - @Override - public void debug(String s) { - Log.d(TAG, s); - } - @Override - public void write(byte[] b) { - try { - if (b != null && transport != null) { - if (monitor != null) monitor.hostData(b); - transport.write(b); - } - } - catch (IOException e) { - Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); - } - } - @Override - public void write(int b) { - try { - if (transport != null) { - if (monitor != null) monitor.hostData(b); - transport.write(b); - } - } - catch (IOException e) { - Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); - } - } - // We don't use telnet sequences. - @Override - public void sendTelnetCommand(byte cmd) { - } - // We don't want remote to resize our window. - @Override - public void setWindowSize(int c, int r) { - } - // test for changed screen contents - @Override - public void testChanged() { - if (monitor != null) monitor.testChanged(); - } - // play beep noise - @Override - public void beep() { - if (parent.isShown()) - manager.playBeep(); - else - manager.sendActivityNotification(host); - } - // monitor placement of new characters - @Override - public void putChar(int c, int l, char ch, int attributes) { - if (monitor != null) monitor.screenChanged(l, c); - - super.putChar(c, l, ch, attributes); - } - @Override - public void insertChar(int c, int l, char ch, int attributes) { - if (monitor != null) monitor.screenChanged(l, l, c, width - 1); - - super.insertChar(c, l, ch, attributes); - } - @Override - public void insertLine(int l, int n, boolean scrollDown) { - if (monitor != null) { - if (scrollDown) monitor.screenChanged(l, height - 1, 0, width - 1); - else monitor.screenChanged(0, l, 0, width - 1); - } - - super.insertLine(l, n, scrollDown); - } - @Override - public void deleteLine(int l) { - if (monitor != null) monitor.screenChanged(l, height - 1, 0, width - 1); - - super.deleteLine(l); - } - @Override - public void deleteChar(int c, int l) { - if (monitor != null) monitor.screenChanged(l, l, c, width - 1); - - super.deleteChar(c, l); - } - @Override - public void setCursorPosition(int c, int l) { - if (monitor != null) monitor.cursorMove(l, c); - - super.setCursorPosition(c, l); - } - }; - - // Don't keep any scrollback if a session is not being opened. - if (host.getWantSession()) - buffer.setBufferSize(scrollback); - else - buffer.setBufferSize(0); - resetColors(); - buffer.setDisplay(this); selectionArea = new SelectionArea(); - keyListener = new TerminalKeyListener(manager, this, buffer, host.getEncoding()); - - String monitor_init = host.getMonitor(); - if ((monitor_init != null) && (monitor_init.length() > 0)) { - monitor = new TerminalMonitor(manager, buffer, keyListener, parent, monitor_init); - } } public PromptHelper getPromptHelper() { @@ -323,15 +210,19 @@ * Spawn thread to open connection and start login process. */ protected void startConnection() { - transport = TransportFactory.getTransport(host.getProtocol()); - transport.setBridge(this); - transport.setManager(manager); - transport.setHost(host); - // TODO make this more abstract so we don't litter on AbsTransport + transport = TransportFactory.getTransport(host.getProtocol()); + transport.setLinks(manager, this, host, emulation); + buffer = transport.getTransportBuffer(); + keyListener = transport.getTerminalKeyListener(); + + String monitor_init = host.getMonitor(); + if ((monitor_init != null) && (monitor_init.length() > 0)) { + monitor = new TerminalMonitor(manager, buffer, keyListener, parent, monitor_init); + } + transport.setCompression(host.getCompression()); transport.setHttpproxy(host.getHttpproxy()); transport.setUseAuthAgent(host.getUseAuthAgent()); - transport.setEmulation(emulation); if (transport.canForwardPorts()) { for (PortForwardBean portForward : manager.hostdb.getPortForwardsForHost(host)) @@ -367,7 +258,8 @@ * @return charset in use by bridge */ public Charset getCharset() { - return relay.getCharset(); + if (relay != null) return relay.getCharset(); + return keyListener.getCharset(); } /** @@ -376,9 +268,7 @@ * @param encoding the canonical name of the character encoding */ public void setCharset(String encoding) { - if (relay != null) - relay.setCharset(encoding); - + if (relay != null) relay.setCharset(encoding); keyListener.setCharset(encoding); } @@ -429,11 +319,8 @@ public void onConnected() { disconnected = false; buffer.reset(); - // We no longer need our local output. - localOutput.clear(); - // previously tried vt100 and xterm for emulation modes - // "screen" works the best for color and escape codes buffer.setAnswerBack(emulation); + localOutput.clear(); // We no longer need our local output. if (HostDatabase.DELKEY_BACKSPACE.equals(host.getDelKey())) buffer.setBackspace(vt320.DELETE_IS_BACKSPACE); @@ -441,11 +328,15 @@ buffer.setBackspace(vt320.DELETE_IS_DEL); // create thread to relay incoming connection data to buffer - relay = new Relay(this, transport, buffer, host.getEncoding()); - Thread relayThread = new Thread(relay); - relayThread.setDaemon(true); - relayThread.setName("Relay"); - relayThread.start(); + // only if needed by the transport + if (transport.needsRelay()) { + relay = new Relay(this, transport, buffer, host.getEncoding()); + Thread relayThread = new Thread(relay); + relayThread.setDaemon(true); + relayThread.setName("Relay"); + relayThread.start(); + } + // force font-size to make sure we resizePTY as needed setFontSize(fontSize); // finally send any post-login string, if requested @@ -563,8 +454,7 @@ charHeight = (int)FloatMath.ceil(fm.descent - fm.top); // refresh any bitmap with new font size - if (parent != null) - parentChanged(parent); + if (parent != null) parentChanged(parent); for (FontSizeChangedListener ofscl : fontSizeChangedListeners) ofscl.onFontSizeChanged(size); @@ -664,8 +554,10 @@ try { // request a terminal pty resize - synchronized (buffer) { - buffer.setScreenSize(columns, rows, true); + if (buffer != null) { + synchronized (buffer) { + buffer.setScreenSize(columns, rows, true); + } } if (transport != null) @@ -675,7 +567,7 @@ Log.e(TAG, "Problem while trying to resize screen or PTY", e); } - // redraw local output if we don't have a sesson to receive our resize request + // redraw local output if we don't have a session to receive our resize request if (transport == null) { synchronized (localOutput) { buffer.reset(); @@ -1246,20 +1138,14 @@ buffer.keyPressed(vt320.KEY_UP, ' ', 0); else if (result.equals("↓")) buffer.keyPressed(vt320.KEY_DOWN, ' ', 0); + else if (result.equals("T")) + buffer.keyPressed(vt320.KEY_TAB, ' ', 0); else if (result.equals("I")) buffer.keyPressed(vt320.KEY_INSERT, ' ', 0); else if (result.equals("D")) buffer.keyPressed(vt320.KEY_DELETE, ' ', 0); else if (result.equals("E")) - buffer.keyTyped(vt320.KEY_ENTER, ' ', 0); - else if (result.equals("T")) { - try { - transport.write(0x09); - } - catch (IOException e) { - Log.e(TAG, "Problem with the arrowsDialog", e); - } - } + buffer.keyPressed(vt320.KEY_ENTER, ' ', 0); } @Override public void onItemClick(AdapterView p, View v, int pos, long id) { @@ -1400,8 +1286,7 @@ else if (result.equals("0")) key = vt320.KEY_F10; - if (key != 0) - buffer.keyPressed(key, ' ', 0); + if (key != 0) buffer.keyPressed(key, ' ', 0); dismiss(); } @@ -1496,10 +1381,7 @@ dismiss(); return true; } - -// return keyListener.onKey(parent, event.getKeyCode(), event); } - return super.dispatchKeyEvent(event); } }; diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/service/TerminalKeyListener.java --- a/src/com/five_ten_sg/connectbot/service/TerminalKeyListener.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/service/TerminalKeyListener.java Mon Jun 16 08:24:00 2014 -0700 @@ -17,6 +17,8 @@ package com.five_ten_sg.connectbot.service; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.lang.ref.WeakReference; import java.util.List; @@ -44,7 +46,6 @@ import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; -import android.widget.Toast; import de.mud.terminal.VDUBuffer; import de.mud.terminal.vt320; @@ -80,30 +81,25 @@ public final static int META_TRANSIENT = META_CTRL_ON | META_ALT_ON | META_SHIFT_ON; - private final TerminalManager manager; - private final TerminalBridge bridge; - private final vt320 buffer; + protected final TerminalManager manager; + protected final TerminalBridge bridge; + protected final vt320 buffer; + protected String encoding; - private String keymode = null; - private boolean hardKeyboard = false; - private String customKeyboard = null; + protected String keymode = null; + protected boolean hardKeyboard = false; + protected boolean hardKeyboardHidden; + protected String customKeyboard = null; - private int metaState = 0; - - private int mDeadKey = 0; + protected int metaState = 0; + protected int mDeadKey = 0; // TODO add support for the new API. private ClipboardManager clipboard = null; - private boolean selectingForCopy = false; - private final SelectionArea selectionArea; + private final SelectionArea selectionArea; + protected final SharedPreferences prefs; - private String encoding; - - private final SharedPreferences prefs; - - private Toast debugToast = null; - private Toast metakeyToast = null; public TerminalKeyListener(TerminalManager manager, TerminalBridge bridge, @@ -116,14 +112,24 @@ selectionArea = new SelectionArea(); prefs = PreferenceManager.getDefaultSharedPreferences(manager); prefs.registerOnSharedPreferenceChangeListener(this); - hardKeyboard = (manager.res.getConfiguration().keyboard - == Configuration.KEYBOARD_QWERTY); + hardKeyboard = (manager.res.getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY); + hardKeyboardHidden = manager.hardKeyboardHidden; updateKeymode(); updateCustomKeymap(); } public void sendEscape() { - buffer.write(0x1b); + buffer.keyPressed(vt320.KEY_ESCAPE, ' ', getStateForBuffer()); + } + + protected void sendEncoded(String s) { + byte [] b = null; + try { + b = s.getBytes(encoding); + } + catch (UnsupportedEncodingException e){ + } + if (b != null) buffer.write(b); } /** @@ -133,28 +139,18 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { try { // skip keys if we aren't connected yet or have been disconnected - if (bridge.isDisconnected() || bridge.transport == null) - return false; - - final boolean hardKeyboardHidden = manager.hardKeyboardHidden; + if (bridge.isDisconnected()) return false; // Ignore all key-up events except for the special keys if (event.getAction() == KeyEvent.ACTION_UP) { // There's nothing here for virtual keyboard users. - if (!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) - return false; + if (!hardKeyboard || hardKeyboardHidden) return false; // if keycode debugging enabled, log and print the pressed key if (prefs.getBoolean(PreferenceConstants.DEBUG_KEYCODES, false)) { String keyCodeString = String.format(": %d", keyCode); String toastText = v.getContext().getString(R.string.keycode_pressed) + keyCodeString; - - if (debugToast == null) - debugToast = Toast.makeText(v.getContext(), toastText, Toast.LENGTH_LONG); - else - debugToast.setText(toastText); - - debugToast.show(); + Log.d(TAG, toastText); } if (fullKeyboard()) { @@ -187,7 +183,7 @@ else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT && (metaState & META_TAB) != 0) { metaState &= ~(META_TAB | META_TRANSIENT); - buffer.write(0x09); + buffer.keyPressed(vt320.KEY_TAB, ' ', getStateForBuffer()); return true; } } @@ -201,7 +197,7 @@ else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT && (metaState & META_TAB) != 0) { metaState &= ~(META_TAB | META_TRANSIENT); - buffer.write(0x09); + buffer.keyPressed(vt320.KEY_TAB, ' ', getStateForBuffer()); return true; } } @@ -213,8 +209,7 @@ if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getAction() == KeyEvent.ACTION_MULTIPLE) { - byte[] input = event.getCharacters().getBytes(encoding); - buffer.write(input); + sendEncoded(event.getCharacters()); return true; } @@ -288,8 +283,7 @@ // If there is no hard keyboard or there is a hard keyboard currently hidden, // CTRL-1 through CTRL-9 will send F1 through F9 - if ((!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) - && sendFunctionKey(keyCode)) + if ((!hardKeyboard || hardKeyboardHidden) && sendFunctionKey(keyCode)) return true; uchar = keyAsControl(uchar); @@ -305,9 +299,7 @@ if (uchar < 0x80) buffer.write(uchar); else - // TODO write encoding routine that doesn't allocate each time - buffer.write(new String(Character.toChars(uchar)) - .getBytes(encoding)); + sendEncoded(new String(Character.toChars(uchar))); return true; } @@ -332,7 +324,7 @@ } else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) { sendMeta = true; - buffer.write(0x1b); + sendEscape(); } if (sendMeta || sendCtrl) { @@ -357,7 +349,7 @@ return true; } else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) { - buffer.write(0x1b); + sendEscape(); buffer.write(k); return true; } @@ -433,11 +425,11 @@ // look for special chars switch (keyCode) { case KEYCODE_ESCAPE: - buffer.write(0x1b); + sendEscape(); return true; case KeyEvent.KEYCODE_TAB: - buffer.write(0x09); + buffer.keyPressed(vt320.KEY_TAB, ' ', getStateForBuffer()); return true; case KEYCODE_PAGE_DOWN: @@ -472,7 +464,7 @@ return (handleShortcut(v, hwbuttonShortcut)); case KeyEvent.KEYCODE_VOLUME_UP: - // check to see which shortcut the camera button triggers + // check to see which shortcut the volume button triggers hwbuttonShortcut = manager.prefs.getString( PreferenceConstants.VOLUP, PreferenceConstants.HWBUTTON_CTRL); @@ -486,7 +478,7 @@ return (handleShortcut(v, hwbuttonShortcut)); case KeyEvent.KEYCODE_SEARCH: - // check to see which shortcut the camera button triggers + // check to see which shortcut the search button triggers hwbuttonShortcut = manager.prefs.getString( PreferenceConstants.SEARCH, PreferenceConstants.HWBUTTON_ESC); @@ -494,19 +486,17 @@ case KeyEvent.KEYCODE_DEL: if ((metaState & META_ALT_MASK) != 0) { - buffer.keyPressed(vt320.KEY_INSERT, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_INSERT, ' ', getStateForBuffer()); } else { - buffer.keyPressed(vt320.KEY_BACK_SPACE, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_BACK_SPACE, ' ', getStateForBuffer()); } metaState &= ~META_TRANSIENT; return true; case KeyEvent.KEYCODE_ENTER: - buffer.write('\r'); + buffer.keyPressed(vt320.KEY_ENTER, ' ', getStateForBuffer()); metaState &= ~META_TRANSIENT; return true; @@ -517,12 +507,10 @@ } else { if ((metaState & META_ALT_MASK) != 0) { - buffer.keyPressed(vt320.KEY_HOME, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_HOME, ' ', getStateForBuffer()); } else { - buffer.keyPressed(vt320.KEY_LEFT, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_LEFT, ' ', getStateForBuffer()); } metaState &= ~META_TRANSIENT; @@ -538,12 +526,10 @@ } else { if ((metaState & META_ALT_MASK) != 0) { - buffer.keyPressed(vt320.KEY_PAGE_UP, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_PAGE_UP, ' ', getStateForBuffer()); } else { - buffer.keyPressed(vt320.KEY_UP, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_UP, ' ', getStateForBuffer()); } metaState &= ~META_TRANSIENT; @@ -559,12 +545,10 @@ } else { if ((metaState & META_ALT_MASK) != 0) { - buffer.keyPressed(vt320.KEY_PAGE_DOWN, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_PAGE_DOWN, ' ', getStateForBuffer()); } else { - buffer.keyPressed(vt320.KEY_DOWN, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_DOWN, ' ', getStateForBuffer()); } metaState &= ~META_TRANSIENT; @@ -580,12 +564,10 @@ } else { if ((metaState & META_ALT_MASK) != 0) { - buffer.keyPressed(vt320.KEY_END, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_END, ' ', getStateForBuffer()); } else { - buffer.keyPressed(vt320.KEY_RIGHT, ' ', - getStateForBuffer()); + buffer.keyPressed(vt320.KEY_RIGHT, ' ', getStateForBuffer()); } metaState &= ~META_TRANSIENT; @@ -599,22 +581,10 @@ return true; } } - catch (IOException e) { - Log.e(TAG, "Problem while trying to handle an onKey() event", e); - - try { - bridge.transport.flush(); - } - catch (IOException ioe) { - Log.d(TAG, "Our transport was closed, dispatching disconnect event"); - bridge.dispatchDisconnect(false); - } - } catch (NullPointerException npe) { Log.d(TAG, "Input before connection established ignored."); return true; } - return false; } @@ -627,7 +597,7 @@ metaPress(META_CTRL_ON); } else if (PreferenceConstants.HWBUTTON_TAB.equals(shortcut)) { - buffer.write(0x09); + buffer.keyPressed(vt320.KEY_TAB, ' ', getStateForBuffer()); } else if (PreferenceConstants.HWBUTTON_CTRLA_SPACE.equals(shortcut)) { buffer.write(0x01); @@ -638,10 +608,10 @@ } else if (PreferenceConstants.HWBUTTON_ESC.equals(shortcut)) { showMetakeyToast(v, PreferenceConstants.HWBUTTON_ESC); - buffer.write(0x1b); + sendEscape(); } else if (PreferenceConstants.HWBUTTON_ESC_A.equals(shortcut)) { - buffer.write(0x1b); + sendEscape(); buffer.write('a'); } else { @@ -652,13 +622,7 @@ } private void showMetakeyToast(View v, String keyname) { - if (metakeyToast == null) - metakeyToast = Toast.makeText(v.getContext(), keyname, Toast.LENGTH_LONG); - else - metakeyToast.setText(keyname); - - metakeyToast.setGravity(Gravity.TOP | Gravity.RIGHT, 0, 0); - metakeyToast.show(); + Log.d(TAG, keyname); } public int keyAsControl(int key) { @@ -816,7 +780,7 @@ } } - private void metaKeyUp(int code) { + protected void metaKeyUp(int code) { if ((metaState & code) != 0) { metaState &= ~code; bridge.redraw(); @@ -902,9 +866,11 @@ this.encoding = encoding; } - + public Charset getCharset() { + return Charset.forName(encoding); + } - private void ctrlKeySpecial() { + protected void ctrlKeySpecial() { if (selectingForCopy) { if (selectionArea.isSelectingOrigin()) selectionArea.finishSelectingOrigin(); @@ -913,10 +879,6 @@ // copy selected area to clipboard String copiedText = selectionArea.copyFrom(buffer); clipboard.setText(copiedText); - // XXX STOPSHIP -// manager.notifyUser(manager.getString( -// R.string.console_copy_done, -// copiedText.length())); selectingForCopy = false; selectionArea.reset(); } @@ -924,7 +886,7 @@ } else { if ((metaState & META_CTRL_ON) != 0) { - buffer.write(0x1b); + sendEscape(); metaState &= ~META_CTRL_ON; } else @@ -934,7 +896,7 @@ bridge.redraw(); } - private boolean customKeymapAction(View v, int keyCode, KeyEvent event) { + protected boolean customKeymapAction(View v, int keyCode, KeyEvent event) { if (bridge == null || customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_DISABLED)) return false; @@ -964,7 +926,7 @@ // screen (-1) or the Asus Transformer Keyboard Dock. // Treat the HW button as ESC. if (event.getDeviceId() > 0) { - buffer.write(0x1b); + sendEscape(); return true; } } @@ -1058,12 +1020,14 @@ // Samsung Captivate Glide (SGH-i927) if (keyCode == 115) { // .com key = ESC - c = 0x1b; + c = 0x00; + termKey = vt320.KEY_ESCAPE; return true; } else if (keyCode == 116) { // Microphone key = TAB - c = 0x09; + c = 0x00; + termKey = vt320.KEY_TAB; } else if ((metaState & META_ALT_MASK) != 0 && (metaState & META_SHIFT_MASK) != 0) { switch (keyCode) { @@ -1089,11 +1053,13 @@ // Samsung Captivate Glide (SGH-i927) Ice Cream Sandwich (4.0.x) if (keyCode == 226) { // .com key = ESC - c = 0x1b; + c = 0x00; + termKey = vt320.KEY_ESCAPE; } else if (keyCode == 220) { // Microphone key = TAB - c = 0x09; + c = 0x00; + termKey = vt320.KEY_TAB; } else if ((metaState & META_ALT_MASK) != 0 && (metaState & META_SHIFT_MASK) != 0) { switch (keyCode) { @@ -1155,7 +1121,7 @@ return false; } - private boolean fullKeyboard() { + protected boolean fullKeyboard() { if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_FULL) || (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_ASUS_TF))) return true; diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/service/TerminalManager.java --- a/src/com/five_ten_sg/connectbot/service/TerminalManager.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/service/TerminalManager.java Mon Jun 16 08:24:00 2014 -0700 @@ -252,7 +252,7 @@ } public String getEmulation() { - return prefs.getString(PreferenceConstants.EMULATION, "screen"); + return prefs.getString(PreferenceConstants.EMULATION, "xterm-256color"); } public int getScrollback() { diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/service/TerminalMonitor.java diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/transport/AbsTransport.java --- a/src/com/five_ten_sg/connectbot/transport/AbsTransport.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/transport/AbsTransport.java Mon Jun 16 08:24:00 2014 -0700 @@ -24,29 +24,126 @@ import com.five_ten_sg.connectbot.bean.HostBean; import com.five_ten_sg.connectbot.bean.PortForwardBean; import com.five_ten_sg.connectbot.service.TerminalBridge; +import com.five_ten_sg.connectbot.service.TerminalKeyListener; import com.five_ten_sg.connectbot.service.TerminalManager; import android.content.Context; import android.net.Uri; +import android.util.Log; +import de.mud.terminal.vt320; /** * @author Kenny Root * */ public abstract class AbsTransport { - HostBean host; - TerminalBridge bridge; - TerminalManager manager; + protected String TAG; + protected TerminalManager manager; + protected TerminalBridge bridge; + protected HostBean host; + protected vt320 buffer = null; + protected String emulation; + + class vt320Default extends vt320 { + @Override + public void debug(String s) { + Log.d(TAG, s); + } + + // terminal key listener sending to the host + @Override + public void write(byte[] b) { + try { + if (bridge.monitor != null) bridge.monitor.hostData(b); + + AbsTransport.this.write(b); + } + catch (IOException e) { + Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); + } + } + @Override + public void write(int b) { + try { + if (bridge.monitor != null) bridge.monitor.hostData(b); + + AbsTransport.this.write(b); + } + catch (IOException e) { + Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); + } + } - String emulation; + // We don't use telnet sequences. + @Override + public void sendTelnetCommand(byte cmd) { + } + // We don't want remote to resize our window. + @Override + public void setWindowSize(int c, int r) { + } + // play beep noise + @Override + public void beep() { + if ((bridge.parent != null) && (bridge.parent.isShown())) + manager.playBeep(); + else + manager.sendActivityNotification(host); + } + + // test for changed screen contents + @Override + public void testChanged() { + if (bridge.monitor != null) bridge.monitor.testChanged(); + } + // relay socket writing to the screen + // bridge.monitor placement of new characters + @Override + public void putChar(int c, int l, char ch, int attributes) { + if (bridge.monitor != null) bridge.monitor.screenChanged(l, c); + + super.putChar(c, l, ch, attributes); + } + @Override + public void insertChar(int c, int l, char ch, int attributes) { + if (bridge.monitor != null) bridge.monitor.screenChanged(l, l, c, width - 1); + + super.insertChar(c, l, ch, attributes); + } + @Override + public void insertLine(int l, int n, boolean scrollDown) { + if (bridge.monitor != null) { + if (scrollDown) bridge.monitor.screenChanged(l, height - 1, 0, width - 1); + else bridge.monitor.screenChanged(0, l, 0, width - 1); + } + + super.insertLine(l, n, scrollDown); + } + @Override + public void deleteLine(int l) { + if (bridge.monitor != null) bridge.monitor.screenChanged(l, height - 1, 0, width - 1); + + super.deleteLine(l); + } + @Override + public void deleteChar(int c, int l) { + if (bridge.monitor != null) bridge.monitor.screenChanged(l, l, c, width - 1); + + super.deleteChar(c, l); + } + @Override + public void setCursorPosition(int c, int l) { + if (bridge.monitor != null) bridge.monitor.cursorMove(l, c); + + super.setCursorPosition(c, l); + } + + // monitor setField() + + }; + public AbsTransport() {} - public AbsTransport(HostBean host, TerminalBridge bridge, TerminalManager manager) { - this.host = host; - this.bridge = bridge; - this.manager = manager; - } - /** * @return protocol part of the URI */ @@ -58,9 +155,8 @@ * Encode the current transport into a URI that can be passed via intent calls. * @return URI to host */ - public static Uri getUri(String input) { - return null; - } + public abstract Uri getUri(String input); + /** * Causes transport to connect to the target host. After connecting but before a @@ -145,24 +241,27 @@ // do nothing } - public void setEmulation(String emulation) { - this.emulation = emulation; - } - public String getEmulation() { return emulation; } - public void setHost(HostBean host) { - this.host = host; + protected vt320 setupTransportBuffer() { + int scrollback = (host.getWantSession()) ? manager.getScrollback() : 0; + buffer.setBufferSize(scrollback); + buffer.setDisplay(bridge); + return buffer; } - public void setBridge(TerminalBridge bridge) { - this.bridge = bridge; + public vt320 getTransportBuffer() { + buffer = new vt320Default(); + return setupTransportBuffer(); } - public void setManager(TerminalManager manager) { - this.manager = manager; + public void setLinks(TerminalManager manager, TerminalBridge bridge, HostBean host, String emulation) { + this.manager = manager; + this.bridge = bridge; + this.host = host; + this.emulation = emulation; } /** @@ -248,14 +347,14 @@ return false; } - public abstract boolean isConnected(); - public abstract boolean isSessionOpen(); - public abstract boolean isAuthenticated(); /** * @return int default port for protocol */ public abstract int getDefaultPort(); + public abstract boolean isConnected(); + public abstract boolean isSessionOpen(); + public abstract boolean isAuthenticated(); /** * @param username @@ -282,12 +381,26 @@ * @param context context containing the correct resources * @return string that hints at the format for connection */ - public static String getFormatHint(Context context) { - return "???"; + public abstract String getFormatHint(Context context); + + /** + * @return do we use the network + */ + public abstract boolean usesNetwork(); + + /** + * @return do we need a relay object to read from the transport + * and send the data into the vt320 buffer + */ + public boolean needsRelay() { + return true; } /** - * @return + * @return a key listener */ - public abstract boolean usesNetwork(); + public TerminalKeyListener getTerminalKeyListener() { + return new TerminalKeyListener(manager, bridge, buffer, host.getEncoding()); + } + } diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/transport/Local.java --- a/src/com/five_ten_sg/connectbot/transport/Local.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/transport/Local.java Mon Jun 16 08:24:00 2014 -0700 @@ -41,12 +41,10 @@ public class Local extends AbsTransport { private static final String TAG = "ConnectBot.Local"; private static final String PROTOCOL = "local"; - private static final String DEFAULT_URI = "local:#Local"; - private FileDescriptor shellFd; - - private FileInputStream is; + private FileDescriptor shellFd; + private FileInputStream is; private FileOutputStream os; /** @@ -55,37 +53,23 @@ public Local() { } - /** - * @param host - * @param bridge - * @param manager - */ - public Local(HostBean host, TerminalBridge bridge, TerminalManager manager) { - super(host, bridge, manager); - } public static String getProtocolName() { return PROTOCOL; } - @Override - public void close() { - try { - if (os != null) { - os.close(); - os = null; - } + + public Uri getUri(String input) { + Uri uri = Uri.parse(DEFAULT_URI); - if (is != null) { - is.close(); - is = null; - } + if (input != null && input.length() > 0) { + uri = uri.buildUpon().fragment(input).build(); } - catch (IOException e) { - Log.e(TAG, "Couldn't close shell", e); - } + + return uri; } + @Override public void connect() { int[] pids = new int[1]; @@ -115,35 +99,6 @@ bridge.onConnected(); } - @Override - public void flush() throws IOException { - os.flush(); - } - - @Override - public String getDefaultNickname(String username, String hostname, int port) { - return DEFAULT_URI; - } - - @Override - public int getDefaultPort() { - return 0; - } - - @Override - public boolean isConnected() { - return is != null && os != null; - } - - @Override - public boolean isSessionOpen() { - return is != null && os != null; - } - - @Override - public boolean isAuthenticated() { - return isConnected(); - } @Override public boolean willBlock() { @@ -166,16 +121,6 @@ } @Override - public void setDimensions(int columns, int rows, int width, int height) { - try { - Exec.setPtyWindowSize(shellFd, rows, columns, width, height); - } - catch (Exception e) { - Log.e(TAG, "Couldn't resize pty", e); - } - } - - @Override public void write(byte[] buffer) throws IOException { if (os != null) os.write(buffer); @@ -187,14 +132,68 @@ os.write(c); } - public static Uri getUri(String input) { - Uri uri = Uri.parse(DEFAULT_URI); + @Override + public void flush() throws IOException { + os.flush(); + } + + @Override + public void close() { + try { + if (os != null) { + os.close(); + os = null; + } + + if (is != null) { + is.close(); + is = null; + } + } + catch (IOException e) { + Log.e(TAG, "Couldn't close shell", e); + } + } - if (input != null && input.length() > 0) { - uri = uri.buildUpon().fragment(input).build(); + @Override + public void setDimensions(int columns, int rows, int width, int height) { + try { + Exec.setPtyWindowSize(shellFd, rows, columns, width, height); + } + catch (Exception e) { + Log.e(TAG, "Couldn't resize pty", e); } + } - return uri; + @Override + public int getDefaultPort() { + return 0; + } + + @Override + public boolean isConnected() { + return is != null && os != null; + } + + @Override + public boolean isSessionOpen() { + return isConnected(); + } + + @Override + public boolean isAuthenticated() { + return isConnected(); + } + + @Override + public String getDefaultNickname(String username, String hostname, int port) { + return DEFAULT_URI; + } + + @Override + public void getSelectionArgs(Uri uri, Map selection) { + selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); + selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); } @Override @@ -214,19 +213,10 @@ return host; } - @Override - public void getSelectionArgs(Uri uri, Map selection) { - selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); - selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); - } - - public static String getFormatHint(Context context) { + public String getFormatHint(Context context) { return context.getString(R.string.hostpref_nickname_title); } - /* (non-Javadoc) - * @see com.five_ten_sg.connectbot.transport.AbsTransport#usesNetwork() - */ @Override public boolean usesNetwork() { return false; diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/transport/SSH.java --- a/src/com/five_ten_sg/connectbot/transport/SSH.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/transport/SSH.java Mon Jun 16 08:24:00 2014 -0700 @@ -82,18 +82,6 @@ * */ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveCallback, AuthAgentCallback { - public SSH() { - super(); - } - - /** - * @param bridge - * @param db - */ - public SSH(HostBean host, TerminalBridge bridge, TerminalManager manager) { - super(host, bridge, manager); - } - private static final String PROTOCOL = "ssh"; private static final String TAG = "ConnectBot.SSH"; private static final int DEFAULT_PORT = 22; @@ -211,6 +199,60 @@ } + + public SSH() { + super(); + } + + + /** + * @return protocol part of the URI + */ + public static String getProtocolName() { + return PROTOCOL; + } + + + public Uri getUri(String input) { + Matcher matcher = hostmask.matcher(input); + + if (!matcher.matches()) + return null; + + StringBuilder sb = new StringBuilder(); + sb.append(PROTOCOL) + .append("://") + .append(Uri.encode(matcher.group(1))) + .append('@') + .append(matcher.group(2)); + String portString = matcher.group(4); + int port = DEFAULT_PORT; + + if (portString != null) { + try { + port = Integer.parseInt(portString); + + if (port < 1 || port > 65535) { + port = DEFAULT_PORT; + } + } + catch (NumberFormatException nfe) { + // Keep the default port + } + } + + if (port != DEFAULT_PORT) { + sb.append(':') + .append(port); + } + + sb.append("/#") + .append(Uri.encode(input)); + Uri uri = Uri.parse(sb.toString()); + return uri; + } + + private void authenticate() { try { if (connection.authenticateWithNone(host.getUsername())) { @@ -302,6 +344,7 @@ } } + /** * Attempt connection with database row pointed to by cursor. * @param cursor @@ -370,6 +413,7 @@ return tryPublicKey(host.getUsername(), pubkey.getNickname(), pair); } + private boolean tryPublicKey(String username, String keyNickname, KeyPair pair) throws IOException { //bridge.outputLine(String.format("Attempting 'publickey' with key '%s' [%s]...", keyNickname, trileadKey.toString())); boolean success = connection.authenticateWithPublicKey(username, pair); @@ -380,6 +424,7 @@ return success; } + /** * Internal method to request actual PTY terminal once we've finished * authentication. If called before authenticated, it will just fail. @@ -431,6 +476,7 @@ } } + @Override public void connect() { connection = new Connection(host.getHostname(), host.getPort()); @@ -536,31 +582,6 @@ } } - @Override - public void close() { - connected = false; - - if (session != null) { - session.close(); - session = null; - } - - if (connection != null) { - connection.close(); - connection = null; - } - } - - private void onDisconnect() { - close(); - bridge.dispatchDisconnect(false); - } - - @Override - public void flush() throws IOException { - if (stdin != null) - stdin.flush(); - } @Override public boolean willBlock() { @@ -572,6 +593,7 @@ } } + @Override public int read(byte[] buffer, int start, int len) throws IOException { int bytesRead = 0; @@ -601,18 +623,81 @@ return bytesRead; } + @Override public void write(byte[] buffer) throws IOException { if (stdin != null) stdin.write(buffer); } + @Override public void write(int c) throws IOException { if (stdin != null) stdin.write(c); } + + @Override + public void flush() throws IOException { + if (stdin != null) + stdin.flush(); + } + + + public void connectionLost(Throwable reason) { + onDisconnect(); + } + + + private void onDisconnect() { + close(); + bridge.dispatchDisconnect(false); + } + + + @Override + public void close() { + connected = false; + + if (session != null) { + session.close(); + session = null; + } + + if (connection != null) { + connection.close(); + connection = null; + } + } + + + @Override + public void setDimensions(int columns, int rows, int width, int height) { + this.columns = columns; + this.rows = rows; + + if (sessionOpen) { + try { + session.resizePTY(columns, rows, width, height); + } + catch (IOException e) { + Log.e(TAG, "Couldn't send resize PTY packet", e); + } + } + } + + + @Override + public void setOptions(Map options) { + if (options.containsKey("compression")) + compression = Boolean.parseBoolean(options.get("compression")); + + if (options.containsKey("httpproxy")) + httpproxy = options.get("httpproxy"); + } + + @Override public Map getOptions() { Map options = new HashMap(); @@ -624,36 +709,22 @@ return options; } + @Override - public void setOptions(Map options) { - if (options.containsKey("compression")) - compression = Boolean.parseBoolean(options.get("compression")); - - if (options.containsKey("httpproxy")) - httpproxy = options.get("httpproxy"); + public void setCompression(boolean compression) { + this.compression = compression; } - public static String getProtocolName() { - return PROTOCOL; - } @Override - public boolean isSessionOpen() { - return sessionOpen; + public void setHttpproxy(String httpproxy) { + this.httpproxy = httpproxy; } + @Override - public boolean isConnected() { - return connected; - } - - @Override - public boolean isAuthenticated() { - return authenticated; - } - - public void connectionLost(Throwable reason) { - onDisconnect(); + public void setUseAuthAgent(String useAuthAgent) { + this.useAuthAgent = useAuthAgent; } @Override @@ -863,26 +934,31 @@ } } - @Override - public void setDimensions(int columns, int rows, int width, int height) { - this.columns = columns; - this.rows = rows; - - if (sessionOpen) { - try { - session.resizePTY(columns, rows, width, height); - } - catch (IOException e) { - Log.e(TAG, "Couldn't send resize PTY packet", e); - } - } - } @Override public int getDefaultPort() { return DEFAULT_PORT; } + + @Override + public boolean isConnected() { + return connected; + } + + + @Override + public boolean isSessionOpen() { + return sessionOpen; + } + + + @Override + public boolean isAuthenticated() { + return authenticated; + } + + @Override public String getDefaultNickname(String username, String hostname, int port) { if (port == DEFAULT_PORT) { @@ -893,59 +969,21 @@ } } - public static Uri getUri(String input) { - Matcher matcher = hostmask.matcher(input); - - if (!matcher.matches()) - return null; - - StringBuilder sb = new StringBuilder(); - sb.append(PROTOCOL) - .append("://") - .append(Uri.encode(matcher.group(1))) - .append('@') - .append(matcher.group(2)); - String portString = matcher.group(4); - int port = DEFAULT_PORT; - - if (portString != null) { - try { - port = Integer.parseInt(portString); - if (port < 1 || port > 65535) { - port = DEFAULT_PORT; - } - } - catch (NumberFormatException nfe) { - // Keep the default port - } - } + @Override + public void getSelectionArgs(Uri uri, Map selection) { + selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); + selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); + selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); + int port = uri.getPort(); - if (port != DEFAULT_PORT) { - sb.append(':') - .append(port); - } + if (port < 0) + port = DEFAULT_PORT; - sb.append("/#") - .append(Uri.encode(input)); - Uri uri = Uri.parse(sb.toString()); - return uri; + selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); + selection.put(HostDatabase.FIELD_HOST_USERNAME, uri.getUserInfo()); } - /** - * Handle challenges from keyboard-interactive authentication mode. - */ - public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) { - interactiveCanContinue = true; - String[] responses = new String[numPrompts]; - - for (int i = 0; i < numPrompts; i++) { - // request response from user for each prompt - responses[i] = bridge.promptHelper.requestPasswordPrompt(instruction, prompt[i]); - } - - return responses; - } @Override public HostBean createHost(Uri uri) { @@ -972,40 +1010,37 @@ return host; } - @Override - public void getSelectionArgs(Uri uri, Map selection) { - selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); - selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); - selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); - int port = uri.getPort(); - if (port < 0) - port = DEFAULT_PORT; - - selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); - selection.put(HostDatabase.FIELD_HOST_USERNAME, uri.getUserInfo()); - } - - @Override - public void setCompression(boolean compression) { - this.compression = compression; - } - - @Override - public void setHttpproxy(String httpproxy) { - this.httpproxy = httpproxy; - } - - public static String getFormatHint(Context context) { + public String getFormatHint(Context context) { return String.format("%s@%s:%s", context.getString(R.string.format_username), context.getString(R.string.format_hostname), context.getString(R.string.format_port)); } + + /** + * @return do we use the network + */ @Override - public void setUseAuthAgent(String useAuthAgent) { - this.useAuthAgent = useAuthAgent; + public boolean usesNetwork() { + return true; + } + + + /** + * Handle challenges from keyboard-interactive authentication mode. + */ + public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) { + interactiveCanContinue = true; + String[] responses = new String[numPrompts]; + + for (int i = 0; i < numPrompts; i++) { + // request response from user for each prompt + responses[i] = bridge.promptHelper.requestPasswordPrompt(instruction, prompt[i]); + } + + return responses; } public Map retrieveIdentities() { @@ -1103,11 +1138,4 @@ return true; } - /* (non-Javadoc) - * @see com.five_ten_sg.connectbot.transport.AbsTransport#usesNetwork() - */ - @Override - public boolean usesNetwork() { - return true; - } } diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/transport/TN5250.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/five_ten_sg/connectbot/transport/TN5250.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,436 @@ +/* + * 510ConnectBot + * Copyright 2014 Carl Byington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.five_ten_sg.connectbot.transport; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.tn5250j.framework.tn5250.Screen5250; +import org.tn5250j.framework.tn5250.tnvt; + +import com.five_ten_sg.connectbot.R; +import com.five_ten_sg.connectbot.bean.HostBean; +import com.five_ten_sg.connectbot.bean.PortForwardBean; +import com.five_ten_sg.connectbot.service.TerminalBridge; +import com.five_ten_sg.connectbot.service.TerminalKeyListener; +import com.five_ten_sg.connectbot.service.TerminalManager; +import com.five_ten_sg.connectbot.util.HostDatabase; +import com.five_ten_sg.connectbot.util.PreferenceConstants; +import android.content.Context; +import android.net.Uri; +import android.util.Log; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import de.mud.terminal.vt320; + + +/** + * @author Carl Byington + * + */ +public class TN5250 extends AbsTransport { + private static final String PROTOCOL = "tn5250"; + private static final String TAG = "ConnectBot.tn5250"; + private static final int DEFAULT_PORT = 23; + + private Screen5250 screen52; + private tnvt handler = null; + private Socket socket; + private boolean connected = false; + + static final Pattern hostmask; + static { + hostmask = Pattern.compile("^([0-9a-z.-]+)(:(\\d+))?$", Pattern.CASE_INSENSITIVE); + } + + + class vt320x5250 extends vt320 { + private HashMap mnemonics; + + public vt320x5250() { + this(80,24); + } + + public vt320x5250(int width, int height) { + super(width, height); + mnemonics = new HashMap(); + mnemonics.put(KEY_PAUSE , "[attn]"); + mnemonics.put(KEY_F1 , "[pf1]"); + mnemonics.put(KEY_F2 , "[pf2]"); + mnemonics.put(KEY_F3 , "[pf3]"); + mnemonics.put(KEY_F4 , "[pf4]"); + mnemonics.put(KEY_F5 , "[pf5]"); + mnemonics.put(KEY_F6 , "[pf6]"); + mnemonics.put(KEY_F7 , "[pf7]"); + mnemonics.put(KEY_F8 , "[pf8]"); + mnemonics.put(KEY_F9 , "[pf9]"); + mnemonics.put(KEY_F10 , "[pf10]"); + mnemonics.put(KEY_F11 , "[pf11]"); + mnemonics.put(KEY_F12 , "[pf12]"); + mnemonics.put(KEY_UP , "[up]"); + mnemonics.put(KEY_DOWN , "[down]"); + mnemonics.put(KEY_LEFT , "[left]"); + mnemonics.put(KEY_RIGHT , "[right]"); + mnemonics.put(KEY_PAGE_DOWN , "[pgdown]"); + mnemonics.put(KEY_PAGE_UP , "[pgup]"); + mnemonics.put(KEY_INSERT , "[insert]"); + mnemonics.put(KEY_DELETE , "[delete]"); + mnemonics.put(KEY_BACK_SPACE , "[backspace]"); + mnemonics.put(KEY_HOME , "[home]"); + mnemonics.put(KEY_END , "[end]"); + mnemonics.put(KEY_NUM_LOCK , ""); + mnemonics.put(KEY_CAPS_LOCK , ""); + mnemonics.put(KEY_SHIFT , ""); + mnemonics.put(KEY_CONTROL , ""); + mnemonics.put(KEY_ALT , ""); + mnemonics.put(KEY_ENTER , "[enter]"); + mnemonics.put(KEY_NUMPAD0 , "0"); + mnemonics.put(KEY_NUMPAD1 , "1"); + mnemonics.put(KEY_NUMPAD2 , "2"); + mnemonics.put(KEY_NUMPAD3 , "3"); + mnemonics.put(KEY_NUMPAD4 , "4"); + mnemonics.put(KEY_NUMPAD5 , "5"); + mnemonics.put(KEY_NUMPAD6 , "6"); + mnemonics.put(KEY_NUMPAD7 , "7"); + mnemonics.put(KEY_NUMPAD8 , "8"); + mnemonics.put(KEY_NUMPAD9 , "9"); + mnemonics.put(KEY_DECIMAL , "."); + mnemonics.put(KEY_ADD , "+"); + mnemonics.put(KEY_ESCAPE , ""); + mnemonics.put(KEY_TAB , "[tab]"); + } + + @Override + public void debug(String s) { + Log.d(TAG, s); + } + + // monitor injecting a field + @Override + public void setField(int l, int c, char [] d) { + screen52.setField(l, c, d); + } + + // terminal key listener sending to local screen + @Override + public void write(byte[] b) { + if (bridge.monitor != null) bridge.monitor.hostData(b); + screen52.sendKeys(new String(b)); + } + @Override + public void write(int b) { + if (bridge.monitor != null) bridge.monitor.hostData(b); + screen52.sendKeys(new String(new byte[] {(byte)b})); + } + @Override + public void keyPressed(int keyCode, char keyChar, int modifiers) { + if (mnemonics.containsKey(keyCode)) { + String s = mnemonics.get(keyCode); + if (s != "") { + if (bridge.monitor != null) bridge.monitor.hostData(s.getBytes()); + screen52.sendKeys(s); + } + } + } + // 5250 writing to the screen + // test for changed screen contents + @Override + public void testChanged() { + if (bridge.monitor != null) bridge.monitor.testChanged(); + } + @Override + public void putChar(int c, int l, char ch, int attributes) { + if (bridge.monitor != null) bridge.monitor.screenChanged(l, c); + super.putChar(c, l, ch, attributes); + } + @Override + public void setCursorPosition(int c, int l) { + if (bridge.monitor != null) bridge.monitor.cursorMove(l, c); + super.setCursorPosition(c, l); + } + }; + + + public TN5250() { + super(); + } + + + /** + * @return protocol part of the URI + */ + public static String getProtocolName() { + return PROTOCOL; + } + + + /** + * Encode the current transport into a URI that can be passed via intent calls. + * @return URI to host + */ + public Uri getUri(String input) { + Matcher matcher = hostmask.matcher(input); + + if (!matcher.matches()) + return null; + + StringBuilder sb = new StringBuilder(); + sb.append(PROTOCOL) + .append("://") + .append(matcher.group(1)); + String portString = matcher.group(3); + int port = DEFAULT_PORT; + + if (portString != null) { + try { + port = Integer.parseInt(portString); + + if (port < 1 || port > 65535) { + port = DEFAULT_PORT; + } + } + catch (NumberFormatException nfe) { + // Keep the default port + } + } + + if (port != DEFAULT_PORT) { + sb.append(':'); + sb.append(port); + } + + sb.append("/#") + .append(Uri.encode(input)); + Uri uri = Uri.parse(sb.toString()); + return uri; + } + + + /** + * Causes transport to connect to the target host. After connecting but before a + * session is started, must call back to {@link TerminalBridge#onConnected()}. + * After that call a session may be opened. + */ + @Override + public void connect() { + screen52 = new Screen5250(); + handler = new tnvt(screen52, true, false, bridge, manager); + String encryption = host.getEncryption5250(); + if ((encryption == null) || (encryption.length() == 0)) encryption = "NONE"; + handler.setSSLType(encryption); + screen52.setVT(handler); + screen52.setBuffer(buffer); + connected = handler.connect(host.getHostname(), host.getPort(), buffer); + if (connected) bridge.onConnected(); + } + + + /** + * Checks if read() will block. If there are no bytes remaining in + * the underlying transport, return true. + */ + @Override + public boolean willBlock() { + // we don't use a relay thread between the transport and the vt320 buffer + return true; + } + + + /** + * Reads from the transport. Transport must support reading into a byte array + * buffer at the start of offset and a maximum of + * length bytes. If the remote host disconnects, throw an + * {@link IOException}. + * @param buffer byte buffer to store read bytes into + * @param offset where to start writing in the buffer + * @param length maximum number of bytes to read + * @return number of bytes read + * @throws IOException when remote host disconnects + */ + public int read(byte[] buffer, int offset, int length) throws IOException { + // we don't use a relay thread between the transport and the vt320 buffer + return 0; + } + + + /** + * Writes to the transport. If the host is not yet connected, simply return without + * doing anything. An {@link IOException} should be thrown if there is an error after + * connection. + * @param buffer bytes to write to transport + * @throws IOException when there is a problem writing after connection + */ + public void write(byte[] buffer) throws IOException { + } + + + /** + * Writes to the transport. See {@link #write(byte[])} for behavior details. + * @param c character to write to the transport + * @throws IOException when there is a problem writing after connection + */ + public void write(int c) throws IOException { + } + + + /** + * Flushes the write commands to the transport. + * @throws IOException when there is a problem writing after connection + */ + public void flush() throws IOException { + } + + + /** + * Closes the connection to the terminal. + */ + public void close() { + handler.disconnect(); + connected = false; + bridge.dispatchDisconnect(false); + } + + + /** + * Tells the transport what dimensions the display is currently + * @param columns columns of text + * @param rows rows of text + * @param width width in pixels + * @param height height in pixels + */ + @Override + public void setDimensions(int columns, int rows, int width, int height) { + // do nothing + } + + + @Override + public vt320 getTransportBuffer() { + buffer = new vt320x5250(); + return setupTransportBuffer(); + } + + + @Override + public int getDefaultPort() { + return DEFAULT_PORT; + } + + + @Override + public boolean isConnected() { + return connected; + } + + + @Override + public boolean isSessionOpen() { + return connected; + } + + + @Override + public boolean isAuthenticated() { + return connected; + } + + + @Override + public String getDefaultNickname(String username, String hostname, int port) { + if (port == DEFAULT_PORT) { + return String.format("%s", hostname); + } + else { + return String.format("%s:%d", hostname, port); + } + } + + + @Override + public void getSelectionArgs(Uri uri, Map selection) { + selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); + selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); + selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); + int port = uri.getPort(); + + if (port < 0) + port = DEFAULT_PORT; + + selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); + } + + + @Override + public HostBean createHost(Uri uri) { + HostBean host = new HostBean(); + host.setProtocol(PROTOCOL); + host.setHostname(uri.getHost()); + int port = uri.getPort(); + + if (port < 0) + port = DEFAULT_PORT; + + host.setPort(port); + String nickname = uri.getFragment(); + + if (nickname == null || nickname.length() == 0) { + host.setNickname(getDefaultNickname(host.getUsername(), + host.getHostname(), host.getPort())); + } + else { + host.setNickname(uri.getFragment()); + } + + return host; + } + + + public String getFormatHint(Context context) { + return String.format("%s:%s", + context.getString(R.string.format_hostname), + context.getString(R.string.format_port)); + } + + + @Override + public boolean usesNetwork() { + return true; + } + + + @Override + public boolean needsRelay() { + // we don't use a relay thread between the transport and the vt320 buffer + return false; + } + + public TerminalKeyListener getTerminalKeyListener() { + return new TerminalKeyListener(manager, bridge, buffer, host.getEncoding()); + } + +} diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/transport/Telnet.java --- a/src/com/five_ten_sg/connectbot/transport/Telnet.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/transport/Telnet.java Mon Jun 16 08:24:00 2014 -0700 @@ -33,11 +33,14 @@ import com.five_ten_sg.connectbot.service.TerminalBridge; import com.five_ten_sg.connectbot.service.TerminalManager; import com.five_ten_sg.connectbot.util.HostDatabase; + import android.content.Context; import android.net.Uri; import android.util.Log; + import de.mud.telnet.TelnetProtocolHandler; + /** * Telnet transport implementation.
* Original idea from the JTA telnet package (de.mud.telnet) @@ -48,18 +51,15 @@ public class Telnet extends AbsTransport { private static final String TAG = "ConnectBot.Telnet"; private static final String PROTOCOL = "telnet"; - private static final int DEFAULT_PORT = 23; private TelnetProtocolHandler handler; - private Socket socket; - - private InputStream is; - private OutputStream os; - private int width; - private int height; - - private boolean connected = false; + private Socket socket; + private InputStream is; + private OutputStream os; + private int width; + private int height; + private boolean connected = false; static final Pattern hostmask; static { @@ -105,19 +105,50 @@ }; } - /** - * @param host - * @param bridge - * @param manager - */ - public Telnet(HostBean host, TerminalBridge bridge, TerminalManager manager) { - super(host, bridge, manager); - } public static String getProtocolName() { return PROTOCOL; } + + public Uri getUri(String input) { + Matcher matcher = hostmask.matcher(input); + + if (!matcher.matches()) + return null; + + StringBuilder sb = new StringBuilder(); + sb.append(PROTOCOL) + .append("://") + .append(matcher.group(1)); + String portString = matcher.group(3); + int port = DEFAULT_PORT; + + if (portString != null) { + try { + port = Integer.parseInt(portString); + + if (port < 1 || port > 65535) { + port = DEFAULT_PORT; + } + } + catch (NumberFormatException nfe) { + // Keep the default port + } + } + + if (port != DEFAULT_PORT) { + sb.append(':'); + sb.append(port); + } + + sb.append("/#") + .append(Uri.encode(input)); + Uri uri = Uri.parse(sb.toString()); + return uri; + } + + @Override public void connect() { try { @@ -135,44 +166,6 @@ } } - @Override - public void close() { - connected = false; - - if (socket != null) - try { - socket.close(); - socket = null; - } - catch (IOException e) { - Log.d(TAG, "Error closing telnet socket.", e); - } - } - - @Override - public void flush() throws IOException { - os.flush(); - } - - @Override - public int getDefaultPort() { - return DEFAULT_PORT; - } - - @Override - public boolean isConnected() { - return connected; - } - - @Override - public boolean isSessionOpen() { - return connected; - } - - @Override - public boolean isAuthenticated() { - return isConnected(); - } @Override public boolean willBlock() { @@ -184,6 +177,7 @@ } } + @Override public int read(byte[] buffer, int start, int len) throws IOException { /* process all already read bytes */ @@ -220,6 +214,7 @@ return n; } + @Override public void write(byte[] buffer) throws IOException { try { @@ -231,6 +226,7 @@ } } + @Override public void write(int c) throws IOException { try { @@ -242,6 +238,28 @@ } } + + @Override + public void flush() throws IOException { + os.flush(); + } + + + @Override + public void close() { + connected = false; + + if (socket != null) + try { + socket.close(); + socket = null; + } + catch (IOException e) { + Log.d(TAG, "Error closing telnet socket.", e); + } + } + + @Override public void setDimensions(int columns, int rows, int width, int height) { try { @@ -252,6 +270,28 @@ } } + + @Override + public int getDefaultPort() { + return DEFAULT_PORT; + } + + @Override + public boolean isConnected() { + return connected; + } + + @Override + public boolean isSessionOpen() { + return isConnected(); + } + + @Override + public boolean isAuthenticated() { + return isConnected(); + } + + @Override public String getDefaultNickname(String username, String hostname, int port) { if (port == DEFAULT_PORT) { @@ -262,43 +302,21 @@ } } - public static Uri getUri(String input) { - Matcher matcher = hostmask.matcher(input); - - if (!matcher.matches()) - return null; - - StringBuilder sb = new StringBuilder(); - sb.append(PROTOCOL) - .append("://") - .append(matcher.group(1)); - String portString = matcher.group(3); - int port = DEFAULT_PORT; - - if (portString != null) { - try { - port = Integer.parseInt(portString); - if (port < 1 || port > 65535) { - port = DEFAULT_PORT; - } - } - catch (NumberFormatException nfe) { - // Keep the default port - } - } + @Override + public void getSelectionArgs(Uri uri, Map selection) { + selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); + selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); + selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); + int port = uri.getPort(); - if (port != DEFAULT_PORT) { - sb.append(':'); - sb.append(port); - } + if (port < 0) + port = DEFAULT_PORT; - sb.append("/#") - .append(Uri.encode(input)); - Uri uri = Uri.parse(sb.toString()); - return uri; + selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); } + @Override public HostBean createHost(Uri uri) { HostBean host = new HostBean(); @@ -323,28 +341,13 @@ return host; } - @Override - public void getSelectionArgs(Uri uri, Map selection) { - selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); - selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); - selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); - int port = uri.getPort(); - if (port < 0) - port = DEFAULT_PORT; - - selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); - } - - public static String getFormatHint(Context context) { + public String getFormatHint(Context context) { return String.format("%s:%s", context.getString(R.string.format_hostname), context.getString(R.string.format_port)); } - /* (non-Javadoc) - * @see com.five_ten_sg.connectbot.transport.AbsTransport#usesNetwork() - */ @Override public boolean usesNetwork() { return true; diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/transport/TransportFactory.java --- a/src/com/five_ten_sg/connectbot/transport/TransportFactory.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/transport/TransportFactory.java Mon Jun 16 08:24:00 2014 -0700 @@ -36,6 +36,7 @@ private static String[] transportNames = { SSH.getProtocolName(), + TN5250.getProtocolName(), Telnet.getProtocolName(), Local.getProtocolName(), }; @@ -48,6 +49,9 @@ if (SSH.getProtocolName().equals(protocol)) { return new SSH(); } + else if (TN5250.getProtocolName().equals(protocol)) { + return new TN5250(); + } else if (Telnet.getProtocolName().equals(protocol)) { return new Telnet(); } @@ -59,21 +63,13 @@ } } - public static Uri getUri(String scheme, String input) { + public static Uri getUri(String protocol, String input) { Log.d("TransportFactory", String.format( - "Attempting to discover URI for scheme=%s on input=%s", scheme, - input)); - - if (SSH.getProtocolName().equals(scheme)) - return SSH.getUri(input); - else if (Telnet.getProtocolName().equals(scheme)) - return Telnet.getUri(input); - else if (Local.getProtocolName().equals(scheme)) { - Log.d("TransportFactory", "Got to the local parsing area"); - return Local.getUri(input); - } - else - return null; + "Attempting to discover URI for protocol=%s on input=%s", + protocol, input)); + AbsTransport t = getTransport(protocol); + if (t == null) return null; + return t.getUri(input); } public static String[] getTransportNames() { @@ -88,13 +84,9 @@ } public static boolean canForwardPorts(String protocol) { - // TODO uh, make this have less knowledge about its children - if (SSH.getProtocolName().equals(protocol)) { - return true; - } - else { - return false; - } + AbsTransport t = getTransport(protocol); + if (t == null) return false; + return t.canForwardPorts(); } /** @@ -103,18 +95,9 @@ * @return expanded format hint */ public static String getFormatHint(String protocol, Context context) { - if (SSH.getProtocolName().equals(protocol)) { - return SSH.getFormatHint(context); - } - else if (Telnet.getProtocolName().equals(protocol)) { - return Telnet.getFormatHint(context); - } - else if (Local.getProtocolName().equals(protocol)) { - return Local.getFormatHint(context); - } - else { - return AbsTransport.getFormatHint(context); - } + AbsTransport t = getTransport(protocol); + if (t == null) return "???"; + return t.getFormatHint(context); } /** diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/util/Colors.java --- a/src/com/five_ten_sg/connectbot/util/Colors.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/util/Colors.java Mon Jun 16 08:24:00 2014 -0700 @@ -23,22 +23,22 @@ */ public class Colors { public final static Integer[] defaults = new Integer[] { - 0xff000000, // black - 0xffcc0000, // red - 0xff00cc00, // green - 0xffcccc00, // brown - 0xff0000cc, // blue - 0xffcc00cc, // purple - 0xff00cccc, // cyan - 0xffcccccc, // light grey - 0xff444444, // dark grey - 0xffff4444, // light red - 0xff44ff44, // light green - 0xffffff44, // yellow - 0xff4444ff, // light blue - 0xffff44ff, // light purple - 0xff44ffff, // light cyan - 0xffffffff, // white + 0xff000000, // black // 0 + 0xffcc0000, // red // 1 + 0xff00cc00, // green // 2 + 0xffcccc00, // brown // 3 + 0xff0000cc, // blue // 4 + 0xffcc00cc, // purple // 5 + 0xff00cccc, // cyan // 6 + 0xffcccccc, // light grey // 7 + 0xff444444, // dark grey // 8 + 0xffff4444, // light red // 9 + 0xff44ff44, // light green // a + 0xffffff44, // yellow // b + 0xff4444ff, // light blue // c + 0xffff44ff, // light purple // d + 0xff44ffff, // light cyan // e + 0xffffffff, // white // f 0xff000000, 0xff00005f, 0xff000087, 0xff0000af, 0xff0000d7, 0xff0000ff, 0xff005f00, 0xff005f5f, 0xff005f87, 0xff005faf, 0xff005fd7, 0xff005fff, 0xff008700, 0xff00875f, 0xff008787, diff -r b3d0d806cbe2 -r 01d939969b10 src/com/five_ten_sg/connectbot/util/HostDatabase.java --- a/src/com/five_ten_sg/connectbot/util/HostDatabase.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/com/five_ten_sg/connectbot/util/HostDatabase.java Mon Jun 16 08:24:00 2014 -0700 @@ -46,7 +46,7 @@ public final static String TAG = "ConnectBot.HostDatabase"; public final static String DB_NAME = "hosts"; - public final static int DB_VERSION = 25; + public final static int DB_VERSION = 26; public final static String TABLE_HOSTS = "hosts"; public final static String FIELD_HOST_NICKNAME = "nickname"; @@ -73,6 +73,8 @@ public final static String FIELD_HOST_X11HOST = "x11host"; public final static String FIELD_HOST_X11PORT = "x11port"; public final static String FIELD_HOST_MONITOR = "monitor"; + public final static String FIELD_HOST_EMULATION = "emulation"; + public final static String FIELD_HOST_ENCRYPTION5250 = "encryption5250"; public final static String TABLE_PORTFORWARDS = "portforwards"; public final static String FIELD_PORTFORWARD_HOSTID = "hostid"; @@ -179,7 +181,9 @@ + FIELD_HOST_WANTX11FORWARD + " TEXT DEFAULT '" + Boolean.toString(false) + "', " + FIELD_HOST_X11HOST + " TEXT DEFAULT '" + X11HOST_DEFAULT + "', " + FIELD_HOST_X11PORT + " INTEGER DEFAULT " + X11PORT_DEFAULT + ", " - + FIELD_HOST_MONITOR + " TEXT)"); + + FIELD_HOST_MONITOR + " TEXT, " + + FIELD_HOST_EMULATION + " TEXT, " + + FIELD_HOST_ENCRYPTION5250 + " TEXT)"); db.execSQL("CREATE TABLE " + TABLE_PORTFORWARDS + " (_id INTEGER PRIMARY KEY, " + FIELD_PORTFORWARD_HOSTID + " INTEGER, " @@ -290,6 +294,12 @@ case 24: db.execSQL("ALTER TABLE " + TABLE_HOSTS + " ADD COLUMN " + FIELD_HOST_MONITOR + " TEXT"); + + case 25: + db.execSQL("ALTER TABLE " + TABLE_HOSTS + + " ADD COLUMN " + FIELD_HOST_EMULATION + " TEXT"); + db.execSQL("ALTER TABLE " + TABLE_HOSTS + + " ADD COLUMN " + FIELD_HOST_ENCRYPTION5250 + " TEXT"); } } @@ -403,7 +413,9 @@ COL_WANTX11FORWARD = c.getColumnIndexOrThrow(FIELD_HOST_WANTX11FORWARD), COL_X11HOST = c.getColumnIndexOrThrow(FIELD_HOST_X11HOST), COL_X11PORT = c.getColumnIndexOrThrow(FIELD_HOST_X11PORT), - COL_MONITOR = c.getColumnIndexOrThrow(FIELD_HOST_MONITOR); + COL_MONITOR = c.getColumnIndexOrThrow(FIELD_HOST_MONITOR), + COL_EMULATION = c.getColumnIndexOrThrow(FIELD_HOST_EMULATION), + COL_ENCRYPTION5250 = c.getColumnIndexOrThrow(FIELD_HOST_ENCRYPTION5250); while (c.moveToNext()) { HostBean host = new HostBean(); @@ -430,6 +442,8 @@ host.setX11Host(c.getString(COL_X11HOST)); host.setX11Port(c.getInt(COL_X11PORT)); host.setMonitor(c.getString(COL_MONITOR)); + host.setHostEmulation(c.getString(COL_EMULATION)); + host.setEncryption5250(c.getString(COL_ENCRYPTION5250)); hosts.add(host); } diff -r b3d0d806cbe2 -r 01d939969b10 src/de/mud/terminal/VDUBuffer.java --- a/src/de/mud/terminal/VDUBuffer.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/de/mud/terminal/VDUBuffer.java Mon Jun 16 08:24:00 2014 -0700 @@ -1,7 +1,7 @@ /* * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". * - * (c) Matthias L. Jugel, Marcus Mei�ner 1996-2005. All Rights Reserved. + * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved. * * Please visit http://javatelnet.org/ for updates and contact. * @@ -37,8 +37,8 @@ */ public class VDUBuffer { - /** The current version id tag */ - public final static String ID = "$Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $"; + /** a generic display that should redraw on demand */ + protected VDUDisplay display; /** Enable debug messages. */ public final static int debug = 0; @@ -99,11 +99,11 @@ /** how much to left shift the background color */ public final static int COLOR_BG_SHIFT = 14; /** color mask */ - public final static int COLOR = 0x7fffe0; /* 0000 0000 0111 1111 1111 1111 1110 0000 */ + public final static int COLOR = 0x7fffe0; /* 0000 0000 0111 1111 1111 1111 1110 0000 */ /** foreground color mask */ - public final static int COLOR_FG = 0x3fe0; /* 0000 0000 0000 0000 0011 1111 1110 0000 */ + public final static int COLOR_FG = 0x003fe0; /* 0000 0000 0000 0000 0011 1111 1110 0000 */ /** background color mask */ - public final static int COLOR_BG = 0x7fc000; /* 0000 0000 0111 1111 1100 0000 0000 0000 */ + public final static int COLOR_BG = 0x7fc000; /* 0000 0000 0111 1111 1100 0000 0000 0000 */ /** * Create a new video display buffer with the passed width and height in @@ -862,9 +862,6 @@ // return value; // } - /** a generic display that should redraw on demand */ - protected VDUDisplay display; - public void setDisplay(VDUDisplay display) { this.display = display; } diff -r b3d0d806cbe2 -r 01d939969b10 src/de/mud/terminal/vt320.java --- a/src/de/mud/terminal/vt320.java Tue Jun 03 08:48:14 2014 -0700 +++ b/src/de/mud/terminal/vt320.java Mon Jun 16 08:24:00 2014 -0700 @@ -39,12 +39,6 @@ */ public abstract class vt320 extends VDUBuffer implements VDUInput { - /** The current version id tag.

- * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $ - * - */ - public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $"; - /** the debug level */ private final static int debug = 0; private StringBuilder debugStr; @@ -72,12 +66,27 @@ } /** + * inject field contents as if typed + */ + public void setField(int l, int c, char [] d) { + // ignore line and column, just send the bytes to the host. + int n = d.length; + byte [] b = new byte [n]; + for (int i=0; i> clazzes = new ArrayList>(); + + + private BuiltInCodePageFactory() { + register(); + } + + public static synchronized final BuiltInCodePageFactory getInstance() { + if (singleton == null) { + singleton = new BuiltInCodePageFactory(); + } + return singleton; + } + + private void register() { + clazzes.add(CCSID37.class); + clazzes.add(CCSID273.class); + clazzes.add(CCSID277.class); + clazzes.add(CCSID278.class); + clazzes.add(CCSID280.class); + clazzes.add(CCSID284.class); + clazzes.add(CCSID285.class); + clazzes.add(CCSID297.class); + clazzes.add(CCSID424.class); + clazzes.add(CCSID500.class); + clazzes.add(CCSID870.class); + clazzes.add(CCSID871.class); + clazzes.add(CCSID875.class); + clazzes.add(CCSID1025.class); + clazzes.add(CCSID1026.class); + clazzes.add(CCSID1112.class); + clazzes.add(CCSID1140.class); + clazzes.add(CCSID1141.class); + clazzes.add(CCSID1147.class); + clazzes.add(CCSID1148.class); + } + + /** + * @return unsorted list of available code pages + */ + public String[] getAvailableCodePages() { + HashSet cpset = new HashSet(); + for (Class clazz : clazzes) { + final ICodepageConverter converter = getConverterFromClassName(clazz); + if (converter != null) { + cpset.add(converter.getName()); + } + } + return cpset.toArray(new String[cpset.size()]); + } + + /** + * @param encoding + * @return an {@link ICodePage} object OR null, of not found + */ + public ICodePage getCodePage(String encoding) { + for (Class clazz : clazzes) { + final ICodepageConverter converter = getConverterFromClassName(clazz); + if (converter != null && converter.getName().equals(encoding)) { + return converter; + } + } + return null; + } + + /** + * Lazy loading converters takes time, + * but doesn't happen so often and saves memory. + * + * @param clazz {@link ICodepageConverter} + * @return + */ + private ICodepageConverter getConverterFromClassName(Class clazz) { + try { + final Constructor constructor = clazz.getConstructor(new Class[0]); + final ICodepageConverter converter = (ICodepageConverter) constructor.newInstance(); + converter.init(); + return converter; + } catch (Exception e) { + Log.e(TAG,"Couldn't load code page converter class:" + clazz.getCanonicalName(), e); + return null; + } + } + +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/CharMappings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/CharMappings.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,85 @@ +/** + * Title: CharMappings.java + * Copyright: Copyright (c) 2001,2002,2003 + * Company: + * @author Kenneth J. Pouncey + * rewritten by LDC, WVL, Luc + * @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.encoding; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * Character Mappings for EBCDIC to ASCII and ASCII to EBCDIC translations + */ +public class CharMappings { + + public static final String DFT_ENC = "37"; + public static final int NATIVE_CP = 0; + public static final int TOOLBOX_CP = 1; + + private static final HashMap map = new HashMap(); + + public static String[] getAvailableCodePages() { + Set cpset = new HashSet(); // no double entries + for (String cp : BuiltInCodePageFactory.getInstance().getAvailableCodePages()) { + cpset.add(cp); + } + for (String cp : ToolboxCodePageFactory.getInstance().getAvailableCodePages()) { + cpset.add(cp); + } + String[] cparray = cpset.toArray(new String[cpset.size()]); + Arrays.sort(cparray); + return cparray; + } + + public static ICodePage getCodePage(String encoding) { + if (map.containsKey(encoding)) { + return map.get(encoding); + } + + ICodePage cp = BuiltInCodePageFactory.getInstance().getCodePage(encoding); + if (cp != null) { + map.put(encoding, cp); + return cp; + } + + cp = ToolboxCodePageFactory.getInstance().getCodePage(encoding); + if (cp != null) { + map.put(encoding, cp); + return cp; + } + + cp = JavaCodePageFactory.getCodePage(encoding); + if (cp != null) { + map.put(encoding, cp); + return cp; + } + + // unsupported codepage ==> return default + return BuiltInCodePageFactory.getInstance().getCodePage(DFT_ENC); + } + +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/ICodePage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/ICodePage.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,22 @@ +package org.tn5250j.encoding; + +public interface ICodePage { + + /** + * Convert a single byte (or maybe more bytes which representing one character) to a Unicode character. + * + * @param index + * @return + */ + public abstract char ebcdic2uni(int index); + + /** + * Convert a Unicode character in it's byte representation. + * Therefore, only 8bit codepages are supported. + * + * @param index + * @return + */ + public abstract byte uni2ebcdic(char index); + +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/JavaCodePageFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/JavaCodePageFactory.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,94 @@ +/** + * Title: JavaCodePage + * Copyright: Copyright (c) 2001, 2002, 2003 + * Company: + * @author LDC, WVL, Luc, master_jaf + * @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.encoding; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/* package */ class JavaCodePageFactory extends AbstractCodePage { + + private final CharsetEncoder encoder; + private final CharsetDecoder decoder; + + /* package */ JavaCodePageFactory(String encoding, CharsetEncoder encoder, CharsetDecoder decoder) { + super(encoding); + this.encoder = encoder; + this.decoder = decoder; + } + + /* (non-Javadoc) + * @see org.tn5250j.encoding.CodePage#ebcdic2uni(int) + */ + @Override + public char ebcdic2uni(int codepoint) { + try { + final ByteBuffer in = ByteBuffer.wrap(new byte[] { (byte) codepoint }); + final CharBuffer out = this.decoder.decode(in); + return out.get(0); + } catch (Exception cce) { + return ' '; + } + } + + /* (non-Javadoc) + * @see org.tn5250j.encoding.CodePage#uni2ebcdic(char) + */ + @Override + public byte uni2ebcdic(char character) { + try { + final CharBuffer in = CharBuffer.wrap(new char[] {character}); + final ByteBuffer out = this.encoder.encode(in); + return out.get(0); + } catch (Exception cce) { + return 0x0; + } + } + + /** + * @param encoding + * @return A new {@link CodePage} object OR null, if not available. + */ + /* package */ static ICodePage getCodePage(final String encoding) { + CharsetDecoder dec = null; + CharsetEncoder enc = null; + try { + final Charset cs = java.nio.charset.Charset.forName(encoding); + dec = cs.newDecoder(); + enc = cs.newEncoder(); + } catch (Exception e) { + enc = null; + dec = null; + } + if ((enc != null) && (dec != null)) { + return new JavaCodePageFactory(encoding, enc, dec); + } + return null; + } + +} \ No newline at end of file diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/ToolboxCodePageFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/ToolboxCodePageFactory.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,156 @@ +/** + * Title: ToolboxCodePage + * Copyright: Copyright (c) 2001, 2002, 2003 + * Company: + * @author Kenneth J. Pouncey + * rewritten by LDC, WVL, Luc + * @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.encoding; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import android.util.Log; + + +class ToolboxCodePageFactory { + private static final String TAG = "ToolboxCodePageFactory"; + private final static String[] CODEPAGES = { "Big5", "Cp037", "Cp273", "Cp277", "Cp278", + "Cp280", "Cp284", "Cp285", "Cp297", "Cp420", "Cp424", "Cp437", + "Cp500", "Cp737", "Cp775", "Cp838", "Cp850", "Cp852", "Cp855", + "Cp856", "Cp857", "Cp858", "Cp860", "Cp861", "Cp862", "Cp863", + "Cp864", "Cp865", "Cp866", "Cp868", "Cp869", "Cp870", + "Cp871", "Cp874", "Cp875", "Cp918", "Cp921", "Cp922", + "Cp923", // IBM Latin-9. + "Cp930", "Cp933", "Cp935", "Cp937", "Cp939", "Cp942", "Cp943", + "Cp948", "Cp949", "Cp950", "Cp964", "Cp970", "Cp1006", "Cp1025", + "Cp1026", "Cp1046", "Cp1097", "Cp1098", "Cp1112", "Cp1122", + "Cp1123", "Cp1124", "Cp1140", "Cp1141", "Cp1142", "Cp1143", + "Cp1144", "Cp1145", "Cp1146", "Cp1147", "Cp1148", "Cp1149", + "Cp1252", "Cp1250", "Cp1251", "Cp1253", "Cp1254", "Cp1255", + "Cp1256", "Cp1257", "Cp1258", "Cp1381", "Cp1383", "Cp33722" }; + + private static final String CONVERTER_NAME = "com.ibm.as400.access.CharConverter"; + private static final String TOBYTES_NAME = "stringToByteArray"; + private static final String TOSTRING_NAME = "byteArrayToString"; + + private static ToolboxCodePageFactory singleton; + + + + private ToolboxCodePageFactory() { + /* private for singleton */ + } + + public static synchronized ToolboxCodePageFactory getInstance() { + if (singleton == null) { + singleton = new ToolboxCodePageFactory(); + } + return singleton; + } + + /** + * @return + */ + public String[] getAvailableCodePages() { + try { + final ClassLoader loader = getClassLoader(); + Class.forName(CONVERTER_NAME, false, loader); + return CODEPAGES; + } catch (Exception e) { + Log.i(TAG,"Couldn't locate JT400 Toolbox in classpath. Charset converters can't be used."); + return new String[0]; + } + } + + /** + * @param encoding + * @return + */ + public ICodePage getCodePage(String encoding) { + try { + ClassLoader loader = getClassLoader(); + Class conv_class = Class.forName(CONVERTER_NAME, true, loader); + Constructor conv_constructor = conv_class.getConstructor(new Class[] { String.class }); + Method toBytes_method = conv_class.getMethod(TOBYTES_NAME, new Class[] { String.class }); + Method toString_method = conv_class.getMethod(TOSTRING_NAME, new Class[] { byte[].class }); + Object convobj = conv_constructor.newInstance(new Object[] { encoding }); + return new ToolboxConverterProxy(convobj, toBytes_method, toString_method); + } catch (Exception e) { + Log.w(TAG,"Can't load charset converter from JT400 Toolbox for code page " + encoding, e); + return null; + } + } + + private static final ClassLoader getClassLoader() { + ClassLoader loader = ToolboxCodePageFactory.class.getClassLoader(); + if (loader == null) { + loader = ClassLoader.getSystemClassLoader(); + } + return loader; + } + + private static class ToolboxConverterProxy implements ICodePage { + + private final Object converter; + private final Method tobytesMethod; + private final Method tostringMethod; + + private ToolboxConverterProxy(Object converterObject, Method tobytesMethod, Method tostringMethod) { + super(); + this.converter = converterObject; + this.tobytesMethod = tobytesMethod; + this.tostringMethod = tostringMethod; + } + + @Override + public char ebcdic2uni(int index) { + Object result; + try { + result = tostringMethod.invoke(converter, new Object[] { new byte[] { (byte) (index & 0xFF) } }); + } catch (Throwable t) { + result = null; + } + + if (result == null) + return 0x00; + + return ((String) result).charAt(0); + } + + @Override + public byte uni2ebcdic(char index) { + Object result; + try { + result = tobytesMethod.invoke(converter, new Object[] { new String(new char[] { index }) }); + } catch (Throwable t) { + result = null; + } + + if (result == null) + return 0x00; + + return ((byte[]) result)[0]; + } + } + +} \ No newline at end of file diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1025.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1025.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1025<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1025.jsp + */ +public final class CCSID1025 extends CodepageConverterAdapter { + + public final static String NAME = "1025"; + public final static String DESCR = "Cyrillic Multilingual"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u0452', + '\u0453', '\u0451', '\u0454', '\u0455', '\u0456', '\u0457', + '\u0458', '[', '.', '<', '(', '+', '!', '&', '\u0459', '\u045A', + '\u045B', '\u045C', '\u045E', '\u045F', '\u042A', '\u2116', + '\u0402', ']', '$', '*', ')', ';', '^', '-', '/', '\u0403', + '\u0401', '\u0404', '\u0405', '\u0406', '\u0407', '\u0408', + '\u0409', '|', ',', '%', '_', '>', '?', '\u040A', '\u040B', + '\u040C', '\u00AD', '\u040E', '\u040F', '\u044E', '\u0430', + '\u0431', '`', ':', '#', '@', '\'', '=', '"', '\u0446', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u0434', '\u0435', '\u0444', + '\u0433', '\u0445', '\u0438', '\u0439', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', '\u043A', '\u043B', '\u043C', '\u043D', + '\u043E', '\u043F', '\u044F', '~', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '\u0440', '\u0441', '\u0442', '\u0443', '\u0436', + '\u0432', '\u044C', '\u044B', '\u0437', '\u0448', '\u044D', + '\u0449', '\u0447', '\u044A', '\u042E', '\u0410', '\u0411', + '\u0426', '\u0414', '\u0415', '\u0424', '\u0413', '{', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', '\u0425', '\u0418', '\u0419', + '\u041A', '\u041B', '\u041C', '}', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', '\u041D', '\u041E', '\u041F', '\u042F', '\u0420', + '\u0421', '\\', '\u00A7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '\u0422', '\u0423', '\u0416', '\u0412', '\u042C', '\u042B', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '\u0417', '\u0428', + '\u042D', '\u0429', '\u0427', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1026.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1026.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1026<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1026.jsp + */ +public final class CCSID1026 extends CodepageConverterAdapter { + + public final static String NAME = "1026"; + public final static String DESCR = "Turkey Latin 5"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '{', '\u00F1', + '\u00C7', '.', '<', '(', '+', '!', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', + '\u00DF', '\u011E', '\u0130', '*', ')', ';', '^', '-', '/', + '\u00C2', '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', '[', + '\u00D1', '\u015F', ',', '%', '_', '>', '?', '\u00F8', '\u00C9', + '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', + '\u00CC', '\u0131', ':', '\u00D6', '\u015E', '\'', '=', '\u00DC', + '\u00D8', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', + '\u00BB', '}', '`', '\u00A6', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '\u00E6', + '\u00B8', '\u00C6', '\u00A4', '\u00B5', '\u00F6', 's', 't', 'u', + 'v', 'w', 'x', 'y', 'z', '\u00A1', '\u00BF', ']', '$', '@', + '\u00AE', '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', + '\u00AF', '\u00A8', '\u00B4', '\u00D7', '\u00E7', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u00F4', '~', '\u00F2', + '\u00F3', '\u00F5', '\u011F', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '\u00B9', '\u00FB', '\\', '\u00F9', '\u00FA', '\u00FF', + '\u00FC', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '\u00B2', '\u00D4', '#', '\u00D2', '\u00D3', '\u00D5', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '"', + '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1112.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1112.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1112<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1112.jsp + */ +public final class CCSID1112 extends CodepageConverterAdapter { + + public final static String NAME = "1112"; + public final static String DESCR = "Baltic, Multilingual"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u0161', + '\u00E4', '\u0105', '\u012F', '\u016B', '\u00E5', '\u0113', + '\u017E', '\u00A2', '.', '<', '(', '+', '|', '&', '\u00E9', + '\u0119', '\u0117', '\u010D', '\u0173', '\u201E', '\u201C', + '\u0123', '\u00DF', '!', '$', '*', ')', ';', '\u00AC', '-', '/', + '\u0160', '\u00C4', '\u0104', '\u012E', '\u016A', '\u00C5', + '\u0112', '\u017D', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', + '\u00C9', '\u0118', '\u0116', '\u010C', '\u0172', '\u012A', + '\u013B', '\u0122', '`', ':', '#', '@', '\'', '=', '"', '\u00D8', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', + '\u0101', '\u017C', '\u0144', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u0156', '\u0157', '\u00E6', + '\u0137', '\u00C6', '\u00A4', '\u00B5', '~', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '\u201D', '\u017A', '\u0100', '\u017B', + '\u0143', '\u00AE', '^', '\u00A3', '\u012B', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '[', ']', + '\u0179', '\u0136', '\u013C', '\u00D7', '{', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u014D', '\u00F6', '\u0146', + '\u00F3', '\u00F5', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', '\u00B9', '\u0107', '\u00FC', '\u0142', '\u015B', '\u2019', + '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u014C', '\u00D6', '\u0145', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u0106', '\u00DC', + '\u0141', '\u015A', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1140.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1140.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1140<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1140.jsp + */ +public final class CCSID1140 extends CodepageConverterAdapter { + + public final static String NAME = "1140"; + public final static String DESCR = "ECECP: USA, Canada, Netherlands, Portugal, Brazil, Australia, New Zealand"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00F1', '\u00A2', '.', '<', '(', '+', '|', '&', '\u00E9', + '\u00EA', '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', + '\u00EC', '\u00DF', '!', '$', '*', ')', ';', '\u00AC', '-', '/', + '\u00C2', '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', + '\u00C7', '\u00D1', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', + '\u00C9', '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', + '\u00CF', '\u00CC', '`', ':', '#', '@', '\'', '=', '"', '\u00D8', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', + '\u00F0', '\u00FD', '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '\u00E6', + '\u00B8', '\u00C6', '\u20AC', '\u00B5', '~', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', + '\u00DE', '\u00AE', '^', '\u00A3', '\u00A5', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '[', ']', + '\u00AF', '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', + '\u00F3', '\u00F5', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', + '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1141.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1141.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1141<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1141.jsp + */ +public final class CCSID1141 extends CodepageConverterAdapter { + + public final static String NAME = "1141"; + public final static String DESCR = "ECECP: Austria, Germany"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '{', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', '\u00F1', + '\u00C4', '.', '<', '(', '+', '!', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', '~', + '\u00DC', '$', '*', ')', ';', '^', '-', '/', '\u00C2', '[', + '\u00C0', '\u00C1', '\u00C3', '\u00C5', '\u00C7', '\u00D1', + '\u00F6', ',', '%', '_', '>', '?', '\u00F8', '\u00C9', '\u00CA', + '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '`', + ':', '#', '\u00A7', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', + '\u20AC', '\u00B5', '\u00DF', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', + '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', '@', '\u00B6', + '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', '\u00AF', '\u00A8', + '\u00B4', '\u00D7', '\u00E4', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '\u00AD', '\u00F4', '\u00A6', '\u00F2', '\u00F3', + '\u00F5', '\u00FC', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '}', '\u00F9', '\u00FA', '\u00FF', '\u00D6', + '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\\', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', ']', '\u00D9', + '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1147.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1147.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1147<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1147.jsp + */ +public final class CCSID1147 extends CodepageConverterAdapter { + + public final static String NAME = "1147"; + public final static String DESCR = "ECECP: France"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '@', '\u00E1', '\u00E3', '\u00E5', '\\', '\u00F1', + '\u00B0', '.', '<', '(', '+', '!', '&', '{', '\u00EA', '\u00EB', + '}', '\u00ED', '\u00EE', '\u00EF', '\u00EC', '\u00DF', '\u00A7', + '$', '*', ')', ';', '^', '-', '/', '\u00C2', '\u00C4', '\u00C0', + '\u00C1', '\u00C3', '\u00C5', '\u00C7', '\u00D1', '\u00F9', ',', + '%', '_', '>', '?', '\u00F8', '\u00C9', '\u00CA', '\u00CB', + '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '\u00B5', ':', + '\u00A3', '\u00E0', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '[', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', '\u20AC', + '`', '\u00A8', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u00A1', + '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', '\u00A2', '#', + '\u00A5', '\u00B7', '\u00A9', ']', '\u00B6', '\u00BC', '\u00BD', + '\u00BE', '\u00AC', '|', '\u00AF', '~', '\u00B4', '\u00D7', + '\u00E9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '\u00AD', + '\u00F4', '\u00F6', '\u00F2', '\u00F3', '\u00F5', '\u00E8', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', '\u00B9', '\u00FB', + '\u00FC', '\u00A6', '\u00FA', '\u00FF', '\u00E7', '\u00F7', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', '\u00D4', '\u00D6', + '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', '\u00D9', '\u00DA', + '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID1148.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID1148.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 1148<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid1148.jsp + */ +public final class CCSID1148 extends CodepageConverterAdapter { + + public final static String NAME = "1148"; + public final static String DESCR = "ECECP: International 1"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00F1', '[', '.', '<', '(', '+', '!', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', + '\u00DF', ']', '$', '*', ')', ';', '^', '-', '/', '\u00C2', + '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', '\u00C7', + '\u00D1', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', '\u00C9', + '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', + '\u00CC', '`', ':', '#', '@', '\'', '=', '"', '\u00D8', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', + '\u00FD', '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', + '\u00C6', '\u20AC', '\u00B5', '~', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', + '\u00AE', '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', + '\u00AF', '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', + '\u00F3', '\u00F5', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', + '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID273.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID273.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,97 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 273<->Unicode. + * + * + * 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.encoding.builtin; + + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid273.jsp + */ +public final class CCSID273 extends CodepageConverterAdapter { + + public final static String NAME = "273"; + public final static String DESCR = "CECP: Austria, Germany"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '{', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', '\u00F1', + '\u00C4', '.', '<', '(', '+', '!', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', '~', + '\u00DC', '$', '*', ')', ';', '^', '-', '/', '\u00C2', '[', + '\u00C0', '\u00C1', '\u00C3', '\u00C5', '\u00C7', '\u00D1', + '\u00F6', ',', '%', '_', '>', '?', '\u00F8', '\u00C9', '\u00CA', + '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '`', + ':', '#', '\u00A7', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', + '\u00A4', '\u00B5', '\u00DF', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', + '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', '@', '\u00B6', + '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', '\u00AF', '\u00A8', + '\u00B4', '\u00D7', '\u00E4', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '\u00AD', '\u00F4', '\u00A6', '\u00F2', '\u00F3', + '\u00F5', '\u00FC', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '}', '\u00F9', '\u00FA', '\u00FF', '\u00D6', + '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\\', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', ']', '\u00D9', + '\u00DA', '\u009F', }; + + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID277.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID277.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 277<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid277.jsp + */ +public final class CCSID277 extends CodepageConverterAdapter { + + public final static String NAME = "277"; + public final static String DESCR = "CECP: Denmark, Norway"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '}', '\u00E7', '\u00F1', + '#', '.', '<', '(', '+', '!', '&', '\u00E9', '\u00EA', '\u00EB', + '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', '\u00DF', + '\u00A4', '\u00C5', '*', ')', ';', '^', '-', '/', '\u00C2', + '\u00C4', '\u00C0', '\u00C1', '\u00C3', '$', '\u00C7', '\u00D1', + '\u00F8', ',', '%', '_', '>', '?', '\u00A6', '\u00C9', '\u00CA', + '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '`', + ':', '\u00C6', '\u00D8', '\'', '=', '"', '@', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', '\u00AA', '\u00BA', '{', '\u00B8', '[', ']', '\u00B5', + '\u00FC', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u00A1', + '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', '\u00A2', + '\u00A3', '\u00A5', '\u00B7', '\u00A9', '\u00A7', '\u00B6', + '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', '\u00AF', '\u00A8', + '\u00B4', '\u00D7', '\u00E6', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', '\u00F3', + '\u00F5', '\u00E5', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '~', '\u00F9', '\u00FA', '\u00FF', '\\', + '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID278.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID278.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 278<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid278.jsp + */ +public final class CCSID278 extends CodepageConverterAdapter { + + public final static String NAME = "278"; + public final static String DESCR = "CECP: Finland, Sweden"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '{', '\u00E0', '\u00E1', '\u00E3', '}', '\u00E7', '\u00F1', + '\u00A7', '.', '<', '(', '+', '!', '&', '`', '\u00EA', '\u00EB', + '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', '\u00DF', + '\u00A4', '\u00C5', '*', ')', ';', '^', '-', '/', '\u00C2', '#', + '\u00C0', '\u00C1', '\u00C3', '$', '\u00C7', '\u00D1', '\u00F6', + ',', '%', '_', '>', '?', '\u00F8', '\\', '\u00CA', '\u00CB', + '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '\u00E9', ':', + '\u00C4', '\u00D6', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', ']', + '\u00B5', '\u00FC', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', + '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', '[', '\u00B6', + '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', '\u00AF', '\u00A8', + '\u00B4', '\u00D7', '\u00E4', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '\u00AD', '\u00F4', '\u00A6', '\u00F2', '\u00F3', + '\u00F5', '\u00E5', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '~', '\u00F9', '\u00FA', '\u00FF', '\u00C9', + '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '@', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F' }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID280.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID280.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 280<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid280.jsp + */ +public final class CCSID280 extends CodepageConverterAdapter { + + public final static String NAME = "280"; + public final static String DESCR = "CECP: Italy"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '{', '\u00E1', '\u00E3', '\u00E5', '\\', '\u00F1', + '\u00B0', '.', '<', '(', '+', '!', '&', ']', '\u00EA', '\u00EB', + '}', '\u00ED', '\u00EE', '\u00EF', '~', '\u00DF', '\u00E9', '$', + '*', ')', ';', '^', '-', '/', '\u00C2', '\u00C4', '\u00C0', + '\u00C1', '\u00C3', '\u00C5', '\u00C7', '\u00D1', '\u00F2', ',', + '%', '_', '>', '?', '\u00F8', '\u00C9', '\u00CA', '\u00CB', + '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '\u00F9', ':', + '\u00A3', '\u00A7', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '[', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', '\u00A4', + '\u00B5', '\u00EC', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', + '\u00A2', '#', '\u00A5', '\u00B7', '\u00A9', '@', '\u00B6', + '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', '\u00AF', '\u00A8', + '\u00B4', '\u00D7', '\u00E0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00A6', '\u00F3', + '\u00F5', '\u00E8', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '\u00FC', '`', '\u00FA', '\u00FF', '\u00E7', + '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F' }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID284.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID284.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 284<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid284.jsp + */ +public final class CCSID284 extends CodepageConverterAdapter { + + public final static String NAME = "284"; + public final static String DESCR = "CECP: Spain, Latin America (Spanish)"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00A6', '[', '.', '<', '(', '+', '|', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', + '\u00DF', ']', '$', '*', ')', ';', '\u00AC', '-', '/', '\u00C2', + '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', '\u00C7', '#', + '\u00F1', ',', '%', '_', '>', '?', '\u00F8', '\u00C9', '\u00CA', + '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '`', + ':', '\u00D1', '@', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', + '\u00A4', '\u00B5', '\u00A8', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', + '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', '\u00A7', + '\u00B6', '\u00BC', '\u00BD', '\u00BE', '^', '!', '\u00AF', '~', + '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', '\u00F3', '\u00F5', + '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', '\u00B9', + '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', '\\', '\u00F7', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', '\u00D4', + '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', '3', '4', + '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', '\u00D9', + '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID285.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID285.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 285<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid285.jsp + */ +public final class CCSID285 extends CodepageConverterAdapter { + + public final static String NAME = "285"; + public final static String DESCR = "CECP: United Kingdom"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00F1', '$', '.', '<', '(', '+', '|', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', + '\u00DF', '!', '\u00A3', '*', ')', ';', '\u00AC', '-', '/', + '\u00C2', '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', + '\u00C7', '\u00D1', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', + '\u00C9', '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', + '\u00CF', '\u00CC', '`', ':', '#', '@', '\'', '=', '"', '\u00D8', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', + '\u00F0', '\u00FD', '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '\u00E6', + '\u00B8', '\u00C6', '\u00A4', '\u00B5', '\u00AF', 's', 't', 'u', + 'v', 'w', 'x', 'y', 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', + '\u00DE', '\u00AE', '\u00A2', '[', '\u00A5', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '^', ']', '~', + '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', '\u00F3', + '\u00F5', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', '\\', + '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID297.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID297.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 297<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid297.jsp + */ +public final class CCSID297 extends CodepageConverterAdapter { + + public final static String NAME = "297"; + public final static String DESCR = "CECP: France"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '@', '\u00E1', '\u00E3', '\u00E5', '\\', '\u00F1', + '\u00B0', '.', '<', '(', '+', '!', '&', '{', '\u00EA', '\u00EB', + '}', '\u00ED', '\u00EE', '\u00EF', '\u00EC', '\u00DF', '\u00A7', + '$', '*', ')', ';', '^', '-', '/', '\u00C2', '\u00C4', '\u00C0', + '\u00C1', '\u00C3', '\u00C5', '\u00C7', '\u00D1', '\u00F9', ',', + '%', '_', '>', '?', '\u00F8', '\u00C9', '\u00CA', '\u00CB', + '\u00C8', '\u00CD', '\u00CE', '\u00CF', '\u00CC', '\u00B5', ':', + '\u00A3', '\u00E0', '\'', '=', '"', '\u00D8', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', '\u00FD', + '\u00FE', '\u00B1', '[', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', '\u00C6', '\u00A4', + '`', '\u00A8', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u00A1', + '\u00BF', '\u00D0', '\u00DD', '\u00DE', '\u00AE', '\u00A2', '#', + '\u00A5', '\u00B7', '\u00A9', ']', '\u00B6', '\u00BC', '\u00BD', + '\u00BE', '\u00AC', '|', '\u00AF', '~', '\u00B4', '\u00D7', + '\u00E9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '\u00AD', + '\u00F4', '\u00F6', '\u00F2', '\u00F3', '\u00F5', '\u00E8', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', '\u00B9', '\u00FB', + '\u00FC', '\u00A6', '\u00FA', '\u00FF', '\u00E7', '\u00F7', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', '\u00D4', '\u00D6', + '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', '\u00D9', '\u00DA', + '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID37.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID37.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,98 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 37<->Unicode. + * + * + * 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.encoding.builtin; + + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid37.jsp + */ +public final class CCSID37 extends CodepageConverterAdapter { + + public final static String NAME = "37"; + public final static String DESCR = "CECP: USA, Canada (ESA*), Netherlands, Portugal, Brazil, Australia, New Zealand"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00F1', '\u00A2', '.', '<', '(', '+', '|', '&', '\u00E9', + '\u00EA', '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', + '\u00EC', '\u00DF', '!', '$', '*', ')', ';', '\u00AC', '-', '/', + '\u00C2', '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', + '\u00C7', '\u00D1', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', + '\u00C9', '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', + '\u00CF', '\u00CC', '`', ':', '#', '@', '\'', '=', '"', '\u00D8', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', + '\u00F0', '\u00FD', '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '\u00E6', + '\u00B8', '\u00C6', '\u00A4', '\u00B5', '~', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', + '\u00DE', '\u00AE', '^', '\u00A3', '\u00A5', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '[', ']', + '\u00AF', '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', + '\u00F3', '\u00F5', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', + '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F', }; + + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } + +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID424.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID424.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 424<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid424.jsp + */ +public final class CCSID424 extends CodepageConverterAdapter { + + public final static String NAME = "424"; + public final static String DESCR = "Hebrew"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u05D0', '\u05D1', + '\u05D2', '\u05D3', '\u05D4', '\u05D5', '\u05D6', '\u05D7', + '\u05D8', '\u00A2', '.', '<', '(', '+', '|', '&', '\u05D9', + '\u05DA', '\u05DB', '\u05DC', '\u05DD', '\u05DE', '\u05DF', + '\u05E0', '\u05E1', '!', '$', '*', ')', ';', '\u00AC', '-', '/', + '\u05E2', '\u05E3', '\u05E4', '\u05E5', '\u05E6', '\u05E7', + '\u05E8', '\u05E9', '\u00A6', ',', '%', '_', '>', '?', '\u001A', + '\u05EA', '\u001A', '\u001A', '\u00A0', '\u001A', '\u001A', + '\u001A', '\u2017', '`', ':', '#', '@', '\'', '=', '"', '\u001A', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', + '\u001A', '\u001A', '\u001A', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u001A', '\u001A', '\u20AC', + '\u00B8', '\u20AA', '\u00A4', '\u00B5', '~', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '\u001A', '\u001A', '\u001A', '\u001A', + '\u001A', '\u00AE', '^', '\u00A3', '\u00A5', '\u2022', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '[', ']', + '\u203E', '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u001A', '\u001A', '\u001A', + '\u001A', '\u001A', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', '\u00B9', '\u202D', '\u202E', '\u202C', '\u001A', '\u001A', + '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u001A', '\u001A', '\u001A', '\u001A', '\u001A', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u202A', '\u202B', + '\u200E', '\u200F', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID500.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID500.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 500<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid500.jsp + */ +public final class CCSID500 extends CodepageConverterAdapter { + + public final static String NAME = "500"; + public final static String DESCR = "CECP: Belgium, Canada (AS/400*), Switzerland, International Latin-1"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00F1', '[', '.', '<', '(', '+', '!', '&', '\u00E9', '\u00EA', + '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', '\u00EC', + '\u00DF', ']', '$', '*', ')', ';', '^', '-', '/', '\u00C2', + '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', '\u00C7', + '\u00D1', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', '\u00C9', + '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', '\u00CF', + '\u00CC', '`', ':', '#', '@', '\'', '=', '"', '\u00D8', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', '\u00BB', '\u00F0', + '\u00FD', '\u00FE', '\u00B1', '\u00B0', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '\u00E6', '\u00B8', + '\u00C6', '\u00A4', '\u00B5', '~', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '\u00A1', '\u00BF', '\u00D0', '\u00DD', '\u00DE', + '\u00AE', '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', + '\u00A7', '\u00B6', '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', + '\u00AF', '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u00F4', '\u00F6', '\u00F2', + '\u00F3', '\u00F5', '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', + '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00B2', + '\u00D4', '\u00D6', '\u00D2', '\u00D3', '\u00D5', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', '\u00DC', + '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID870.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID870.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 870<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid870.jsp + */ +public final class CCSID870 extends CodepageConverterAdapter { + + public final static String NAME = "870"; + public final static String DESCR = "Latin 2 - EBCDIC Multilingual"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u0163', '\u00E1', '\u0103', '\u010D', '\u00E7', + '\u0107', '[', '.', '<', '(', '+', '!', '&', '\u00E9', '\u0119', + '\u00EB', '\u016F', '\u00ED', '\u00EE', '\u013E', '\u013A', + '\u00DF', ']', '$', '*', ')', ';', '^', '-', '/', '\u00C2', + '\u00C4', '\u02DD', '\u00C1', '\u0102', '\u010C', '\u00C7', + '\u0106', '|', ',', '%', '_', '>', '?', '\u02C7', '\u00C9', + '\u0118', '\u00CB', '\u016E', '\u00CD', '\u00CE', '\u013D', + '\u0139', '`', ':', '#', '@', '\'', '=', '"', '\u02D8', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u015B', '\u0148', '\u0111', + '\u00FD', '\u0159', '\u015F', '\u00B0', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', '\u0142', '\u0144', '\u0161', '\u00B8', + '\u02DB', '\u00A4', '\u0105', '~', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '\u015A', '\u0147', '\u0110', '\u00DD', '\u0158', + '\u015E', '\u02D9', '\u0104', '\u017C', '\u0162', '\u017B', + '\u00A7', '\u017E', '\u017A', '\u017D', '\u0179', '\u0141', + '\u0143', '\u0160', '\u00A8', '\u00B4', '\u00D7', '{', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u00F4', '\u00F6', + '\u0155', '\u00F3', '\u0151', '}', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', '\u011A', '\u0171', '\u00FC', '\u0165', '\u00FA', + '\u011B', '\\', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '\u010F', '\u00D4', '\u00D6', '\u0154', '\u00D3', '\u0150', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '\u010E', '\u0170', + '\u00DC', '\u0164', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID871.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID871.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 871<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid871.jsp + */ +public final class CCSID871 extends CodepageConverterAdapter { + + public final static String NAME = "871"; + public final static String DESCR = "CECP: Iceland"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u00A0', '\u00E2', + '\u00E4', '\u00E0', '\u00E1', '\u00E3', '\u00E5', '\u00E7', + '\u00F1', '\u00DE', '.', '<', '(', '+', '!', '&', '\u00E9', + '\u00EA', '\u00EB', '\u00E8', '\u00ED', '\u00EE', '\u00EF', + '\u00EC', '\u00DF', '\u00C6', '$', '*', ')', ';', '\u00D6', '-', + '/', '\u00C2', '\u00C4', '\u00C0', '\u00C1', '\u00C3', '\u00C5', + '\u00C7', '\u00D1', '\u00A6', ',', '%', '_', '>', '?', '\u00F8', + '\u00C9', '\u00CA', '\u00CB', '\u00C8', '\u00CD', '\u00CE', + '\u00CF', '\u00CC', '\u00F0', ':', '#', '\u00D0', '\'', '=', '"', + '\u00D8', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u00AB', + '\u00BB', '`', '\u00FD', '{', '\u00B1', '\u00B0', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', '\u00AA', '\u00BA', '}', '\u00B8', + ']', '\u00A4', '\u00B5', '\u00F6', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '\u00A1', '\u00BF', '@', '\u00DD', '[', '\u00AE', + '\u00A2', '\u00A3', '\u00A5', '\u00B7', '\u00A9', '\u00A7', + '\u00B6', '\u00BC', '\u00BD', '\u00BE', '\u00AC', '|', '\u00AF', + '\u00A8', '\\', '\u00D7', '\u00FE', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', '\u00AD', '\u00F4', '~', '\u00F2', '\u00F3', + '\u00F5', '\u00E6', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '\u00B9', '\u00FB', '\u00FC', '\u00F9', '\u00FA', '\u00FF', + '\u00B4', '\u00F7', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '\u00B2', '\u00D4', '^', '\u00D2', '\u00D3', '\u00D5', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00DB', + '\u00DC', '\u00D9', '\u00DA', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CCSID875.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CCSID875.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * Title: tn5250J + * Copyright: Copyright (c) 2001,2009 + * Company: + * @author: master_jaf + * + * Description: + * Alternative (extended) implementation of a codepage converter CCSID 875<->Unicode. + * + * + * 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.encoding.builtin; + +/** + * @author master_jaf + * @see http://www-01.ibm.com/software/globalization/ccsid/ccsid875.jsp + */ +public final class CCSID875 extends CodepageConverterAdapter { + + public final static String NAME = "875"; + public final static String DESCR = "Greek"; + + /* + * Char maps manually extracted from JTOpen v6.4. Because char maps can't be + * covered by any license, this should legal. + */ + private static final char[] codepage = { '\u0000', '\u0001', '\u0002', + '\u0003', '\u009C', '\t', '\u0086', '\u007F', '\u0097', '\u008D', + '\u008E', '\u000B', '\f', '\r', '\u000E', '\u000F', '\u0010', + '\u0011', '\u0012', '\u0013', '\u009D', '\u0085', '\u0008', + '\u0087', '\u0018', '\u0019', '\u0092', '\u008F', '\u001C', + '\u001D', '\u001E', '\u001F', '\u0080', '\u0081', '\u0082', + '\u0083', '\u0084', '\n', '\u0017', '\u001B', '\u0088', '\u0089', + '\u008A', '\u008B', '\u008C', '\u0005', '\u0006', '\u0007', + '\u0090', '\u0091', '\u0016', '\u0093', '\u0094', '\u0095', + '\u0096', '\u0004', '\u0098', '\u0099', '\u009A', '\u009B', + '\u0014', '\u0015', '\u009E', '\u001A', ' ', '\u0391', '\u0392', + '\u0393', '\u0394', '\u0395', '\u0396', '\u0397', '\u0398', + '\u0399', '[', '.', '<', '(', '+', '!', '&', '\u039A', '\u039B', + '\u039C', '\u039D', '\u039E', '\u039F', '\u03A0', '\u03A1', + '\u03A3', ']', '$', '*', ')', ';', '^', '-', '/', '\u03A4', + '\u03A5', '\u03A6', '\u03A7', '\u03A8', '\u03A9', '\u03AA', + '\u03AB', '|', ',', '%', '_', '>', '?', '\u00A8', '\u0386', + '\u0388', '\u0389', '\u00A0', '\u038A', '\u038C', '\u038E', + '\u038F', '`', ':', '#', '@', '\'', '=', '"', '\u0385', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', '\u03B1', '\u03B2', '\u03B3', + '\u03B4', '\u03B5', '\u03B6', '\u00B0', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', '\u03B7', '\u03B8', '\u03B9', '\u03BA', + '\u03BB', '\u03BC', '\u00B4', '~', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '\u03BD', '\u03BE', '\u03BF', '\u03C0', '\u03C1', + '\u03C3', '\u00A3', '\u03AC', '\u03AD', '\u03AE', '\u03CA', + '\u03AF', '\u03CC', '\u03CD', '\u03CB', '\u03CE', '\u03C2', + '\u03C4', '\u03C5', '\u03C6', '\u03C7', '\u03C8', '{', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', '\u00AD', '\u03C9', '\u0390', + '\u03B0', '\u2018', '\u2015', '}', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', '\u00B1', '\u00BD', '\u001A', '\u0387', '\u2019', + '\u00A6', '\\', '\u001A', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '\u00B2', '\u00A7', '\u001A', '\u001A', '\u00AB', '\u00AC', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '\u00B3', '\u00A9', + '\u001A', '\u001A', '\u00BB', '\u009F', }; + + public String getName() { + return NAME; + } + + public String getDescription() { + return DESCR; + } + + public String getEncoding() { + return NAME; + } + + @Override + protected char[] getCodePage() { + return codepage; + } +} diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/encoding/builtin/CodepageConverterAdapter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/encoding/builtin/CodepageConverterAdapter.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,82 @@ +/** + * $Id$ + * + * 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.encoding.builtin; + +import java.util.Arrays; + +/** + * Adapter class for converters using 8bit codepages. + * + * @author master_jaf + */ +public abstract class CodepageConverterAdapter implements ICodepageConverter { + + private char[] codepage = null; + private int[] reverse_codepage = null; + + /* (non-Javadoc) + * @see org.tn5250j.cp.ICodepageConverter#init() + */ + public ICodepageConverter init() { + codepage = getCodePage(); + + int size = 0; + for (int i=0; iTitle: ScreenOIAListener

+ *

Description: Main interface to draw the graphical image of the 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.event; + +import org.tn5250j.framework.tn5250.ScreenOIA; + +public interface ScreenOIAListener { + + public static final int OIA_CHANGED_INSERT_MODE = 0; + public static final int OIA_CHANGED_KEYS_BUFFERED = 1; + public static final int OIA_CHANGED_KEYBOARD_LOCKED = 2; + public static final int OIA_CHANGED_MESSAGELIGHT = 3; + public static final int OIA_CHANGED_SCRIPT = 4; + public static final int OIA_CHANGED_BELL = 5; + public static final int OIA_CHANGED_CLEAR_SCREEN = 6; + public static final int OIA_CHANGED_INPUTINHIBITED = 7; + public static final int OIA_CHANGED_CURSOR = 8; + + + public void onOIAChanged(ScreenOIA oia, int change); + +} diff -r b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,358 @@ +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 android.util.Log; + +import de.mud.terminal.vt320; + + +public class DataStreamProducer implements Runnable { + private static final String TAG = "DataStreamProducer"; + private tnvt vt; + private BufferedInputStream bin; + private vt320 buffer; + private ByteArrayOutputStream baosin; + private Thread me; + private byte[] saveStream; + private final BlockingQueue dsq; + private byte[] abyte2; + private FileOutputStream fw; + private BufferedOutputStream dw; + private boolean dumpBytes = false; + private ICodePage codePage; + + + + public DataStreamProducer(tnvt vt, BufferedInputStream bin, vt320 buffer, BlockingQueue queue, byte[] init) { + this.bin = bin; + this.vt = vt; + this.buffer = buffer; + 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.w(TAG," DataStreamProducer thread interrupted and stopping " + se.getMessage()); + done = true; + } + + catch (IOException ioe) { + + Log.w(TAG,ioe.getMessage()); + if (me.isInterrupted()) + done = true; + + } + catch (Exception ex) { + + Log.w(TAG,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.d(TAG,"partial stream found"); + } + + if (j > size) { + saveStream = new byte[abyte0.length]; + System.arraycopy(abyte0, 0, saveStream, 0, abyte0.length); + Log.d(TAG,"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.w(TAG,"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) { + if (bin.available() == 0) buffer.testChanged(); + 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.w(TAG,fnfe.getMessage()); + } + + } + else { + + try { + + if (dw != null) + dw.close(); + if (fw != null) + fw.close(); + dw = null; + fw = null; + codePage = null; + } + catch(IOException ioe) { + + Log.w(TAG,ioe.getMessage()); + } + } + + Log.i(TAG,"Data Stream output is now " + dumpBytes); + } + + public void dump (byte[] abyte0) { + try { + + Log.i(TAG,"\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.w(TAG,"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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 android.util.Log; + + + +public class KeyStrokenizer { + private static final String TAG = "KeyStrokenizer"; + private StringBuffer keyStrokes; + private StringBuffer sb; + private int index; + private int length; + + + + public KeyStrokenizer() { + + sb = new StringBuffer(); + setKeyStrokes(null); + } + + public void setKeyStrokes (String strokes) { + + if (strokes != null) { + keyStrokes.setLength(0); + Log.d(TAG,"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.w(TAG," 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.w(TAG, + " mnemonic key was incomplete ending not found :2 " + + "at position " + index); + } + c = keyStrokes.charAt(index); + } + } + } + } + break; + + case ']': + index++; + if(index >= length) { + Log.w(TAG, + " 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.w(TAG, + " 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.d(TAG,"next "+ keyStrokes); + + return s; + } + + public String getUnprocessedKeyStroked() { + if(index >= length) { + return null; + } + return keyStrokes.substring(index); + } + +} \ No newline at end of file diff -r b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,3933 @@ +/** + * 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 android.util.Log; +import de.mud.terminal.vt320; +import de.mud.terminal.VDUBuffer; + + +public class Screen5250 { + private static final String TAG = "Screen5250"; + private ScreenFields screenFields; + private int lastAttr; + private int lastPos; + private int lenScreen; + private KeyStrokenizer strokenizer; + private tnvt sessionVT; + private vt320 buffer; // used to draw the screen + 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; + + // Operator Information Area + private ScreenOIA oia; + + // screen planes + protected ScreenPlanes planes; + + //Added by Barry + private StringBuffer keybuf; + + + + public Screen5250() { + + //Added by Barry + this.keybuf = new StringBuffer(); + + try { + jbInit(); + } catch (Exception ex) { + Log.w(TAG,"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.d(TAG,"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) { + Log.d(TAG,"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.i(TAG,"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.i(TAG,"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.d(TAG,"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.w(TAG,pe.getMessage() + " at " + + pe.getErrorOffset()); + } + } + sb.setLength(0); + m++; + } + Log.d(TAG,"" + 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) != '/') { + Log.d(TAG," Hotspot clicked!!! we will send characters " + + planes.getChar(pos) + " " + planes.getChar(pos+1)); + aid.append(planes.getChar(pos)); + aid.append(planes.getChar(pos + 1)); + } else { + Log.d(TAG," 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)); + } + sessionVT.showURL(eb.toString()); + // take out the log statement when we are sure it is + // working + Log.i(TAG,"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; + } + + public void setBuffer(vt320 buffer) { + this.buffer = buffer; + } + + /** + * 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(); + } + } + + //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 + * + */ + public synchronized void sendKeys(String text) { + + 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; + else 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.i(TAG," 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(); + + 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 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(); + } + + } + + /** + * 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 content of the field at (l,c) to d + * if l == -1, set the current field contents to d + */ + public void setField(int l, int c, char [] d) { + ScreenField cf; + if (l >= 0) { + int position = l * numCols + c; + isInField(position, true); + } + if ((d != null) && (d.length > 0)) { + cf = screenFields.getCurrentField(); + cf.setString(new String(d)); + lastPos = cf.getStartPos(); + } + updateDirty(); + } + + /** + * 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.w(TAG," 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.i(TAG,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(); + + } + + /** + * 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(); + + } + + 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(); + } + + 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); + + } + + 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(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(); + } + + /** + * repaint part of the screen + * + */ + private void fireScreenChanged(int startRow, int startCol, int endRow, int endCol) { + int [] vt320color = {0x0, // black + 0x4, // blue + 0x2, // green + 0x6, // cyan + 0x1, // red + 0x5, // magenta/purple + 0xb, // yellow + 0x7, // light gray/white + 0x8, // dark gray + 0xc, // light blue + 0xa, // light green + 0xe, // light cyan + 0x9, // light red + 0xd, // light magenta/purple + 0x3, // brown + 0xf // bright white + }; + for (int r = startRow; r <= endRow; r++) { + for (int c = startCol; c <= endCol; c++) { + int p = getPos(r,c); + char ch = planes.getChar(p); + char co = planes.getCharColor(p); + char at = planes.getCharExtended(p); + if (ch < ' ') ch = ' '; + int bg = vt320color[(int)((co >> 8) & 0x0f)]; + int fg = vt320color[(int)(co & 0x0f)]; + int ul = (int)(at & EXTENDED_5250_UNDERLINE); + int nd = (int)(at & EXTENDED_5250_NON_DSP); + int vt_attr = (fg << VDUBuffer.COLOR_FG_SHIFT) + (bg << VDUBuffer.COLOR_BG_SHIFT); + if (ul > 0) vt_attr |= VDUBuffer.UNDERLINE; + if (nd > 0) vt_attr |= VDUBuffer.INVISIBLE; + buffer.putChar(c, r, ch, vt_attr); + } + } + buffer.redrawPassthru(); + dirtyScreen.setBounds(lenScreen,0,0,0); + } + + /** + * repaint the dirty part of the screen + * + */ + private synchronized void fireScreenChanged() { + if (dirtyScreen.x > dirtyScreen.y) { + Log.i(TAG," x < y " + dirtyScreen); + return; + } + fireScreenChanged(getRow(dirtyScreen.x), getCol(dirtyScreen.x), + getRow(dirtyScreen.y), getCol(dirtyScreen.y)); + + } + + /** + * update the cursor position + * + */ + private synchronized void fireCursorChanged() { + int l = getRow(lastPos); + int c = getCol(lastPos); + buffer.setCursorPosition(c,l); + } + + /** + * update the screen size. + */ + private void fireScreenSizeChanged() { + buffer.setScreenSize(numCols, numRows, true); + } + + /** + * This method does a complete refresh of the screen. + */ + public final void updateScreen() { + repaintScreen(); + setCursorActive(false); + setCursorActive(true); + } + + /** + * 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,607 @@ +/** + * 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; + cursorProg = 0; + fieldId = 0; + length = len; + startPos = (row * s.getColumns()) + col; + 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; + } + + public int getStartPos() { + return startPos; + } + + 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 were 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,824 @@ +/** + * 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; + +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 char getCharColor(int pos) { + return screenColor[pos]; + } + + protected final int getCharAttr(int pos) { + return screenAttr[pos]; + } + + protected final char getCharExtended(int pos) { + return screenExtended[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; + } + + 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 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 android.util.Log; + + +/** + * + * Write To Display Structured Field: + * + * This module will parse the structured field information for enhanced + * emulation mode. + * + */ +public class WTDSFParser { + private static final String TAG = "WTDSFParser"; + private Screen5250 screen52; + private tnvt vt; + private ICodePage codePage; + int pos; + byte[] segment; + int length; + boolean error; + boolean guiStructsExist; + + + + 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.i(TAG,"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.d(TAG, + " orientation " + Integer.toBinaryString(orientation) + + " mAttr " + mAttr + + " cAttr " + cAttr + + " Header/Footer " + hfBuffer); + screen52.writeWindowTitle(lastPos, + rows, + cols, + orientation, + mAttr, + cAttr, + hfBuffer); + break; + default: + Log.w(TAG,"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.i(TAG,"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.i(TAG," 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.d(TAG," 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.w(TAG," 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 b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,2650 @@ +/** + * 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 android.content.Intent; +import android.net.Uri; +import android.util.Log; + +import com.five_ten_sg.connectbot.R; +import com.five_ten_sg.connectbot.service.TerminalBridge; +import com.five_ten_sg.connectbot.service.TerminalManager; +import de.mud.terminal.vt320; + +import org.tn5250j.TN5250jConstants; +import org.tn5250j.encoding.CharMappings; +import org.tn5250j.encoding.ICodePage; +import org.tn5250j.framework.transport.SocketConnector; + + +public final class tnvt implements Runnable { + private static final String TAG = "tnvt"; + // 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; + public BufferedInputStream bin; + public 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 boolean cursorOn = false; + private String hostname = ""; + 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 TerminalBridge bridge; + private TerminalManager manager; + + + + /** + * @param screen52 + * @param enhanced + * @param support132 + * @param bridge + * @param manager + */ + public tnvt(Screen5250 screen52, boolean enhanced, boolean support132, TerminalBridge bridge, TerminalManager manager) { + this.screen52 = screen52; + this.support132 = support132; + this.enhanced = enhanced; + this.bridge = bridge; + this.manager = manager; + setCodePage("37"); + 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 void showURL(String url) { + if (url.indexOf("://") < 0) url = "http://" + url; + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + manager.startActivity(intent); + } + + public String getHostName() { + + return hostname; + } + + 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.i(TAG," socks set "); + } + + public final boolean connect(String hostname, int port, vt320 buffer) { + try { + this.hostname = hostname; + this.port = port; + + try { + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED,"X - Connecting"); + } catch (Exception exc) { + Log.w(TAG,"setStatus(ON) " + exc.getMessage()); + } + + SocketConnector sc = new SocketConnector(); + if (sslType != null) sc.setSSLType(sslType); + sock = sc.createSocket(hostname, port, bridge, manager); + + if (sock == null) { + Log.w(TAG,"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.w(TAG,"setCursorOff " + excc.getMessage()); + + } + + producer = new DataStreamProducer(this, bin, buffer, 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 { + screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED, + ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); + } catch (Exception exc) { + Log.w(TAG,"setStatus(OFF) " + exc.getMessage()); + } + + keepTrucking = true; + me = new Thread(this); + me.start(); + + } catch (Exception exception) { + if (exception.getMessage() == null) + exception.printStackTrace(); + Log.w(TAG,"connect() " + exception.getMessage()); + + if (sock == null) + Log.w(TAG,"I did not get a socket"); + + disconnect(); + return false; + } + return true; + + } + + public final boolean disconnect() { + + 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.i(TAG,"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(); + } catch (Exception exception) { + Log.w(TAG,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.w(TAG,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.w(TAG,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.w(TAG,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.w(TAG,ioe.getMessage()); + } + } + + /** + * Opens a dialog and asks the user before sending a request + * + * @see {@link #systemRequest(String)} + */ + public final void systemRequest() { + String ask = manager.res.getString(R.string.prompt_sys_request); + String sysreq = bridge.promptHelper.requestStringPrompt(null, ask); + 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.i(TAG,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.w(TAG,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.w(TAG,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.d(TAG,"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.d(TAG,"RUN cmd = " + cmd); + Log.d(TAG,"RUN wait = " + waitFor); + + Runtime r = Runtime.getRuntime(); + Process p = r.exec(cmd); + if (waitFor) + { + int result = p.waitFor(); + Log.d(TAG,"RUN result = " + result); + } + } + catch (Throwable t) + { + Log.e(TAG,"exception",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.i(TAG,"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.getScreenAsChars(); + 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)); + //controller.fireScanned(command, remainder); + Log.i(TAG,"trying to run " + 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.w(TAG," 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.d(TAG,"No operation"); + break; + case 1: + Log.d(TAG,"Invite Operation"); + parseIncoming(); + // screen52.setKeyboardLocked(false); + pendingUnlock = true; + cursorOn = true; + setInvited(); + break; + case 2: + Log.d(TAG,"Output Only"); + parseIncoming(); + screen52.updateDirty(); + break; + case 3: + Log.d(TAG,"Put/Get Operation"); + parseIncoming(); + setInvited(); + if (!firstScreen) { + firstScreen = true; + //controller.fireSessionChanged(TN5250jConstants.STATE_CONNECTED); + } + break; + case 4: + Log.d(TAG,"Save Screen Operation"); + parseIncoming(); + break; + + case 5: + Log.d(TAG,"Restore Screen Operation"); + parseIncoming(); + break; + case 6: + Log.d(TAG,"Read Immediate"); + sendAidKey(0); + break; + case 7: + Log.d(TAG,"Reserved"); + break; + case 8: + Log.d(TAG,"Read Screen Operation"); + try { + readScreen(); + } catch (IOException ex) { + Log.w(TAG,ex.getMessage()); + } + break; + + case 9: + Log.d(TAG,"Reserved"); + break; + + case 10: + Log.d(TAG,"Cancel Invite Operation"); + cancelInvite(); + break; + + case 11: + Log.d(TAG,"Turn on message light"); + screen52.getOIA().setMessageLightOn(); + screen52.setCursorActive(true); + + break; + case 12: + Log.d(TAG,"Turn off Message light"); + screen52.getOIA().setMessageLightOff(); + screen52.setCursorActive(true); + + break; + default: + break; + } + + if (screen52.isUsingGuiInterface()) + screen52.drawFields(); + + try { + if (!strpccmd) { + screen52.updateDirty(); + } else { + strpccmd(); + } + } catch (Exception exd) { + Log.w(TAG," 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() { + Log.d(TAG," Pending unlock " + pendingUnlock); + Log.d(TAG," Status Error " + screen52.isStatusErrorCode()); + Log.d(TAG," Keyboard Locked " + screen52.getOIA().isKeyBoardLocked()); + Log.d(TAG," Cursor On " + cursorOn); + Log.d(TAG," Cursor Active " + screen52.cursorActive); + } + + + 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.i(TAG," 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.i(TAG,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.d(TAG,"Saved "); + Log.d(TAG,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.w(TAG,ioe.getMessage()); + } + + sc = null; + Log.d(TAG,"Save Screen end "); + } + + /** + * + * @throws IOException + */ + public final void restoreScreen() throws IOException { + int which = 0; + + ScreenPlanes planes = screen52.planes; + + try { + Log.d(TAG,"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()) || (cols != screen52.getColumns())) + 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.i(TAG," 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.d(TAG,"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(); + } + Log.d(TAG,"/nRestored "); + Log.d(TAG,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.w(TAG,"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.d(TAG,"save screen partial"); + saveScreen(); + break; + + case ESC: // ESCAPE + break; + case 7: // audible bell + manager.playBeep(); + 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.d(TAG,"restore screen partial"); + restoreScreen(); + break; + + case CMD_CLEAR_UNIT_ALTERNATE: // 0x20 32 clear unit alternate + int param = bk.getNextByte(); + if (param != 0) { + Log.d(TAG," 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; + } + } catch (Exception exc) { + Log.w(TAG,"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.i(TAG,"invalid " + from + " command " + os + + " at pos " + cp); + } catch (Exception e) { + + Log.w(TAG,"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.w(TAG,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.w(TAG,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.d(TAG,"SOH - Start of Header Order"); + error = processSOH(); + + break; + case 02: // RA - Repeat to address + Log.d(TAG,"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.d(TAG,"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.d(TAG,"Command - Escape"); + done = true; + break; + + case 16: // TD - Transparent Data + Log.d(TAG,"TD - Transparent Data"); + int j = (bk.getNextByte() & 0xff) << 8 | bk.getNextByte() + & 0xff; // length + break; + + case 17: // SBA - set buffer address order (row column) + Log.d(TAG,"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.d(TAG,"WEA - Extended Attribute"); + bk.getNextByte(); + bk.getNextByte(); + break; + + case 19: // IC - Insert Cursor + Log.d(TAG,"IC - Insert Cursor"); + int icX = bk.getNextByte(); + int icY = bk.getNextByte() & 0xff; + if (icX >= 0 && icX <= saRows && icY >= 0 && icY <= saCols) { + + Log.d(TAG," 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.d(TAG,"MC - Move Cursor"); + int imcX = bk.getNextByte(); + int imcY = bk.getNextByte() & 0xff; + if (imcX >= 0 && imcX <= saRows && imcY >= 0 + && imcY <= saCols) { + + Log.d(TAG," 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.d(TAG,"WTDSF - Write To Display Structured Field order"); + byte[] seg = bk.getSegment(); + error = sfParser.parseWriteToDisplayStructuredField(seg); + break; + + case 29: // SF - Start of Field + Log.d(TAG,"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.i(TAG,Integer.toHexString(fcw1) + " " + + Integer.toHexString(fcw2) + + " "); + Log.i(TAG,Integer.toHexString(attr) + + " " + + Integer.toHexString(bk + .getNextByte() & 0xff)); + 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.d(TAG,"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.d(TAG,"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.w(TAG,"write to display " + e.getMessage()); + e.printStackTrace(); + } + ; + + processCC1(control1); + + return error; + + } + + private boolean processSOH() throws Exception { + + int l = bk.getNextByte(); // length + Log.d(TAG," 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.d(TAG," 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.d(TAG," Control byte1 " + Integer.toBinaryString(byte1 & 0xff)); + + if ((byte1 & 0x04) == 0x04) { + manager.playBeep(); + } + 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.d(TAG," WTD position no move"); + } else { + + screen52.setPendingInsert(true); + Log.d(TAG," 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.d(TAG,"invalid structured field sub command " + + bk.getByteOffset(-1)); + break; + } + break; + default: + Log.d(TAG,"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.i(TAG,"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.i(TAG,"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; + } + } + Log.i(TAG,"Chose keyboard mapping " + kbdTypesCodePage.toString() + " for code page " + cp); + } + + public final ICodePage getCodePage() { + return codePage; + } + + public void signalBell() { + manager.playBeep(); + } + +} diff -r b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,207 @@ +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 com.five_ten_sg.connectbot.R; +import com.five_ten_sg.connectbot.service.TerminalBridge; +import com.five_ten_sg.connectbot.service.TerminalManager; + +import org.tn5250j.GlobalConfigure; +import org.tn5250j.framework.transport.SSLInterface; +import android.util.Log; + + +/** + *

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

+ * + * @author Stephen M. Kennedy + * + */ +public class SSLImplementation implements SSLInterface, X509TrustManager { + private static final String TAG = "SSLImplementation"; + SSLContext sslContext = null; + KeyStore userks = null; + private String userKsPath; + private char[] userksPassword = "changeit".toCharArray(); + + TerminalBridge bridge = null; + TerminalManager manager = null; + String target = null; // destination:port + + KeyManagerFactory userkmf = null; + + TrustManagerFactory usertmf = null; + + TrustManager[] userTrustManagers = null; + + X509Certificate[] acceptedIssuers; + + public SSLImplementation(TerminalBridge bridge, TerminalManager manager) { + this.bridge = bridge; + this.manager = manager; + + } + + public void init(String sslType) { + try { + Log.d(TAG,"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); + Log.d(TAG,"Initializing User Key Manager Factory"); + userkmf = KeyManagerFactory.getInstance(KeyManagerFactory + .getDefaultAlgorithm()); + userkmf.init(userks, userksPassword); + Log.d(TAG,"Initializing User Trust Manager Factory"); + usertmf = TrustManagerFactory.getInstance(TrustManagerFactory + .getDefaultAlgorithm()); + usertmf.init(userks); + userTrustManagers = usertmf.getTrustManagers(); + Log.d(TAG,"Initializing SSL Context"); + sslContext = SSLContext.getInstance(sslType); + sslContext.init(userkmf.getKeyManagers(), new TrustManager[] {this}, null); + } catch (Exception ex) { + Log.e(TAG,"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 { + target = destination + ":" + String.valueOf(port); + socket = (SSLSocket) sslContext.getSocketFactory().createSocket( + destination, port); + } catch (Exception e) { + Log.e(TAG,"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 = manager.res.getString(R.string.host_cert_version) + cert.getVersion() + "\r\n"; + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_serial) + cert.getSerialNumber() + "\r\n"); + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_algorithm) + cert.getSigAlgName() + "\r\n"); + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_issuer) + cert.getIssuerDN().getName() + "\r\n"); + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_from) + cert.getNotBefore() + "\r\n"); + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_to) + cert.getNotAfter() + "\r\n"); + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_dn) + cert.getSubjectDN().getName() + "\r\n"); + certInfo = certInfo.concat(manager.res.getString(R.string.host_cert_publickey) + cert.getPublicKey().getFormat() + "\r\n"); + + bridge.outputLine(manager.res.getString(R.string.host_authenticity_warning, target)); + bridge.outputLine(manager.res.getString(R.string.host_certificate, certInfo)); + Boolean result = bridge.promptHelper.requestBooleanPrompt(null, manager.res.getString(R.string.prompt_accept_certificate)); + if ((result == null) || (!result.booleanValue())) { + throw new java.security.cert.CertificateException( + "Certificate Rejected"); + } + + result = bridge.promptHelper.requestBooleanPrompt(null, manager.res.getString(R.string.prompt_save_certificate)); + if ((result != null) && (result.booleanValue())) { + try { + userks.setCertificateEntry(cert.getSubjectDN().getName(), + cert); + userks.store(new FileOutputStream(userKsPath), + userksPassword); + } catch (Exception e) { + Log.e(TAG,"Error saving certificate [" + e.getMessage() + + "]"); + e.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff -r b3d0d806cbe2 -r 01d939969b10 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 Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,108 @@ +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 com.five_ten_sg.connectbot.R; +import com.five_ten_sg.connectbot.service.TerminalBridge; +import com.five_ten_sg.connectbot.service.TerminalManager; + + +/** + * 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; + TerminalBridge bridge = null; + TerminalManager manager = null; + + public X509CertificateTrustManager(TrustManager[] managers, KeyStore keyStore, TerminalBridge bridge, TerminalManager manager) { + this.bridge = bridge; + this.manager = manager; + 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, TerminalBridge bridge, TerminalManager manager) { + + Socket socket = null; + Exception ex = null; + + if (sslType == null || sslType.trim().length() == 0 || + sslType.toUpperCase().equals(TN5250jConstants.SSL_TYPE_NONE)) { + Log.i(TAG,"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 + + Log.i(TAG,"Creating SSL ["+sslType+"] Socket"); + + SSLInterface sslIf = null; + + try { + sslIf = (SSLInterface) new SSLImplementation(bridge, manager); + } 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) { + Log.e(TAG, "exception", ex); + } + if (socket == null) { + Log.w(TAG, "No socket was created"); + } + return socket; + } + + +} \ No newline at end of file diff -r b3d0d806cbe2 -r 01d939969b10 src/org/tn5250j/interfaces/ConfigureFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tn5250j/interfaces/ConfigureFactory.java Mon Jun 16 08:24:00 2014 -0700 @@ -0,0 +1,98 @@ +/* + * @(#)ConfigureFactory.java + * @author Kenneth J. Pouncey + * Modified by LDC Luc + * + * Copyright: Copyright (c) 2001, 2002, 2003 + * + * 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.interfaces; + +import org.tn5250j.GlobalConfigure; +import java.util.Properties; + +/** + * An interface defining objects that can create Configure + * instances. + */ +public abstract class ConfigureFactory { + + static final public String SESSIONS = "sessions"; + static final public String MACROS = "macros"; + static final public String KEYMAP = "keymap"; + private static ConfigureFactory factory; + + /** + * @return An instance of the Configure. + */ + public static ConfigureFactory getInstance() + { + ConfigureFactory.setFactory(); + return factory; + } + + private static final void setFactory() + { + if (factory == null) + { + try + { + String className = System.getProperty(ConfigureFactory.class.getName()); + if (className != null) + { + Class classObject = Class.forName(className); + Object object = classObject.newInstance(); + if (object instanceof ConfigureFactory) + { + ConfigureFactory.factory = (ConfigureFactory) object; + } + } + } + catch (Exception ex) + { + ; + } + if (ConfigureFactory.factory == null) + { //take the default +// ConfigureFactory.factory = new GlobalConfigureFactory(); + ConfigureFactory.factory = new GlobalConfigure(); + } + } + } + + abstract public void reloadSettings(); + abstract public void saveSettings(); + abstract public String getProperty(String regKey); + abstract public String getProperty(String regKey, String defaultValue); + abstract public void setProperties(String regKey, Properties regProps); + + abstract public void setProperties(String regKey, String fileName, String header); + abstract public void setProperties(String regKey, String fileName, String header, + boolean createFile); + abstract public Properties getProperties(String regKey); + abstract public Properties getProperties(String regKey,String fileName); + abstract public Properties getProperties(String regKey,String fileName, + boolean createFile, String header); + abstract public Properties getProperties(String regKey,String fileName, + boolean createFile, String header, + boolean reloadIfLoaded); + abstract public void saveSettings(String regKey); + abstract public void saveSettings(String regKey, String header); + abstract public void saveSettings(String regKey, String fileName, String header); + +} \ No newline at end of file diff -r b3d0d806cbe2 -r 01d939969b10 xml/510connectbot.in --- a/xml/510connectbot.in Tue Jun 03 08:48:14 2014 -0700 +++ b/xml/510connectbot.in Mon Jun 16 08:24:00 2014 -0700 @@ -24,7 +24,7 @@ - 2014-05-13 + 2014-06-14 Carl Byington @@ -40,7 +40,7 @@ @PACKAGE@ - an android vt320 terminal emulator for telnet/ssh connections + an android vt320/tn5250 terminal emulator for telnet/ssh connections @@ -61,14 +61,17 @@ compatible with the licenses of all the sub-parts. - The intention is to add 5250 emulation to this project. + This fork extends previous connectbot projects in two ways. It includes + tn5250 terminal emulation, in addition to the previous vt320 terminal + emulation. It also contains hooks for a separate monitoring process + that has access to some of the internal operations in this emulator. Terminal Monitor - For every terminal session (local, telnet, ssh or other), this + For every terminal session (local, telnet, ssh or tn5250), this terminal emulator also makes a connection to a terminal monitor process, which can see keystrokes and screen contents, and can inject characters to send to the host. @@ -179,7 +182,8 @@ TODO - Add 5250 emulation. + The tn5250 ssl/tls key storage should use the same storage mechanism + as the base ssh key storage. @@ -230,6 +234,11 @@ Marcus Meiner. http://www.javassh.org + Based on TN5250J terminal emulator provided under the GPLv2 + license. Copyright (C) 2001 Kenneth J. Pouncey. + http://tn5250j.sourceforge.net/ + + Includes the JSOCKS library, provided under the GNU LGPL license. http://jsocks.sourceforge.net @@ -247,6 +256,12 @@ https://github.com/staktrace/connectbot/commits/filetransfer modifications by Kartikaya Gupta. + + Internal file selection dialog is based on Android File + Dialog by Alexander Ponomarev, provided under a BSD-style + license. + http://code.google.com/p/android-file-dialog +