changeset 79:01d939969b10

merge tn5250 branch into default
author Carl Byington <carl@five-ten-sg.com>
date Mon, 16 Jun 2014 08:24:00 -0700
parents b3d0d806cbe2 (current diff) 044b1a951925 (diff)
children ab8d2f6c5847
files src/com/five_ten_sg/connectbot/service/TerminalBridge.java src/com/five_ten_sg/connectbot/service/TerminalMonitor.java
diffstat 73 files changed, 16491 insertions(+), 872 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 	package="com.five_ten_sg.connectbot"
-	android:versionName="1.7.2-1"
+	android:versionName="1.8.0-1"
 	android:versionCode="1"
 	android:installLocation="auto">
 
@@ -63,9 +63,10 @@
 			<intent-filter>
 				<action android:name="android.intent.action.PICK" />
 				<category android:name="android.intent.category.DEFAULT" />
-				<data android:scheme="ssh" />
+				<data android:scheme="tn5250" />
+				<data android:scheme="ssh"    />
 				<data android:scheme="telnet" />
-				<data android:scheme="local" />
+				<data android:scheme="local"  />
 			</intent-filter>
 		</activity>
 
@@ -104,9 +105,10 @@
 				<action android:name="android.intent.action.VIEW" />
 				<category android:name="android.intent.category.DEFAULT" />
 				<category android:name="android.intent.category.BROWSABLE" />
-				<data android:scheme="ssh" />
+				<data android:scheme="tn5250" />
+				<data android:scheme="ssh"    />
 				<data android:scheme="telnet" />
-				<data android:scheme="local" />
+				<data android:scheme="local"  />
 				<!-- format:  ssh://user@host:port/#nickname  -->
 				<!-- format:  telnet://host:port/#nickname  -->
 				<!-- format:  local://  -->
--- 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)
--- 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
 
--- 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 @@
 &lt;carl@five-ten-sg.com&gt;</p>
 
 <p>This is an enhanced version of the popular open-source telnet and
-secure shell (SSH) client ConnectBot.</p>
+secure shell (SSH) client ConnectBot. It now includes tn5250 emulation.</p>
 
 <p>It is licensed under
 the <a href="http://www.gnu.org/licenses/gpl-3.0.txt">GPLv3 or later
@@ -50,6 +50,12 @@
 </p>
 
 <p>
+Based on TN5250J terminal emulator provided under the GPLv2
+license. Copyright &copy; 2001 Kenneth J. Pouncey.
+<a href="http://tn5250j.sourceforge.net"></a>http://tn5250j.sourceforge.net
+</p>
+
+<p>
 Includes the JSOCKS library, provided under the GNU LGPL
 license. <a href="http://jsocks.sourceforge.net">http://jsocks.sourceforge.net</a>
 </p>
--- 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 @@
 		<item>screen</item>
 	</string-array>
 
+	<string-array name="list_5250_encryption_modes" translatable="false">
+		<item>NONE</item>
+		<item>SSLv2</item>
+		<item>SSLv3</item>
+		<item>TLS</item>
+	</string-array>
+
 	<string-array name="list_rotation" translatable="false">
 		<item>@string/list_rotation_default</item>
 		<item>@string/list_rotation_land</item>
--- 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 @@
 	<!-- First field is encryption algorithm. Second is the actual fingerprint in hex digits -->
 	<string name="host_fingerprint">"Host %1$s key fingerprint is %2$s"</string>
 
+    <!-- tn5250 strings -->
+	<string name="host_cert_version">"Version: "</string>
+	<string name="host_cert_serial">"Serial Number: "</string>
+	<string name="host_cert_algorithm">"Signature Algorithm: "</string>
+	<string name="host_cert_issuer">"Issuer: "</string>
+	<string name="host_cert_from">"Valid From: "</string>
+	<string name="host_cert_to">"Valid To: "</string>
+	<string name="host_cert_dn">"Subject DN: "</string>
+	<string name="host_cert_publickey">"Public Key: "</string>
+	<string name="host_certificate">"The certificate is %1$s"</string>
+	<string name="prompt_accept_certificate">"Unknown Certificate - Do you accept it?"</string>
+	<string name="prompt_save_certificate">"Do you want to save this certificate?"</string>
+	<string name="prompt_sys_request">"Enter sys-request string"</string>
+
 	<string name="alert_passwords_do_not_match_msg">"Passwords do not match!"</string>
 	<string name="alert_wrong_password_msg">"Wrong password!"</string>
 	<string name="alert_key_corrupted_msg">"Private key appears corrupt!"</string>
@@ -332,6 +346,13 @@
 	<!-- Monitor field title for host editor preference -->
 	<string name="hostpref_monitor_title">"Monitor Init String"</string>
 
+	<!-- Override global emulation (terminal type) host editor preference -->
+	<string name="hostpref_emulation_title">"Emulation mode"</string>
+	<string name="hostpref_emulation_summary">"Override global emulation mode / answerback string"</string>
+
+	<!-- Host 5250_encryption preference title -->
+	<string name="hostpref_5250_encryption_title">"Host 5250 Encryption"</string>
+
 	<!-- Host preference category title for x11 forwarding -->
 	<string name="hostpref_x11_forwarding">"X11 forwarding"</string>
 
@@ -501,7 +522,7 @@
 	<string name="terminal_no_session">"Session will not be started due to host preference."</string>
 	<string name="terminal_enable_portfoward">"Enable port forward: %1$s"</string>
 
-	<string name="local_shell_unavailable">"Failure! Local shell is unavailable on this phone."</string>
+	<string name="local_shell_unavailable">"Failure! Local shell is unavailable on this device."</string>
 
 	<!-- Text sent to the user to alert them that a Terminal Bell is received in a background session -->
 	<string name="notification_text">"%1$s wants your attention."</string>
--- 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 @@
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 
-	<EditTextPreference
-		android:key="nickname"
-		android:title="@string/hostpref_nickname_title"
-		android:singleLine="true"
-		/>
+    <EditTextPreference
+        android:key="nickname"
+        android:title="@string/hostpref_nickname_title"
+        android:singleLine="true"
+        />
 
-	<ListPreference
-		android:key="color"
-		android:title="@string/hostpref_color_title"
-		android:entries="@array/list_colors"
-		android:entryValues="@array/list_color_values"
-		/>
+    <ListPreference
+        android:key="color"
+        android:title="@string/hostpref_color_title"
+        android:entries="@array/list_colors"
+        android:entryValues="@array/list_color_values"
+        />
 
-	<EditTextPreference
-		android:key="fontsize"
-		android:title="@string/hostpref_fontsize_title"
-		android:inputType="number"
-		android:singleLine="true"
-		/>
+    <EditTextPreference
+        android:key="fontsize"
+        android:title="@string/hostpref_fontsize_title"
+        android:inputType="number"
+        android:singleLine="true"
+        />
 
 <!--
-	<CheckBoxPreference
-		android:key="usekeys"
-		android:title="Use SSH keys"
-		/>
+    <CheckBoxPreference
+        android:key="usekeys"
+        android:title="Use SSH keys"
+        />
 -->
 
-	<ListPreference
-		android:key="pubkeyid"
-		android:title="@string/hostpref_pubkeyid_title"
-		android:entries="@array/list_pubkeyids"
-		android:entryValues="@array/list_pubkeyids_value"
-		/>
+    <ListPreference
+        android:key="pubkeyid"
+        android:title="@string/hostpref_pubkeyid_title"
+        android:entries="@array/list_pubkeyids"
+        android:entryValues="@array/list_pubkeyids_value"
+        />
 
-	<ListPreference
-		android:key="useauthagent"
-		android:title="@string/hostpref_authagent_title"
-		android:entries="@array/list_authagent"
-		android:entryValues="@array/list_authagent_values"
-		/>
+    <ListPreference
+        android:key="useauthagent"
+        android:title="@string/hostpref_authagent_title"
+        android:entries="@array/list_authagent"
+        android:entryValues="@array/list_authagent_values"
+        />
 
-	<EditTextPreference
-		android:key="postlogin"
-		android:title="@string/hostpref_postlogin_title"
-		android:summary="@string/hostpref_postlogin_summary"
-		/>
+    <EditTextPreference
+        android:key="postlogin"
+        android:title="@string/hostpref_postlogin_title"
+        android:summary="@string/hostpref_postlogin_summary"
+        />
 
-	<CheckBoxPreference
-		android:key="compression"
-		android:title="@string/hostpref_compression_title"
-		android:summary="@string/hostpref_compression_summary"
-		/>
+    <CheckBoxPreference
+        android:key="compression"
+        android:title="@string/hostpref_compression_title"
+        android:summary="@string/hostpref_compression_summary"
+        />
 
-	<EditTextPreference
-		android:key="httpproxy"
-		android:title="@string/hostpref_httpproxy_title"
-		android:summary="@string/hostpref_httpproxy_summary"
-		android:inputType="textUri"
-		/>
+    <EditTextPreference
+        android:key="httpproxy"
+        android:title="@string/hostpref_httpproxy_title"
+        android:summary="@string/hostpref_httpproxy_summary"
+        android:inputType="textUri"
+        />
 
-	<CheckBoxPreference
-		android:key="wantsession"
-		android:title="@string/hostpref_wantsession_title"
-		android:summary="@string/hostpref_wantsession_summary"
-		/>
+    <CheckBoxPreference
+        android:key="wantsession"
+        android:title="@string/hostpref_wantsession_title"
+        android:summary="@string/hostpref_wantsession_summary"
+        />
 
-	<CheckBoxPreference
-		android:key="stayconnected"
-		android:title="@string/hostpref_stayconnected_title"
-		android:summary="@string/hostpref_stayconnected_summary"
-		/>
+    <CheckBoxPreference
+        android:key="stayconnected"
+        android:title="@string/hostpref_stayconnected_title"
+        android:summary="@string/hostpref_stayconnected_summary"
+        />
 
-	<ListPreference
-		android:key="delkey"
-		android:title="@string/hostpref_delkey_title"
-		android:summary="@string/hostpref_delkey_summary"
-		android:entries="@array/list_delkey"
-		android:entryValues="@array/list_delkey_values"
-		/>
+    <ListPreference
+        android:key="delkey"
+        android:title="@string/hostpref_delkey_title"
+        android:summary="@string/hostpref_delkey_summary"
+        android:entries="@array/list_delkey"
+        android:entryValues="@array/list_delkey_values"
+        />
+
+    <ListPreference
+        android:key="encoding"
+        android:title="@string/hostpref_encoding_title"
+        android:summary="@string/hostpref_encoding_summary"
+        />
+
+    <PreferenceCategory
+        android:title="@string/hostpref_connection_category">
 
-	<ListPreference
-		android:key="encoding"
-		android:title="@string/hostpref_encoding_title"
-		android:summary="@string/hostpref_encoding_summary"
-		/>
+        <EditTextPreference
+            android:key="username"
+            android:title="@string/hostpref_username_title"
+            android:singleLine="true"
+            />
 
-	<PreferenceCategory
-		android:title="@string/hostpref_connection_category">
+        <EditTextPreference
+            android:key="hostname"
+            android:title="@string/hostpref_hostname_title"
+            android:singleLine="true"
+            />
 
-		<EditTextPreference
-			android:key="username"
-			android:title="@string/hostpref_username_title"
-			android:singleLine="true"
-			/>
+        <EditTextPreference
+            android:key="port"
+            android:title="@string/hostpref_port_title"
+            android:numeric="integer"
+            />
 
-		<EditTextPreference
-			android:key="hostname"
-			android:title="@string/hostpref_hostname_title"
-			android:singleLine="true"
-			/>
+        <EditTextPreference
+            android:key="monitor"
+            android:title="@string/hostpref_monitor_title"
+            android:singleLine="true"
+            />
 
-		<EditTextPreference
-			android:key="port"
-			android:title="@string/hostpref_port_title"
-			android:numeric="integer"
-			/>
+        <EditTextPreference
+            android:key="emulation"
+            android:title="@string/hostpref_emulation_title"
+            android:summary="@string/hostpref_emulation_summary"
+            android:singleLine="true"
+            />
 
-		<EditTextPreference
-			android:key="monitor"
-			android:title="@string/hostpref_monitor_title"
-			android:singleLine="true"
-			/>
-	</PreferenceCategory>
+        <ListPreference
+            android:key="encryption5250"
+            android:title="@string/hostpref_5250_encryption_title"
+			android:entries="@array/list_5250_encryption_modes"
+			android:entryValues="@array/list_5250_encryption_modes"
+            />
+    </PreferenceCategory>
 
-	<PreferenceCategory
-	    android:title="@string/hostpref_x11_forwarding">
+
+    <PreferenceCategory
+        android:title="@string/hostpref_x11_forwarding">
 
-		<CheckBoxPreference
-			android:key="wantx11forward"
-			android:title="@string/hostpref_wantx11forward_title"
-			android:summary="@string/hostpref_wantx11forward_summary"
-		/>
+        <CheckBoxPreference
+            android:key="wantx11forward"
+            android:title="@string/hostpref_wantx11forward_title"
+            android:summary="@string/hostpref_wantx11forward_summary"
+        />
 
-		<EditTextPreference
-		    android:key="x11host"
-		    android:title="@string/hostpref_x11host_title"
-		    android:singleLine="true"
-		    />
+        <EditTextPreference
+            android:key="x11host"
+            android:title="@string/hostpref_x11host_title"
+            android:singleLine="true"
+            />
 
-		<EditTextPreference
-		    android:key="x11port"
-		    android:title="@string/hostpref_x11port_title"
-		    android:numeric="integer"
-		    />
+        <EditTextPreference
+            android:key="x11port"
+            android:title="@string/hostpref_x11port_title"
+            android:numeric="integer"
+            />
 
-	</PreferenceCategory>
+    </PreferenceCategory>
 
 </PreferenceScreen>
--- 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"
 			/>
 
 		<EditTextPreference
--- a/src/com/five_ten_sg/connectbot/HostListActivity.java	Tue Jun 03 08:48:14 2014 -0700
+++ b/src/com/five_ten_sg/connectbot/HostListActivity.java	Mon Jun 16 08:24:00 2014 -0700
@@ -97,11 +97,11 @@
         public void onServiceConnected(ComponentName className, IBinder service) {
             bound = ((TerminalManager.TerminalBinder) service).getService();
             // update our listview binder to find the service
-            HostListActivity.this.updateList();
+            updateList();
         }
         public void onServiceDisconnected(ComponentName className) {
             bound = null;
-            HostListActivity.this.updateList();
+            updateList();
         }
     };
 
@@ -146,7 +146,7 @@
             }
         }
         else if (requestCode == REQUEST_EDIT) {
-            this.updateList();
+            updateList();
         }
     }
 
@@ -174,21 +174,20 @@
         boolean agreed = prefs.getBoolean(PreferenceConstants.EULA, false);
 
         if (!agreed) {
-            this.startActivityForResult(new Intent(this, WizardActivity.class), REQUEST_EULA);
+            startActivityForResult(new Intent(this, WizardActivity.class), REQUEST_EULA);
         }
 
-        this.makingShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())
+        makingShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())
                               || Intent.ACTION_PICK.equals(getIntent().getAction());
         // connect with hosts database and populate list
-        this.hostdb = new HostDatabase(this);
-        ListView list = this.getListView();
-        this.sortedByColor = prefs.getBoolean(PreferenceConstants.SORT_BY_COLOR, false);
-        //this.list.setSelector(R.drawable.highlight_disabled_pressed);
-        list.setOnItemClickListener(new OnItemClickListener() {
-
+        hostdb = new HostDatabase(this);
+        updateList();
+        sortedByColor = prefs.getBoolean(PreferenceConstants.SORT_BY_COLOR, false);
+        registerForContextMenu(getListView());
+        getListView().setOnItemClickListener(new OnItemClickListener() {
             public synchronized void onItemClick(AdapterView<?> 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() {
--- 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();
--- 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;
     }
 
--- 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<FontSizeChangedListener> fontSizeChangedListeners;
 
@@ -160,7 +158,6 @@
         manager = null;
         defaultPaint = new Paint();
         selectionArea = new SelectionArea();
-        scrollback = 1;
         localOutput = new LinkedList<String>();
         fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>();
         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);
             }
         };
--- 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;
--- 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() {
--- 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());
+    }
+
 }
--- 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<String, String> 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<String, String> 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;
--- 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<String, String> options) {
+        if (options.containsKey("compression"))
+            compression = Boolean.parseBoolean(options.get("compression"));
+
+        if (options.containsKey("httpproxy"))
+            httpproxy = options.get("httpproxy");
+    }
+
+
     @Override
     public Map<String, String> getOptions() {
         Map<String, String> options = new HashMap<String, String>();
@@ -624,36 +709,22 @@
         return options;
     }
 
+
     @Override
-    public void setOptions(Map<String, String> 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<String, String> 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<String, String> 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<String, byte[]> retrieveIdentities() {
@@ -1103,11 +1138,4 @@
         return true;
     }
 
-    /* (non-Javadoc)
-     * @see com.five_ten_sg.connectbot.transport.AbsTransport#usesNetwork()
-     */
-    @Override
-    public boolean usesNetwork() {
-        return true;
-    }
 }
--- /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<Integer, String> mnemonics;
+
+        public vt320x5250() {
+            this(80,24);
+        }
+
+        public vt320x5250(int width, int height) {
+            super(width, height);
+            mnemonics = new HashMap<Integer, String>();
+            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
+     * <code>buffer</code> at the start of <code>offset</code> and a maximum of
+     * <code>length</code> 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<String, String> 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());
+    }
+
+}
--- 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.<br/>
  * 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<String, String> 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<String, String> 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;
--- 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);
     }
 
     /**
--- 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,
--- 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);
         }
 
--- 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;
     }
--- 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.<P>
-     * $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<n; i++) b[i] = (byte)(d[i] & 0x00ff);
+        write(b);
+    }
+
+    /**
      * Play the beep sound ...
      */
     public void beep() {
         /* do nothing by default */
     }
 
+    public void redrawPassthru() {
+        redraw();   // VDUBuffer.redraw is protected
+    }
+
     /**
      * Convenience function for putString(char[], int, int)
      */
@@ -741,8 +750,9 @@
     public final static int KEY_NUMPAD8 = 39;
     public final static int KEY_NUMPAD9 = 40;
     public final static int KEY_DECIMAL = 41;
-    public final static int KEY_ADD = 42;
-    public final static int KEY_ESCAPE = 43;
+    public final static int KEY_ADD     = 42;
+    public final static int KEY_ESCAPE  = 43;
+    public final static int KEY_TAB     = 44;
 
     public final static int DELETE_IS_DEL = 0;
     public final static int DELETE_IS_BACKSPACE = 1;
@@ -1094,12 +1104,24 @@
 
             case KEY_CAPS_LOCK:
                 capslock = !capslock;
-                return;
+                break;
 
             case KEY_SHIFT:
             case KEY_CONTROL:
             case KEY_ALT:
-                return;
+                break;
+
+            case KEY_ESCAPE:
+                write(0x1b);
+                break;
+
+            case KEY_ENTER:
+                write(0x0d);
+                break;
+
+            case KEY_TAB:
+                write(0x09);
+                break;
 
             default:
                 break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/GlobalConfigure.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,508 @@
+/**
+ * Title: GlobalConfigure.java
+ * Copyright:   Copyright (c) 2001, 2002, 2003
+ * Company:
+ * @author  Kenneth J. Pouncey
+ * @version 0.1
+ *
+ * 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;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import com.five_ten_sg.connectbot.TerminalView;
+import org.tn5250j.interfaces.ConfigureFactory;
+import android.util.Log;
+
+
+/**
+ * Utility class for referencing global settings and functions of which at most
+ * one instance can exist per VM.
+ *
+ * Use GlobalConfigure.instance() to access this instance.
+ */
+public class GlobalConfigure extends ConfigureFactory {
+    private static final String TAG = "GlobalConfigure";
+    public static final String TN5250J_FOLDER = ".tn5250j";
+
+    /**
+     * A handle to the unique GlobalConfigure class
+     */
+    static private GlobalConfigure _instance;
+
+    /**
+     * A handle to the the Global Properties
+     */
+    static private Properties settings;
+
+    static private Hashtable registry = new Hashtable();
+    static private Hashtable headers = new Hashtable();  //LUC GORRENS
+
+
+    /**
+     * The constructor is made protected to allow overriding.
+     */
+    public GlobalConfigure() {
+        if (_instance == null) {
+            // initialize the settings information
+            initialize();
+            // set our instance to this one.
+            _instance = this;
+        }
+    }
+
+    /**
+     *
+     * @return The unique instance of this class.
+     */
+    static public GlobalConfigure instance() {
+
+        if (_instance == null) {
+            _instance = new GlobalConfigure();
+        }
+        return _instance;
+
+    }
+
+    /**
+     * Initialize the properties registry for use later.
+     *
+     */
+    private void initialize() {
+        verifySettingsFolder();
+        loadSettings();
+        loadSessions();
+        loadMacros();
+        loadKeyStrokes();
+    }
+
+    /**
+     * check if folder %USERPROFILE%/.tn5250j exists
+     * and create if necessary
+     */
+    private void verifySettingsFolder() {
+        final String settingsfolder = settingsFolder();
+        final File f = new File (settingsfolder);
+        if (!f.exists()) {
+            try {
+                Log.i(TAG,"Settings folder '"+settingsfolder+"' doesn't exist. Will created now.");
+                f.mkdir();
+            } catch (Exception e) {
+                Log.w(TAG,"Couldn't create settings folder '"+settingsfolder+"'", e);
+            }
+        }
+    }
+
+    /**
+     * Load the sessions properties
+     */
+    private void loadSessions() {
+
+        setProperties(SESSIONS,SESSIONS,"------ Sessions --------",true);
+    }
+
+    /**
+     * Load the macros
+     */
+    private void loadMacros() {
+
+        setProperties(MACROS,MACROS,"------ Macros --------",true);
+
+    }
+
+    private void loadKeyStrokes() {
+
+        setProperties(KEYMAP,KEYMAP,
+                "------ Key Map key=keycode,isShiftDown,isControlDown,isAltDown,isAltGrDown --------",
+                true);
+
+    }
+
+    /**
+     * Reload the environment settings.
+     */
+    @Override
+    public void reloadSettings() {
+        Log.i(TAG,"reloading settings");
+        loadSettings();
+        loadSessions();
+        loadMacros();
+        loadKeyStrokes();
+        Log.i(TAG,"Done (reloading settings).");
+    }
+
+    /**
+     * Loads the emulator setting from the setting(s) file
+     */
+    private void loadSettings() {
+
+        FileInputStream in = null;
+        settings = new Properties();
+
+        try {
+            in = new FileInputStream(settingsFile());
+            settings.load(in);
+        }
+        catch (FileNotFoundException fnfea) {
+            Log.i(TAG," Information Message: "
+                    + fnfea.getMessage() + ".  The file " + settingsFile()
+                    + " will be created for first time use.");
+            saveSettings();
+        }
+        catch (IOException ioea) {
+            Log.w(TAG,"IO Exception accessing File "
+                    + settingsFile() + " for the following reason : "
+                    + ioea.getMessage());
+        }
+        catch (SecurityException sea) {
+            Log.w(TAG,"Security Exception for file "
+                    + settingsFile() + "  This file can not be "
+                    + "accessed because : " + sea.getMessage());
+        }
+    }
+
+    /**
+     * Save the settings for the global configuration
+     */
+    @Override
+    public void saveSettings() {
+
+        try {
+            FileOutputStream out = new FileOutputStream(settingsFile());
+            settings.store(out,"----------------- tn5250j Global Settings --------------");
+        }
+        catch (FileNotFoundException fnfe) {}
+        catch (IOException ioe) {}
+    }
+
+    /**
+     * Save the setting in the registry using the key passed in with no header
+     * output.
+     *
+     * @param regKey
+     */
+    @Override
+    public void saveSettings(String regKey) {
+
+        saveSettings(regKey,"");
+    }
+
+    /**
+     * Save the settings in the registry using the key passed with a header
+     * in the output.
+     *
+     * @param regKey
+     * @param Header
+     */
+    @Override
+    public void saveSettings(String regKey, String header) {
+
+        saveSettings(regKey,regKey,header);
+    }
+
+    /**
+     * Save the settings in the registry using the key passed with a header
+     * in the output.
+     *
+     * @param regKey
+     * @param Header
+     */
+    @Override
+    public void saveSettings(String regKey, String fileName, String header) {
+
+        if (registry.containsKey(regKey)) {
+            try {
+                FileOutputStream out = new FileOutputStream(
+                        settingsDirectory() + fileName);
+                Properties props = (Properties)registry.get(regKey);
+                props.store(out,header);
+                out.flush();
+                out.close();
+            }
+            catch (FileNotFoundException fnfe) {
+                Log.w(TAG,"File not found : writing file "
+                        + fileName + ".  Description of error is "
+                        + fnfe.getMessage());
+            }
+            catch (IOException ioe) {
+                Log.w(TAG,"IO Exception : writing file "
+                        + fileName + ".  Description of error is "
+                        + ioe.getMessage());
+            }
+            catch (SecurityException se) {
+                Log.w(TAG,"Security Exception : writing file "
+                        + fileName + ".  Description of error is "
+                        + se.getMessage());
+            }
+
+        }
+
+    }
+
+    /**
+     * Place the Properties in the registry under a given registry name
+     *
+     * @param regKey
+     * @param regProps
+     */
+    @Override
+    public void setProperties(String regKey, Properties regProps) {
+
+        registry.put(regKey, regProps);
+
+    }
+
+    /**
+     * Set the properties for the given registry key.
+     *
+     * @param regKey
+     * @param fileName
+     * @param header
+     */
+    @Override
+    public void setProperties(String regKey,  String fileName, String  header) {  //LG NEW
+        setProperties(regKey, fileName, header, false);
+    }
+
+    /**
+     * Set the properties for the given registry key.
+     *
+     * @param regKey
+     * @param fileName
+     * @param header
+     * @param createFile
+     */
+    @Override
+    public void setProperties(String regKey,  String fileName, String  header,
+            boolean createFile) {
+
+        FileInputStream in = null;
+        Properties props = new Properties();
+        headers.put(regKey, header);
+
+        try {
+            in = new FileInputStream(settingsDirectory() + fileName);
+            props.load(in);
+
+        }
+        catch (FileNotFoundException fnfe) {
+
+            if (createFile) {
+                Log.i(TAG," Information Message: " + fnfe.getMessage()
+                        + ".  The file " + fileName + " will"
+                        + " be created for first time use.");
+
+                saveSettings(regKey,header);
+
+            }
+            else {
+
+                Log.i(TAG," Information Message: " + fnfe.getMessage()
+                        + ".");
+
+            }
+        }
+        catch (IOException ioe) {
+            Log.w(TAG,"IO Exception accessing File "+ fileName +
+                    " for the following reason : "
+                    + ioe.getMessage());
+        }
+        catch (SecurityException se) {
+            Log.w(TAG,"Security Exception for file "+ fileName
+                    + ".  This file can not be accessed because : "
+                    + se.getMessage());
+        }
+
+        registry.put(regKey,props);
+
+    }
+
+    /**
+     * Returns the properties associated with a given registry key.
+     *
+     * @param regKey
+     * @return
+     */
+    @Override
+    public Properties getProperties(String regKey) {
+
+        if (registry.containsKey(regKey)) {
+            return (Properties)registry.get(regKey);
+        }
+        return null;
+    }
+
+    public Properties getProperties() {
+        return settings;
+    }
+
+    @Override
+    public Properties  getProperties(String regKey,String fileName) {
+        return getProperties(regKey,fileName,false,"",false);
+    }
+
+    @Override
+    public Properties  getProperties(String regKey,String fileName,
+            boolean createFile, String header) {
+        return getProperties(regKey,fileName,false,"",false);
+    }
+
+    @Override
+    public Properties  getProperties(String regKey,
+                                     String fileName,
+                                     boolean createFile,
+                                     String header,
+                                     boolean reloadIfLoaded) {
+
+        if (!registry.containsKey(regKey) || reloadIfLoaded) {
+
+            FileInputStream in = null;
+            Properties props = new Properties();
+            headers.put(regKey, header);
+
+            try {
+                in = new FileInputStream(settingsDirectory()
+                        +  fileName);
+                props.load(in);
+
+            }
+            catch (FileNotFoundException fnfe) {
+
+                if (createFile) {
+                    Log.i(TAG," Information Message: " + fnfe.getMessage()
+                            + ".  The file " + fileName + " will"
+                            + " be created for first time use.");
+
+                    registry.put(regKey,props);
+
+                    saveSettings(regKey,header);
+
+                    return props;
+
+                }
+                else {
+
+                    Log.i(TAG," Information Message: " + fnfe.getMessage()
+                            + ".");
+
+                }
+            }
+            catch (IOException ioe) {
+                Log.w(TAG,"IO Exception accessing File "+ fileName +
+                        " for the following reason : "
+                        + ioe.getMessage());
+            }
+            catch (SecurityException se) {
+                Log.w(TAG,"Security Exception for file "+ fileName
+                        + ".  This file can not be accessed because : "
+                        + se.getMessage());
+            }
+
+            registry.put(regKey,props);
+
+            return props;
+        }
+        else {
+            return (Properties)registry.get(regKey);
+        }
+    }
+
+    /**
+     * Returns the setting from the given key of the global properties or the
+     * default passed if the property does not exist.
+     *
+     * @param key
+     * @param def
+     * @return
+     */
+    @Override
+    public String getProperty(String key, String def) {
+        if (settings.containsKey(key))
+            return settings.getProperty(key);
+        else
+            return def;
+    }
+
+    /**
+     * Returns the setting from the given key of the global properties.
+     *
+     * @param key
+     * @return
+     */
+    @Override
+    public String getProperty(String key) {
+        return settings.getProperty(key);
+    }
+
+    /**
+     * Private helper to return the full path to the settings file
+     *
+     * @return
+     */
+    private String settingsFile() {
+        return settingsDirectory() + "tn5250jstartup.cfg";
+
+    }
+
+    /**
+     * Private helper to return the settings directory
+     *
+     * @return
+     */
+    private String settingsDirectory() {
+        return settingsFolder() + File.separator;
+
+    }
+
+    /**
+     * Private helper to return the settings folder path
+     *
+     * @return
+     */
+    private String settingsFolder() {
+        return TerminalView.android_home_directory + File.separator + TN5250J_FOLDER;
+
+    }
+
+    /**
+     * Not sure yet so be careful using this.
+     *
+     * @return
+     */
+    public ClassLoader getClassLoader() {
+
+        ClassLoader loader = GlobalConfigure.class.getClassLoader();
+        if (loader == null)
+            loader = ClassLoader.getSystemClassLoader();
+
+        return loader;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/TN5250jConstants.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,530 @@
+/*
+ * @(#)TN5250jConstants.java
+ * Copyright:    Copyright (c) 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ *
+ */
+
+package org.tn5250j;
+
+public interface TN5250jConstants {
+
+   // Version information
+   public static final String tn5250jRelease = "0";
+   public static final String tn5250jVersion = ".7";
+   public static final String tn5250jSubVer= ".3";
+   
+   public static final String VERSION_INFO = tn5250jRelease + tn5250jVersion + tn5250jSubVer;
+
+   // STATE
+   static final int STATE_DISCONNECTED   =  0;
+   static final int STATE_CONNECTED   =  1;
+   static final int STATE_REMOVE   =  2;
+
+   // SESSION Level key value pairs
+   public static final String SESSION_HOST      = "SESSION_HOST";
+   public static final String SESSION_HOST_PORT ="SESSION_HOST_PORT";
+   public static final String SESSION_CONFIG_RESOURCE = "SESSION_CONFIG_RESOURCE";
+   public static final String SESSION_TYPE     = "SESSION_HOST_TYPE";
+   public static final String SESSION_TN_ENHANCED = "SESSION_TN_ENHANCED";
+   public static final String SESSION_SCREEN_SIZE = "SESSION_SCREEN_SIZE";
+   public static final String SESSION_CODE_PAGE = "SESSION_CODE_PAGE";
+   public static final String SESSION_PROXY_HOST = "SESSION_PROXY_HOST";
+   public static final String SESSION_PROXY_PORT = "SESSION_PROXY_PORT";
+   public static final String SESSION_USE_GUI = "SESSION_USE_GUI";
+   public static final String SESSION_DEVICE_NAME = "SESSION_DEVICE_NAME";
+   public static final String SESSION_NAMES_REFS = "SESSION_NAMES_REFS";
+   public static final String SESSION_LOCALE = "SESSION_LOCALE";
+   public static final String SESSION_CONFIG_FILE = "SESSION_CONFIG_FILE";
+   public static final String SESSION_TERM_NAME_SYSTEM = "SESSION_TERM_NAME_SYSTEM";
+   public static final String SESSION_TERM_NAME = "SESSION_TERM_NAME";
+   public static final String SESSION_IS_APPLET = "SESSION_IS_APPLET";
+   public static final String SESSION_HEART_BEAT = "SESSION_KEEP_ALIVE_ENABLED";
+
+//   public static final String GUI_MDI_TYPE = "GUI_MDI_TYPE";
+   public static final String GUI_FRAME_WIDTH = "GUI_FRAME_WIDTH";
+   public static final String GUI_FRAME_HEIGHT = "GUI_FRAME_HEIGHT";
+   public static final String GUI_NO_TAB = "GUI_NO_TAB";
+   public static final String NO_CHECK_RUNNING = "NO_CHECK_RUNNING";
+   public static final String START_MONITOR_THREAD = "START_MONITOR_THREAD";
+
+//   public static final String SSL_TYPE = "TN5250J_SSL_TYPE";
+   public static final String SSL_TYPE = "-sslType";
+   public static final String SSL_TYPE_NONE = "NONE";
+   public static final String SSL_TYPE_SSLv2 = "SSLv2";
+   public static final String SSL_TYPE_SSLv3 = "SSLv3";
+   public static final String SSL_TYPE_TLS = "TLS";
+
+   public static final String[] SSL_TYPES = {SSL_TYPE_NONE,
+                                             SSL_TYPE_SSLv2,
+                                             SSL_TYPE_SSLv3,
+                                             SSL_TYPE_TLS};
+
+   // Session JUMP Directions
+   static final int JUMP_PREVIOUS   =  0;
+   static final int JUMP_NEXT   =  1;
+
+//   // OS_OHIO_SESSION_TYPE type of sessions
+//   public static final String OS_OHIO_SESSION_TYPE_5250_STR   = "2";
+
+   // SCREEN_SIZE Size of screen string
+   public static final String SCREEN_SIZE_24X80_STR   = "0";
+   public static final String SCREEN_SIZE_27X132_STR   = "1";
+
+   // SCREEN_SIZE Size of screen int
+   public static final int SCREEN_SIZE_24X80   = 0;
+   public static final int SCREEN_SIZE_27X132   = 1;
+
+   public static final int NUM_PARMS = 20;
+
+   // mnemonic value constants
+   public static final int BACK_SPACE = 1001;
+   public static final int BACK_TAB  = 1002;
+   public static final int UP = 1003;
+   public static final int DOWN = 1004;
+   public static final int LEFT = 1005;
+   public static final int RIGHT = 1006;
+   public static final int DELETE = 1007;
+   public static final int TAB = 1008;
+   public static final int EOF = 1009;
+   public static final int ERASE_EOF = 1010;
+   public static final int ERASE_FIELD = 1011;
+   public static final int INSERT = 1012;
+   public static final int HOME = 1013;
+   public static final int KEYPAD_0 = 1014;
+   public static final int KEYPAD_1 = 1015;
+   public static final int KEYPAD_2 = 1016;
+   public static final int KEYPAD_3 = 1017;
+   public static final int KEYPAD_4 = 1018;
+   public static final int KEYPAD_5 = 1019;
+   public static final int KEYPAD_6 = 1020;
+   public static final int KEYPAD_7 = 1021;
+   public static final int KEYPAD_8 = 1022;
+   public static final int KEYPAD_9 = 1023;
+   public static final int KEYPAD_PERIOD = 1024;
+   public static final int KEYPAD_COMMA = 1025;
+   public static final int KEYPAD_MINUS = 1026;
+   public static final int FIELD_EXIT = 1027;
+   public static final int FIELD_PLUS = 1028;
+   public static final int FIELD_MINUS = 1029;
+   public static final int BOF = 1030;
+   public static final int SYSREQ = 1031;
+   public static final int RESET = 1032;
+   public static final int NEXTWORD = 1033;
+   public static final int PREVWORD = 1034;
+   public static final int COPY = 1035;
+   public static final int PASTE = 1036;
+   public static final int ATTN = 1037;
+   public static final int MARK_UP = 1038;
+   public static final int MARK_DOWN = 1039;
+   public static final int MARK_LEFT = 1040;
+   public static final int MARK_RIGHT = 1041;
+   public static final int DUP_FIELD = 1042;
+   public static final int NEW_LINE = 1043;
+   public static final int JUMP_NEXT_SESS = 5000;
+   public static final int JUMP_PREV_SESS = 5001;
+   public static final int OPEN_NEW = 5002;
+   public static final int TOGGLE_CONNECTION = 5003;
+   public static final int HOTSPOTS = 5004;
+   public static final int GUI = 5005;
+   public static final int DSP_MSGS = 5006;
+   public static final int DSP_ATTRIBUTES = 5007;
+   public static final int PRINT_SCREEN = 5008;
+   public static final int CURSOR = 5009;
+   public static final int DEBUG = 5010;
+   public static final int CLOSE = 5011;
+   public static final int TRANSFER = 5012;
+   public static final int E_MAIL = 5013;
+   public static final int RUN_SCRIPT = 5014;
+   public static final int SPOOL_FILE = 5015;
+   public static final int QUICK_MAIL = 5016;
+   public static final int OPEN_SAME = 5017;
+   public static final int FAST_CURSOR_DOWN = 5018;
+   public static final int FAST_CURSOR_UP = 5019;
+   public static final int FAST_CURSOR_RIGHT = 5020;
+   public static final int FAST_CURSOR_LEFT = 5021;
+
+   // PF Keys
+   public static final int PF1 = 0x31;
+   public static final int PF2 = 0x32;
+   public static final int PF3 = 0x33;
+   public static final int PF4 = 0x34;
+   public static final int PF5 = 0x35;
+   public static final int PF6 = 0x36;
+   public static final int PF7 = 0x37;
+   public static final int PF8 = 0x38;
+   public static final int PF9 = 0x39;
+   public static final int PF10 = 0x3A;
+   public static final int PF11 = 0x3B;
+   public static final int PF12 = 0x3C;
+   public static final int PF13 = 0xB1;
+   public static final int PF14 = 0xB2;
+   public static final int PF15 = 0xB3;
+   public static final int PF16 = 0xB4;
+   public static final int PF17 = 0xB5;
+   public static final int PF18 = 0xB6;
+   public static final int PF19 = 0xB7;
+   public static final int PF20 = 0xB8;
+   public static final int PF21 = 0xB9;
+   public static final int PF22 = 0xBA;
+   public static final int PF23 = 0xBB;
+   public static final int PF24 = 0xBC;
+
+   public static final String mnemonicData[] = {
+        "[backspace]", "[backtab]", "[up]", "[down]", "[left]",
+        "[right]", "[delete]", "[tab]", "[eof]", "[eraseeof]",
+        "[erasefld]", "[insert]", "[home]", "[keypad0]", "[keypad1]",
+        "[keypad2]", "[keypad3]", "[keypad4]", "[keypad5]", "[keypad6]",
+        "[keypad7]", "[keypad8]", "[keypad9]", "[keypad.]", "[keypad,]",
+        "[keypad-]", "[fldext]", "[field+]", "[field-]", "[bof]",
+        "[enter]","[pf1]","[pf2]","[pf3]","[pf4]",
+        "[pf5]","[pf6]","[pf7]","[pf8]","[pf9]",
+        "[pf10]","[pf11]","[pf12]","[pf13]","[pf14]",
+        "[pf15]","[pf16]","[pf17]","[pf18]","[pf19]",
+        "[pf20]","[pf21]","[pf22]","[pf23]","[pf24]",
+        "[clear]", "[help]", "[pgup]", "[pgdown]", "[rollleft]",
+        "[rollright]", "[hostprint]", "[pa1]", "[pa2]", "[pa3]",
+        "[sysreq]","[reset]","[nextword]", "[prevword]", "[copy]",
+        "[paste]","[attn]","[markup]", "[markdown]", "[markleft]",
+        "[markright]","[dupfield]","[newline]","[jumpnext]","[jumpprev]",
+        "[opennew]","[togcon]","[hotspots]","[gui]","[dspmsgs]",
+        "[dspattr]","[print]","[cursor]","[debug]","[close]",
+        "[transfer]","[e-mail]","[runscript]","[spoolfile]","[quick-mail]",
+        "[open-same]","[fastcursordown]","[fastcursorup]","[fastcursorright]","[fastcursorleft]"
+   };
+
+   public static final int mnemonicValue[] = {
+        1001, 1002, 1003, 1004, 1005,
+        1006, 1007, 1008, 1009, 1010,
+        1011, 1012, 1013, 1014, 1015,
+        1016, 1017, 1018, 1019, 1020,
+        1021, 1022, 1023, 1024, 1025,
+        1026, 1027, 1028, 1029, 1030,
+        0xF1, 0x31, 0x32, 0x33, 0x34,
+        0x35, 0x36, 0x37, 0x38, 0x39,
+        0x3A, 0x3B, 0x3C, 0xB1, 0xB2,
+        0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+        0xB8, 0xB9, 0xBA, 0xBB, 0xBC,
+        0xBD, 0xF3, 0xF4, 0xF5, 0xD9,
+        0xDA, 0xF6, 0x6C, 0x6E, 0x6B,
+        1031, 1032, 1033, 1034, 1035,
+        1036, 1037, 1038, 1039, 1040,
+        1041, 1042, 1043, 5000, 5001,
+        5002, 5003, 5004, 5005, 5006,
+        5007, 5008, 5009, 5010, 5011,
+        5012, 5013, 5014, 5015, 5016,
+        5017, 5018, 5019, 5020, 5021
+   };
+
+   public static final String MNEMONIC_CLEAR   =  "[clear]";
+   public static final String MNEMONIC_ENTER   =  "[enter]";
+   public static final String MNEMONIC_HELP   =  "[help]";
+   public static final String MNEMONIC_PAGE_DOWN   =  "[pgdown]";
+   public static final String MNEMONIC_PAGE_UP   =  "[pgup]";
+   public static final String MNEMONIC_PRINT   =  "[hostprint]";
+   public static final String MNEMONIC_PF1   =  "[pf1]";
+   public static final String MNEMONIC_PF2   =  "[pf2]";
+   public static final String MNEMONIC_PF3   =  "[pf3]";
+   public static final String MNEMONIC_PF4   =  "[pf4]";
+   public static final String MNEMONIC_PF5   =  "[pf5]";
+   public static final String MNEMONIC_PF6   =  "[pf6]";
+   public static final String MNEMONIC_PF7   =  "[pf7]";
+   public static final String MNEMONIC_PF8   =  "[pf8]";
+   public static final String MNEMONIC_PF9   =  "[pf9]";
+   public static final String MNEMONIC_PF10   =  "[pf10]";
+   public static final String MNEMONIC_PF11   =  "[pf11]";
+   public static final String MNEMONIC_PF12   =  "[pf12]";
+   public static final String MNEMONIC_PF13   =  "[pf13]";
+   public static final String MNEMONIC_PF14   =  "[pf14]";
+   public static final String MNEMONIC_PF15   =  "[pf15]";
+   public static final String MNEMONIC_PF16   =  "[pf16]";
+   public static final String MNEMONIC_PF17   =  "[pf17]";
+   public static final String MNEMONIC_PF18   =  "[pf18]";
+   public static final String MNEMONIC_PF19   =  "[pf19]";
+   public static final String MNEMONIC_PF20   =  "[pf20]";
+   public static final String MNEMONIC_PF21   =  "[pf21]";
+   public static final String MNEMONIC_PF22   =  "[pf22]";
+   public static final String MNEMONIC_PF23   =  "[pf23]";
+   public static final String MNEMONIC_PF24   =  "[pf24]";
+   public static final String MNEMONIC_BACK_SPACE   =  "[backspace]";
+   public static final String MNEMONIC_BACK_TAB   =  "[backtab]";
+   public static final String MNEMONIC_UP   =  "[up]";
+   public static final String MNEMONIC_DOWN   =  "[down]";
+   public static final String MNEMONIC_LEFT   =  "[left]";
+   public static final String MNEMONIC_RIGHT   =  "[right]";
+   public static final String MNEMONIC_DELETE   =  "[delete]";
+   public static final String MNEMONIC_TAB =  "[tab]";
+   public static final String MNEMONIC_END_OF_FIELD   =  "[eof]";
+   public static final String MNEMONIC_ERASE_EOF   =  "[eraseeof]";
+   public static final String MNEMONIC_ERASE_FIELD   =  "[erasefld]";
+   public static final String MNEMONIC_INSERT   =  "[insert]";
+   public static final String MNEMONIC_HOME   =  "[home]";
+   public static final String MNEMONIC_KEYPAD0   =  "[keypad0]";
+   public static final String MNEMONIC_KEYPAD1   =  "[keypad1]";
+   public static final String MNEMONIC_KEYPAD2   =  "[keypad2]";
+   public static final String MNEMONIC_KEYPAD3   =  "[keypad3]";
+   public static final String MNEMONIC_KEYPAD4   =  "[keypad4]";
+   public static final String MNEMONIC_KEYPAD5   =  "[keypad5]";
+   public static final String MNEMONIC_KEYPAD6   =  "[keypad6]";
+   public static final String MNEMONIC_KEYPAD7   =  "[keypad7]";
+   public static final String MNEMONIC_KEYPAD8   =  "[keypad8]";
+   public static final String MNEMONIC_KEYPAD9   =  "[keypad9]";
+   public static final String MNEMONIC_KEYPAD_PERIOD   =  "[keypad.]";
+   public static final String MNEMONIC_KEYPAD_COMMA   =  "[keypad,]";
+   public static final String MNEMONIC_KEYPAD_MINUS   =  "[keypad-]";
+   public static final String MNEMONIC_FIELD_EXIT   =  "[fldext]";
+   public static final String MNEMONIC_FIELD_PLUS   =  "[field+]";
+   public static final String MNEMONIC_FIELD_MINUS   =  "[field-]";
+   public static final String MNEMONIC_BEGIN_OF_FIELD   =  "[bof]";
+   public static final String MNEMONIC_PA1   =  "[pa1]";
+   public static final String MNEMONIC_PA2   =  "[pa2]";
+   public static final String MNEMONIC_PA3   =  "[pa3]";
+   public static final String MNEMONIC_SYSREQ   =  "[sysreq]";
+   public static final String MNEMONIC_RESET   =  "[reset]";
+   public static final String MNEMONIC_NEXTWORD   =  "[nextword]";
+   public static final String MNEMONIC_PREVWORD   =  "[prevword]";
+   public static final String MNEMONIC_ATTN   =  "[attn]";
+   public static final String MNEMONIC_MARK_LEFT   =  "[markleft]";
+   public static final String MNEMONIC_MARK_RIGHT   =  "[markright]";
+   public static final String MNEMONIC_MARK_UP   =  "[markup]";
+   public static final String MNEMONIC_MARK_DOWN   =  "[markdown]";
+   public static final String MNEMONIC_DUP_FIELD   =  "[dupfield]";
+   public static final String MNEMONIC_NEW_LINE   =  "[newline]";
+   public static final String MNEMONIC_JUMP_NEXT   =  "[jumpnext]";
+   public static final String MNEMONIC_JUMP_PREV   =  "[jumpprev]";
+   public static final String MNEMONIC_OPEN_NEW   =  "[opennew]";
+   public static final String MNEMONIC_TOGGLE_CONNECTION   =  "[togcon]";
+   public static final String MNEMONIC_HOTSPOTS   =  "[hotspots]";
+   public static final String MNEMONIC_GUI   =  "[gui]";
+   public static final String MNEMONIC_DISP_MESSAGES   =  "[dspmsgs]";
+   public static final String MNEMONIC_DISP_ATTRIBUTES   =  "[dspattr]";
+   public static final String MNEMONIC_PRINT_SCREEN   =  "[print]";
+   public static final String MNEMONIC_CURSOR   =  "[cursor]";
+   public static final String MNEMONIC_DEBUG   =  "[debug]";
+   public static final String MNEMONIC_CLOSE   =  "[close]";
+   public static final String MNEMONIC_E_MAIL   =  "[e-mail]";
+   public static final String MNEMONIC_COPY   =  "[copy]";
+   public static final String MNEMONIC_PASTE   =  "[paste]";
+   public static final String MNEMONIC_FILE_TRANSFER   =  "[transfer]";
+   public static final String MNEMONIC_RUN_SCRIPT   =  "[runscript]";
+   public static final String MNEMONIC_SPOOL_FILE   =  "[spoolfile]";
+   public static final String MNEMONIC_QUICK_MAIL   =  "[quick-mail]";
+   public static final String MNEMONIC_OPEN_SAME   =  "[open-same]";
+   public static final String MNEMONIC_FAST_CURSOR_DOWN   =  "[fastcursordown]";
+   public static final String MNEMONIC_FAST_CURSOR_UP   =  "[fastcursorup]";
+   public static final String MNEMONIC_FAST_CURSOR_RIGHT   =  "[fastcursorright]";
+   public static final String MNEMONIC_FAST_CURSOR_LEFT   =  "[fastcursorleft]";
+
+   // AID-Generating Keys
+   public static final int AID_CLEAR = 0xBD;
+   public static final int AID_ENTER = 0xF1;
+   public static final int AID_HELP = 0xF3;
+   public static final int AID_ROLL_UP = 0xF4;
+   public static final int AID_ROLL_DOWN = 0xF5;
+   public static final int AID_ROLL_LEFT = 0xD9;
+   public static final int AID_ROLL_RIGHT = 0xDA;
+   public static final int AID_PRINT = 0xF6;
+   public static final int AID_PF1 = 0x31;
+   public static final int AID_PF2 = 0x32;
+   public static final int AID_PF3 = 0x33;
+   public static final int AID_PF4 = 0x34;
+   public static final int AID_PF5 = 0x35;
+   public static final int AID_PF6 = 0x36;
+   public static final int AID_PF7 = 0x37;
+   public static final int AID_PF8 = 0x38;
+   public static final int AID_PF9 = 0x39;
+   public static final int AID_PF10 = 0x3A;
+   public static final int AID_PF11 = 0x3B;
+   public static final int AID_PF12 = 0x3C;
+   public static final int AID_PF13 = 0xB1;
+   public static final int AID_PF14 = 0xB2;
+   public static final int AID_PF15 = 0xB3;
+   public static final int AID_PF16 = 0xB4;
+   public static final int AID_PF17 = 0xB5;
+   public static final int AID_PF18 = 0xB6;
+   public static final int AID_PF19 = 0xB7;
+   public static final int AID_PF20 = 0xB8;
+   public static final int AID_PF21 = 0xB9;
+   public static final int AID_PF22 = 0xBA;
+   public static final int AID_PF23 = 0xBB;
+   public static final int AID_PF24 = 0xBC;
+
+   // negative response categories
+   public static final int NR_REQUEST_REJECT = 0x08;
+   public static final int NR_REQUEST_ERROR = 0x10;
+   public static final int NR_STATE_ERROR = 0x20;
+   public static final int NR_USAGE_ERROR = 0x40;
+   public static final int NR_PATH_ERROR = 0x80;
+
+   // commands
+   public static final byte CMD_WRITE_TO_DISPLAY = 0x11; // 17
+   public static final byte CMD_CLEAR_UNIT = 0x40; // 64
+   public static final byte CMD_CLEAR_UNIT_ALTERNATE = 0x20; // 32
+   public static final byte CMD_CLEAR_FORMAT_TABLE = 0x50; // 80
+   public static final byte CMD_READ_INPUT_FIELDS = 0x42; // 66
+   public static final byte CMD_READ_MDT_FIELDS = 0x52; // 82
+   public static final byte CMD_READ_MDT_IMMEDIATE_ALT = (byte)0x83; // 131
+//   public static final byte CMD_READ_MDT_FIELDS_ALT = (byte)0x82; // 130
+//   public static final byte CMD_READ_IMMEDIATE = 0x72; // 114
+   public static final byte CMD_READ_SCREEN_IMMEDIATE = 0x62; // 98
+   public static final byte CMD_WRITE_STRUCTURED_FIELD = (byte)243;  // (byte)0xF3 -13
+   public static final byte CMD_SAVE_SCREEN = 0x02; // 02
+   public static final byte CMD_RESTORE_SCREEN = 0x12; // 18
+   public static final byte CMD_WRITE_ERROR_CODE = 0x21; // 33
+   public static final byte CMD_WRITE_ERROR_CODE_TO_WINDOW = 0x22; // 34
+   public static final byte CMD_ROLL = 0x23; // 35
+   public static final byte CMD_READ_SCREEN_TO_PRINT = (byte)0x66; // 102
+
+   // PLANES
+   public static final int PLANE_TEXT   =  1;
+   public static final int PLANE_COLOR   =  2;
+   public static final int PLANE_FIELD   =  3;
+   public static final int PLANE_EXTENDED   =  4;
+   public static final int PLANE_EXTENDED_GRAPHIC   =  5;
+   public static final int PLANE_EXTENDED_FIELD   =  6;
+   public static final int PLANE_ATTR   =  7;
+   public static final int PLANE_IS_ATTR_PLACE   =  8;
+
+   // COLOR_BG
+   public static final char COLOR_BG_BLACK   =  0;
+   public static final char COLOR_BG_BLUE    =  1;
+   public static final char COLOR_BG_GREEN   =  2;
+   public static final char COLOR_BG_CYAN    =  3;
+   public static final char COLOR_BG_RED     =  4;
+   public static final char COLOR_BG_MAGENTA =  5;
+   public static final char COLOR_BG_YELLOW  =  6;
+   public static final char COLOR_BG_WHITE   =  7;
+
+   // COLOR_FG
+   public static final char COLOR_FG_BLACK         =  0;
+   public static final char COLOR_FG_BLUE          =  1;
+   public static final char COLOR_FG_GREEN         =  2;
+   public static final char COLOR_FG_CYAN          =  3;
+   public static final char COLOR_FG_RED           =  4;
+   public static final char COLOR_FG_MAGENTA       =  5;
+   public static final char COLOR_FG_YELLOW        =  6;
+   public static final char COLOR_FG_WHITE         =  7;
+   public static final char COLOR_FG_GRAY          =  8;
+   public static final char COLOR_FG_LIGHT_BLUE    =  9;
+   public static final char COLOR_FG_LIGHT_GREEN   =  0xA;
+   public static final char COLOR_FG_LIGHT_CYAN    =  0xB;
+   public static final char COLOR_FG_LIGHT_RED     =  0xC;
+   public static final char COLOR_FG_LIGHT_MAGENTA =  0xD;
+   public static final char COLOR_FG_BROWN         =  0xE;
+   public static final char COLOR_FG_WHITE_HIGH    =  0xF;
+                                                  
+   public static final int EXTENDED_5250_REVERSE   =  0x10;
+   public static final int EXTENDED_5250_UNDERLINE   =  0x08;
+   public static final int EXTENDED_5250_BLINK   =  0x04;
+   public static final int EXTENDED_5250_COL_SEP   =  0x02;
+   public static final int EXTENDED_5250_NON_DSP   =  0x01;
+
+   public static final char ATTR_32 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_GREEN & 0xff);
+   public static final char ATTR_33 = (COLOR_BG_GREEN << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_34 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_WHITE & 0xff);
+   public static final char ATTR_35 = (COLOR_BG_WHITE << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_36 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_GREEN & 0xff);
+   public static final char ATTR_37 = (COLOR_BG_GREEN << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_38 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_WHITE & 0xff);
+   public static final char ATTR_40 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_RED & 0xff);
+   public static final char ATTR_41 = (COLOR_BG_RED << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_42 = (COLOR_BG_BLACK << 8 & 0xff00) |
+														(COLOR_FG_RED & 0xff);
+   public static final char ATTR_43 = (COLOR_BG_RED << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+
+   public static final char ATTR_44 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_RED & 0xff);
+   public static final char ATTR_45 = ( COLOR_BG_RED << 8 & 0xff00) |
+   													( COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_46 = (COLOR_BG_BLACK << 8 & 0xff00) |
+														(COLOR_FG_RED & 0xff);
+
+   public static final char ATTR_48 = (COLOR_BG_BLACK << 8 & 0xff00) |
+      												(COLOR_FG_CYAN & 0xff);
+   public static final char ATTR_49 = (COLOR_BG_CYAN << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_50 = (COLOR_BG_BLACK << 8 & 0xff00) |
+   													(COLOR_FG_YELLOW & 0xff);
+
+   public static final char ATTR_51 = (COLOR_BG_YELLOW << 8 & 0xff00) |
+   													(COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_52 = ( COLOR_BG_BLACK << 8 & 0xff00) |
+   													( COLOR_FG_CYAN & 0xff);
+   public static final char ATTR_53 = ( COLOR_BG_CYAN << 8 & 0xff00) |
+   													( COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_54 = ( COLOR_BG_BLACK << 8 & 0xff00) |
+   													( COLOR_FG_YELLOW & 0xff);
+   public static final char ATTR_56 = ( COLOR_BG_BLACK << 8 & 0xff00) |
+   													( COLOR_FG_MAGENTA & 0xff);
+   public static final char ATTR_57 = ( COLOR_BG_MAGENTA << 8 & 0xff00) |
+   													( COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_58 = ( COLOR_BG_BLACK << 8 & 0xff00) |
+   													( COLOR_FG_BLUE & 0xff);
+   public static final char ATTR_59 = ( COLOR_BG_BLUE << 8 & 0xff00) |
+   													( COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_60 = ( COLOR_BG_BLACK << 8 & 0xff00) |
+   													( COLOR_FG_MAGENTA & 0xff);
+   public static final char ATTR_61 = ( COLOR_BG_MAGENTA << 8 & 0xff00) |
+   													( COLOR_FG_BLACK & 0xff);
+   public static final char ATTR_62 = ( COLOR_BG_BLACK << 8 & 0xff00) |
+   													( COLOR_FG_BLUE & 0xff);
+
+   public static final int NO_GUI = 0;
+   public static final int UPPER_LEFT = 1;
+   public static final int UPPER = 2;
+   public static final int UPPER_RIGHT = 3;
+   public static final int GUI_LEFT = 4;
+   public static final int GUI_RIGHT = 5;
+   public static final int LOWER_LEFT = 6;
+   public static final int BOTTOM = 7;
+   public static final int LOWER_RIGHT = 8;
+   public static final int FIELD_LEFT = 9;
+   public static final int FIELD_RIGHT = 10;
+   public static final int FIELD_MIDDLE = 11;
+   public static final int FIELD_ONE = 12;
+   public static final int BUTTON_LEFT = 13;
+   public static final int BUTTON_RIGHT = 14;
+   public static final int BUTTON_MIDDLE = 15;
+   public static final int BUTTON_ONE = 16;
+   public static final int BUTTON_LEFT_UP = 17;
+   public static final int BUTTON_RIGHT_UP = 18;
+   public static final int BUTTON_MIDDLE_UP = 19;
+   public static final int BUTTON_ONE_UP = 20;
+   public static final int BUTTON_LEFT_DN = 21;
+   public static final int BUTTON_RIGHT_DN = 22;
+   public static final int BUTTON_MIDDLE_DN = 23;
+   public static final int BUTTON_ONE_DN = 24;
+   public static final int BUTTON_LEFT_EB = 25;
+   public static final int BUTTON_RIGHT_EB = 26;
+   public static final int BUTTON_MIDDLE_EB = 27;
+   public static final int BUTTON_SB_UP = 28;
+   public static final int BUTTON_SB_DN = 29;
+   public static final int BUTTON_SB_GUIDE = 30;
+   public static final int BUTTON_SB_THUMB = 31;
+   public static final int BUTTON_LAST = 31;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/encoding/AbstractCodePage.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,45 @@
+/**
+ * Title: CodePage.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;
+
+/**
+ *
+ * This class controls the translation from EBCDIC to ASCII and ASCII to EBCDIC
+ *
+ */
+public abstract class AbstractCodePage implements ICodePage {
+
+	protected AbstractCodePage(String encoding) {
+		this.encoding = encoding;
+	}
+
+	public String getEncoding() {
+		return encoding;
+	}
+
+	protected String encoding;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/encoding/BuiltInCodePageFactory.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,149 @@
+/**
+ * $Id$
+ *
+ * Title: tn5250J
+ * Copyright:   Copyright (c) 2001,2012
+ * 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;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.tn5250j.encoding.builtin.CCSID1025;
+import org.tn5250j.encoding.builtin.CCSID1026;
+import org.tn5250j.encoding.builtin.CCSID1112;
+import org.tn5250j.encoding.builtin.CCSID1140;
+import org.tn5250j.encoding.builtin.CCSID1141;
+import org.tn5250j.encoding.builtin.CCSID1147;
+import org.tn5250j.encoding.builtin.CCSID1148;
+import org.tn5250j.encoding.builtin.CCSID273;
+import org.tn5250j.encoding.builtin.CCSID277;
+import org.tn5250j.encoding.builtin.CCSID278;
+import org.tn5250j.encoding.builtin.CCSID280;
+import org.tn5250j.encoding.builtin.CCSID284;
+import org.tn5250j.encoding.builtin.CCSID285;
+import org.tn5250j.encoding.builtin.CCSID297;
+import org.tn5250j.encoding.builtin.CCSID37;
+import org.tn5250j.encoding.builtin.CCSID424;
+import org.tn5250j.encoding.builtin.CCSID500;
+import org.tn5250j.encoding.builtin.CCSID870;
+import org.tn5250j.encoding.builtin.CCSID871;
+import org.tn5250j.encoding.builtin.CCSID875;
+import org.tn5250j.encoding.builtin.ICodepageConverter;
+import android.util.Log;
+
+
+/**
+ * Methods for built-in code page support.
+ */
+class BuiltInCodePageFactory {
+    private static final String TAG = "BuiltInCodePageFactory";
+	private static BuiltInCodePageFactory singleton;
+
+	private final List<Class<?>> clazzes = new ArrayList<Class<?>>();
+
+
+	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<String> cpset = new HashSet<String>();
+		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;
+		}
+	}
+
+}
--- /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<String,ICodePage> map = new HashMap<String, ICodePage>();
+
+	public static String[] getAvailableCodePages() {
+		Set<String> cpset = new HashSet<String>(); // 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);
+	}
+
+}
--- /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);
+
+}
--- /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
--- /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
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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;
+	}
+}
--- /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; i<codepage.length; i++) {
+			size = Math.max(size, codepage[i]);
+		}
+		assert (size + 1) < 1024*1024; // some kind of maximum size limiter.
+		reverse_codepage = new int[size+1];
+		Arrays.fill(reverse_codepage, '?');
+		for (int i=0; i<codepage.length; i++) {
+			reverse_codepage[codepage[i]] = i;
+		}
+		return this;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.tn5250j.cp.ICodepageConverter#uni2ebcdic(char)
+	 */
+	public byte uni2ebcdic(char index) {
+		assert index < reverse_codepage.length;
+		return (byte)reverse_codepage[index];
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.tn5250j.cp.ICodepageConverter#ebcdic2uni(int)
+	 */
+	public char ebcdic2uni(int index) {
+		index = index & 0xFF;
+		assert index < 256;
+		return codepage[index];
+	}
+
+	/**
+	 * @return The oringal 8bit codepage. 
+	 */
+	protected abstract char[] getCodePage();
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/encoding/builtin/ICodepageConverter.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,34 @@
+package org.tn5250j.encoding.builtin;
+
+import org.tn5250j.encoding.ICodePage;
+
+/**
+ * Interface for classes which do the translation from
+ * EBCDIC bytes to Unicode characters and vice versa.
+ * 
+ */
+public interface ICodepageConverter extends ICodePage {
+
+	/**
+	 * Returns an name/ID for this converter.
+	 * Example '273' or 'CP1252'. This name should be unique,
+	 * cause it's used in user settungs and so on.
+	 * 
+	 * @return
+	 */
+	public abstract String getName();
+	
+	/**
+	 * Returns a short description for this converter.
+	 * For Example '273 - German, EBCDIC'
+	 * 
+	 * @return
+	 */
+	public abstract String getDescription();
+		
+	/**
+	 * Does special initialization stuff for this converter.
+	 */
+	public abstract ICodepageConverter init();
+	
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/event/ScreenOIAListener.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,45 @@
+/**
+ *
+ * <p>Title: ScreenOIAListener</p>
+ * <p>Description: Main interface to draw the graphical image of the screen</p>
+ * <p>Copyright: Copyright (c) 2000 - 2002</p>
+ * <p>
+ * 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
+ * </p>
+ * @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);
+
+}
--- /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<Object> 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<Object> 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
--- /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 <a href="http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=/nls/rbagsnatlangkeybrdtype.htm">National language keyboard types and SBCS code pages</a>
+ */
+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 + "]";
+	}
+
+}
--- /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
--- /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;
+	}
+
+}
--- /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<Double> 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<Double> sumVector = new Vector<Double>();
+
+        // 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:
+     *
+     * <table BORDER COLS=2 WIDTH="50%" >
+     *
+     * <tr>
+     * <td>MNEMONIC_CLEAR</td>
+     * <td>[clear]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_ENTER</td>
+     * <td>[enter]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_HELP</td>
+     * <td>[help]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PAGE_DOWN</td>
+     * <td>[pgdown]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PAGE_UP</td>
+     * <td>[pgup]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PRINT</td>
+     * <td>[print]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF1</td>
+     * <td>[pf1]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF2</td>
+     * <td>[pf2]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF3</td>
+     * <td>[pf3]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF4</td>
+     * <td>[pf4]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF5</td>
+     * <td>[pf5]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF6</td>
+     * <td>[pf6]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF7</td>
+     * <td>[pf7]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF8</td>
+     * <td>[pf8]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF9</td>
+     * <td>[pf9]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF10</td>
+     * <td>[pf10]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF11</td>
+     * <td>[pf11]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF12</td>
+     * <td>[pf12]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF13</td>
+     * <td>[pf13]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF14</td>
+     * <td>[pf14]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF15</td>
+     * <td>[pf15]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF16</td>
+     * <td>[pf16]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF17</td>
+     * <td>[pf17]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF18</td>
+     * <td>[pf18]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF19</td>
+     * <td>[pf19]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF20</td>
+     * <td>[pf20]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF21</td>
+     * <td>[pf21]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF22</td>
+     * <td>[pf22]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF23</td>
+     * <td>[pf23]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PF24</td>
+     * <td>[pf24]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_BACK_SPACE</td>
+     * <td>[backspace]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_BACK_TAB</td>
+     * <td>[backtab]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_UP</td>
+     * <td>[up]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_DOWN</td>
+     * <td>[down]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_LEFT</td>
+     * <td>[left]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_RIGHT</td>
+     * <td>[right]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_DELETE</td>
+     * <td>[delete]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_TAB</td>
+     * <td>"[tab]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_END_OF_FIELD</td>
+     * <td>[eof]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_ERASE_EOF</td>
+     * <td>[eraseeof]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_ERASE_FIELD</td>
+     * <td>[erasefld]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_INSERT</td>
+     * <td>[insert]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_HOME</td>
+     * <td>[home]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD0</td>
+     * <td>[keypad0]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD1</td>
+     * <td>[keypad1]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD2</td>
+     * <td>[keypad2]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD3</td>
+     * <td>[keypad3]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD4</td>
+     * <td>[keypad4]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD5</td>
+     * <td>[keypad5]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD6</td>
+     * <td>[keypad6]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD7</td>
+     * <td>[keypad7]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD8</td>
+     * <td>[keypad8]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD9</td>
+     * <td>[keypad9]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD_PERIOD</td>
+     * <td>[keypad.]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD_COMMA</td>
+     * <td>[keypad,]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_KEYPAD_MINUS</td>
+     * <td>[keypad-]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_FIELD_EXIT</td>
+     * <td>[fldext]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_FIELD_PLUS</td>
+     * <td>[field+]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_FIELD_MINUS</td>
+     * <td>[field-]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_BEGIN_OF_FIELD</td>
+     * <td>[bof]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PA1</td>
+     * <td>[pa1]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PA2</td>
+     * <td>[pa2]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_PA3</td>
+     * <td>[pa3]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_SYSREQ</td>
+     * <td>[sysreq]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_RESET</td>
+     * <td>[reset]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_ATTN</td>
+     * <td>[attn]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_MARK_LEFT</td>
+     * <td>[markleft]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_MARK_RIGHT</td>
+     * <td>[markright]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_MARK_UP</td>
+     * <td>[markup]</td>
+     * </tr>
+     * <tr>
+     * <td>MNEMONIC_MARK_DOWN</td>
+     * <td>[markdown]</td>
+     * </tr>
+     *
+     * </table>
+     *
+     * @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
+     * <p>
+     *
+     * 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
+     * <p>
+     *
+     * 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.
+     * <p>
+     * 0000: 00 50 73 1D 89 81 00 50 DA 44 C8 45 08 00 45 00 .Ps....P.D.E..E.
+     * </p>
+     * <p>
+     * 0010: 00 36 E9 1C 40 00 80 06 9B F9 C1 A8 33 58 C0 A8 .6..@...k....3X..
+     * </p>
+     * <p>
+     * 0020: C0 02 06 0E 00 17 00 52 6E 88 73 40 DE CB 50 18 .......Rn.s@..P.
+     * </p>
+     * <p>
+     * 0030: 20 12 3C 53 00 00 00 0C 12 A0 00 00 04 01 00 00 . <S............
+     * </p>
+     * <p>
+     * 0040: 00 05 FF EF .... ----------|| The 00 XX is the code to be sent. I
+     * found the following <table BORDER COLS=2 WIDTH="50%" >
+     * <tr>
+     * <td>ERR_CURSOR_PROTECTED</td>
+     * <td>0x05</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_INVALID_SIGN</td>
+     * <td>0x11</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_NO_ROOM_INSERT</td>
+     * <td>0x12</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_NUMERIC_ONLY</td>
+     * <td>0x09</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_NUMERIC_09</td>
+     * <td>0x10</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_FIELD_MINUS</td>
+     * <td>0x16</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_ENTER_NOT_ALLOWED</td>
+     * <td>0x20</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_MANDITORY_ENTER</td>
+     * <td>0x21</td>
+     * </tr>
+     * <tr>
+     * <td>ERR_ENTER_NOT_ALLOWED</td>
+     * <td>0x20</td>
+     * </tr>
+     * </table> I am tired of typing and they should be self explanitory. Finding
+     * them in the first place was the pain.
+     * </p>
+     *
+     * @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;
+        }
+
+    }
+
+    /**
+     * <p>
+     *  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.
+     *  </p>
+     *  <p>
+     *  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.
+     *  <p>
+     *
+     * @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);
+
+    }
+
+    /**
+     * <p>
+     *  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.
+     * </p>
+     * <p>
+     * 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.
+     * </p>
+     *
+     * @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);
+    }
+
+    /**
+     * <p>
+     *  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.
+     *  </p>
+     *  <p>
+     *  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.
+     *  </p>
+     *
+     * @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);
+    }
+
+    /**
+     * <p>
+     *  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.
+     *  </p>
+     *
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * 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.
+     * </p>
+     *
+     * @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);
+
+    }
+
+    /**
+     * <p>
+     *  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.
+     * </p>
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * 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.
+     * </p>
+     *
+     * @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;
+    }
+
+}
--- /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
--- /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:
+    *
+    * <table BORDER COLS=3 WIDTH="50%" >
+    * <tr><th>Constant </th><th>Value</th>
+    *                            <th>Description</th></tr>
+    * <tr><td>OS_OHIO_DIRECTION_FORWARD </td><td>0</td>
+    *                            <td>Forward (beginning towards end)</td></tr>
+    * <tr><td>OS_OHIO_DIRECTION_BACKWARD </td><td>1</td>
+    *                            <td>Backward (end towards beginning)</td></tr>
+    * </table>
+    *       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
--- /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 @@
+/**
+ * <p>Title: ScreenOIA.java</p>
+ * <p>Description: Main interface to control Operator information area screen</p>
+ * <p>Copyright: Copyright (c) 2000 - 2002</p>
+ * <p>
+ * 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
+ * </p>
+ * @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<ScreenOIAListener>(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<ScreenOIAListener> 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;
+
+}
--- /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;
+
+	}
+
+
+	/**
+	 * <p>
+	 *  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.
+	 *  </p>
+	 *  <p>
+	 *  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.
+	 *  <p>
+	 *
+	 * @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);
+
+	}
+
+	/**
+	 * <p>
+	 *  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.
+	 * </p>
+	 * <p>
+	 * 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.
+	 * </p>
+	 *
+	 * @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;
+	}
+
+	/**
+	 * <p>
+	 *  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.
+	 *  </p>
+	 *  <p>
+	 *  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.
+	 *  </p>
+	 *
+	 * @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);
+	}
+
+	/**
+	 * <p>
+	 *  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.
+	 *  </p>
+	 *
+	 * <p>
+	 * 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.
+	 * </p>
+	 * <p>
+	 * 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.
+	 * </p>
+	 *
+	 * @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);
+
+	}
+
+	/**
+	 * <p>
+	 *  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.
+	 * </p>
+	 * <p>
+	 * 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.
+	 * </p>
+	 * <p>
+	 * 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.
+	 * </p>
+	 *
+	 * @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
--- /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;
+
+   }
+
+}
--- /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<Window> guiStructs = new ArrayList<Window>(3);
+   private final List<ChoiceField> choices = new ArrayList<ChoiceField>(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  .<O.@.......3X..
+//0020   33 01 09 e4 00 17 5b bf b7 a4 c3 41 43 d1 50 18  3.....[....AC.P.
+//0030   fc de e9 d8 00 00 00 12 12 a0 00 00 04 00 80 03  ................
+//0040   16 18 f1 11 14 1a 00 22 ff ef                    ......."..
+
+         int colAvail = 0x20;
+         int colSelAvail = 0x20;
+         int fld = 0;
+
+         do {
+            minLen = segment[pos++];    // Minor Length byte 21
+
+            int minType = segment[pos++];    // Minor Type
+
+            switch (minType) {
+
+               case 0x01:  // Choice Presentation Display
+
+                  // flag
+                  int flagCP1 = segment[pos++];
+
+                  pos++; // mon select cursor avail emphasis - byte4
+                  colSelAvail = segment[pos++];  // -byte 5
+
+                  pos++; // mon select cursor - byte 6
+                  int colSelCur = segment[pos++];  // -byte 7
+
+                  pos++; // mon select cursor not avail emphasis - byte 8
+                  int colSelNotAvail = segment[pos++];  // -byte 9
+
+                  pos++; // mon avail emphasis - byte 10
+                  colAvail = segment[pos++];  // -byte 11
+
+                  pos++; // mon select emphasis - byte 12
+                  int colSel = segment[pos++];  // -byte 13
+
+                  pos++; // mon not avail emphasis - byte 14
+                  int colNotAvail = segment[pos++];  // -byte 15
+
+                  pos++; // mon indicator emphasis - byte 16
+                  int colInd = segment[pos++];  // -byte 17
+
+                  pos++; // mon indicator not avail emphasis - byte 18
+                  int colNotAvailInd = segment[pos++];  // -byte 19
+
+                  break;
+
+               case 0x10:  // Choice Text minor structure
+
+                  cnt = 5;
+                  int flagCT1 = segment[pos++];
+                  int flagCT2 = segment[pos++];
+                  int flagCT3 = segment[pos++];
+                  int mnemOffset = 0;
+                  boolean aid = false;
+                  boolean selected = false;
+
+                  // is in selected state
+                  if ((flagCT1 & 0x40) == 0x40) {
+                	  Log.d(TAG," selected ");
+                     selected = true;
+                  }
+
+                  //System.out.println(Integer.toBinaryString((flagCT1 & 0xf0)));
+                  // is mnemonic offset specified
+                  if ((flagCT1 & 0x08) == 8) {
+                	 Log.d(TAG," mnemOffset " + mnemOffset);
+                     mnemOffset = segment[pos++];
+                     cnt++;
+                  }
+
+                  // is aid key specified
+                  if ((flagCT1 & 0x04) == 4) {
+
+                     aid = true;
+                     Log.d(TAG," aidKey " + aid);
+//                     cnt++;
+                  }
+
+                  // is single digit number specified
+                  if ((flagCT1 & 0x01) == 0x01) {
+                	 Log.d(TAG," single digit " );
+                     pos++;
+                     cnt++;
+                  }
+
+                  // is double digint number specified
+                  if ((flagCT1 & 0x02) == 0x02) {
+                	 Log.d(TAG," double digit " );
+
+                     pos++;
+                     cnt++;
+                  }
+
+                  String s = "";
+                  byte byte0 = 0;
+                  fld++;
+
+                  screen52.setCursor(chcRowStart,chcColStart);
+
+                  // we do not add a selection if it is marked as unavailable
+                  if ((flagCT1 & 0x80) != 0x80) {
+                     screen52.addField(0x26,1,0,0,0,0);
+                     screen52.getScreenFields().getCurrentField().setFieldChar('.');
+                     screen52.getScreenFields().getCurrentField().setSelectionFieldInfo(17,
+                                 fld,
+                                 chcPos);
+                     screen52.setCursor(chcRowStart,chcColStart + 3);
+
+                     for (;cnt < minLen; cnt++) {
+
+                        byte0 = segment[pos++];
+                        s += vt.codePage.ebcdic2uni(byte0);
+                        screen52.setChar(vt.codePage.ebcdic2uni(byte0));
+
+                     }
+
+                     addChoiceField(chcRowStart,chcColStart,chcRow,chcCol,s);
+                  }
+
+//         screen52.getScreenFields().getCurrentField().setMDT();
+
+                  Log.d(TAG,s + " selected " + selected);
+//                  chcRowStart;
+                  //maxColChoice
+                  colCtr++;
+//                  rowCtr++;
+                  if (colCtr >= 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
--- /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<Object> dsq = new ArrayBlockingQueue<Object>(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 <code>#!</code> is
+     * encountered and if this sequence is <strong>not </strong> 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 <code>execCommand</code>
+     * provided to make the scanning sequence more flexible. We'd like for
+     * example to embed also a <code>+</code> or <code>-</code> sign to
+     * indicate whether the tnvt should trigger a repaint or not. This would
+     * allow the flashing of command sequences without them becoming visible.
+     *
+     * <ul>
+     * <li><strong>PRE </strong> The screen character at position
+     * <code>STRSCAN + 2</code> is not a white space.</li>
+     * </ul>
+     */
+    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();
+    }
+
+}
--- /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;
+
+
+/**
+ * <p>
+ * This class implements the SSLInterface and is used to create SSL socket
+ * instances.
+ * </p>
+ *
+ * @author Stephen M. Kennedy <skennedy@tenthpowertech.com>
+ *
+ */
+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
--- /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 <skennedy@tenthpowertech.com>
+ * @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<trustManagers.length; i++) {
+    		if (trustManagers[i] instanceof X509TrustManager)
+    			((X509TrustManager)trustManagers[i]).checkServerTrusted(chain,type);
+    	}
+      return;
+    } catch (CertificateException ce) {
+	      X509Certificate cert = chain[0];
+	      String certInfo = "Version: " + cert.getVersion() + "\n";
+	      certInfo = certInfo.concat("Serial Number: " + cert.getSerialNumber()+"\n");
+	      certInfo = certInfo.concat("Signature Algorithm: " + cert.getSigAlgName()+"\n");
+	      certInfo = certInfo.concat("Issuer: " + cert.getIssuerDN().getName()+"\n");
+	      certInfo = certInfo.concat("Valid From: " + cert.getNotBefore()+"\n");
+	      certInfo = certInfo.concat("Valid To: " + cert.getNotAfter()+"\n");
+	      certInfo = certInfo.concat("Subject DN: " + cert.getSubjectDN().getName()+"\n");
+	      certInfo = certInfo.concat("Public Key: " + cert.getPublicKey().getFormat()+"\n");
+
+          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 Not Accepted");
+	      }
+    	}
+  }
+
+  public X509Certificate[] getAcceptedIssuers() {
+  	ArrayList<X509Certificate> list = new ArrayList<X509Certificate>(10);
+	for (int i=0; i<trustManagers.length; i++) {
+		if (trustManagers[i] instanceof X509TrustManager)
+			list.addAll(Arrays.asList(((X509TrustManager)trustManagers[i]).getAcceptedIssuers()));
+	}
+	X509Certificate[] acceptedIssuers = new X509Certificate[list.size()];
+	acceptedIssuers = list.toArray(acceptedIssuers);
+    return acceptedIssuers;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/framework/transport/SSLInterface.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,44 @@
+package org.tn5250j.framework.transport;
+
+/*
+ * @(#)SSLInterface.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 java.net.Socket;
+
+public interface SSLInterface {
+
+	/**
+	 * Initialize the components required to create a new client socket
+	 * when createSSLSocket is called.
+	 * @param type The ssl socket type (SSLv2, SSLv3, TLS)
+	 * @see org.tn5250j.framework.transport.SSLConstants
+	 */
+   public abstract void init(String sslType);
+
+   /**
+    * Create a new socket
+    * @param destination
+    * @param port
+    * @return new socket, or null if none could be created.
+    */
+   public abstract Socket createSSLSocket(String destination, int port);
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tn5250j/framework/transport/SocketConnector.java	Mon Jun 16 08:24:00 2014 -0700
@@ -0,0 +1,109 @@
+
+/**
+ * @(#)SocketConnector.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
+ *
+ */
+package org.tn5250j.framework.transport;
+
+import java.net.Socket;
+
+import com.five_ten_sg.connectbot.service.TerminalBridge;
+import com.five_ten_sg.connectbot.service.TerminalManager;
+
+import org.tn5250j.framework.transport.SSL.SSLImplementation;
+import org.tn5250j.TN5250jConstants;
+import android.util.Log;
+
+
+public class SocketConnector {
+    private static final String TAG = "SocketConnector";
+  String sslType = null;
+
+  /**
+   * Creates a new instance that creates a plain socket by default.
+   */
+  public SocketConnector() {
+
+  }
+
+  /**
+   * Set the type of SSL connection to use.  Specify null or an empty string
+   * to use a plain socket.
+   * @param type The SSL connection type
+   * @see org.tn5250j.framework.transport.SSLConstants
+   */
+  public void setSSLType(String type) {
+    sslType = type;
+  }
+
+  /**
+   * Create a new client Socket to the given destination and port.  If an SSL
+   * socket type has not been specified <i>(by setSSLType(String))</i>, 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
--- /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
--- 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 @@
 
     <refentry id="x@PACKAGE@.1">
         <refentryinfo>
-            <date>2014-05-13</date>
+            <date>2014-06-14</date>
             <author>
                 <firstname>Carl</firstname>
                 <surname>Byington</surname>
@@ -40,7 +40,7 @@
 
         <refnamediv id='name.1'>
             <refname>@PACKAGE@</refname>
-            <refpurpose>an android vt320 terminal emulator for telnet/ssh connections</refpurpose>
+            <refpurpose>an android vt320/tn5250 terminal emulator for telnet/ssh connections</refpurpose>
         </refnamediv>
 
         <refsect1 id='build.1'>
@@ -61,14 +61,17 @@
                 compatible with the licenses of all the sub-parts.
             </para>
             <para>
-                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.
             </para>
         </refsect1>
 
         <refsect1 id='monitor.1'>
             <title>Terminal Monitor</title>
             <para>
-                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 @@
         <refsect1 id='todo.1'>
             <title>TODO</title>
             <para>
-                Add 5250 emulation.
+                The tn5250 ssl/tls key storage should use the same storage mechanism
+                as the base ssh key storage.
             </para>
         </refsect1>
 
@@ -230,6 +234,11 @@
                 Marcus Meiner. http://www.javassh.org
             </para>
             <para>
+                Based on TN5250J terminal emulator provided under the GPLv2
+                license. Copyright (C) 2001 Kenneth J. Pouncey.
+                http://tn5250j.sourceforge.net/
+            </para>
+            <para>
                 Includes the JSOCKS library, provided
                 under the GNU LGPL license. http://jsocks.sourceforge.net
             </para>
@@ -247,6 +256,12 @@
                 https://github.com/staktrace/connectbot/commits/filetransfer
                 modifications by Kartikaya Gupta.
             </para>
+            <para>
+                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
+            </para>
         </refsect1>
 
         <refsect1 id='version.1'>