diff --git a/lib3270j/src/main/java/haus/nightmare/lib3270j/ConnectionConfig.java b/lib3270j/src/main/java/haus/nightmare/lib3270j/ConnectionConfig.java index b41ac44..0c6fabf 100644 --- a/lib3270j/src/main/java/haus/nightmare/lib3270j/ConnectionConfig.java +++ b/lib3270j/src/main/java/haus/nightmare/lib3270j/ConnectionConfig.java @@ -435,6 +435,14 @@ public class ConnectionConfig { } } + // Parse [lu@]host[:port] (e.g. "00C2@mvs.host.com:1023") + String parsedLu = null; + int atIdx = s.indexOf('@'); + if (atIdx > 0 && atIdx < s.length() - 1) { + parsedLu = s.substring(0, atIdx).trim(); + s = s.substring(atIdx + 1).trim(); + } + String host = s; int port = (defaultPort > 0) ? defaultPort : (tls ? 992 : 23); @@ -458,6 +466,9 @@ public class ConnectionConfig { } ConnectionConfig config = new ConnectionConfig(host, port, defaultModel != null ? defaultModel : TerminalModel.IBM_3279_4); + if (parsedLu != null && !parsedLu.isEmpty()) { + config.setLuName(parsedLu); + } config.setUseTls(tls); config.setTn3270eEnabled(tn3270e); config.setKeepAliveEnabled(keepAlive); diff --git a/lib3270j/src/main/java/haus/nightmare/lib3270j/telnet/TelnetFSM.java b/lib3270j/src/main/java/haus/nightmare/lib3270j/telnet/TelnetFSM.java index f8c3f4c..1f0af46 100644 --- a/lib3270j/src/main/java/haus/nightmare/lib3270j/telnet/TelnetFSM.java +++ b/lib3270j/src/main/java/haus/nightmare/lib3270j/telnet/TelnetFSM.java @@ -70,8 +70,22 @@ public class TelnetFSM { private List getCandidateTerminalTypes() { List list = new ArrayList<>(); + String currentLu = null; + List lus = config.getLuNames(); + if (lus != null && !lus.isEmpty() && luIndex < lus.size()) { + currentLu = lus.get(luIndex); + } else if (config.getLuName() != null && !config.getLuName().trim().isEmpty()) { + currentLu = config.getLuName().trim(); + } + if (config.getTerminalName() != null && !config.getTerminalName().trim().isEmpty()) { - list.add(config.getTerminalName().trim()); + String tName = config.getTerminalName().trim(); + if (currentLu != null && !currentLu.isEmpty() && !tName.contains("@")) { + list.add(tName + "@" + currentLu); + list.add(tName); + } else { + list.add(tName); + } return list; } if (config.isDynamicModel()) { @@ -82,24 +96,41 @@ public class TelnetFSM { list.add("IBM-3279-2"); list.add("IBM-3278-2"); list.add("UNKNOWN"); - return list; + } else { + TerminalModel model = config.getModel(); + list.add(model.getTerminalType()); + list.add(model.getBaseTerminalType()); + if (model.isColor()) { + try { + TerminalModel mono = TerminalModel.forModel(model.getModelNumber(), false); + list.add(mono.getTerminalType()); + list.add(mono.getBaseTerminalType()); + } catch (Exception ignored) {} + } + if (model.getModelNumber() != 2) { + list.add("IBM-3279-2-E"); + list.add("IBM-3279-2"); + list.add("IBM-3278-2"); + } + list.add("UNKNOWN"); } - TerminalModel model = config.getModel(); - list.add(model.getTerminalType()); - list.add(model.getBaseTerminalType()); - if (model.isColor()) { - try { - TerminalModel mono = TerminalModel.forModel(model.getModelNumber(), false); - list.add(mono.getTerminalType()); - list.add(mono.getBaseTerminalType()); - } catch (Exception ignored) {} + + if (currentLu != null && !currentLu.isEmpty()) { + List luCandidates = new ArrayList<>(); + for (String item : list) { + if (!"UNKNOWN".equalsIgnoreCase(item) && !item.contains("@")) { + luCandidates.add(item + "@" + currentLu); + } + } + for (String item : list) { + if (!"UNKNOWN".equalsIgnoreCase(item)) { + luCandidates.add(item); + } + } + luCandidates.add("UNKNOWN"); + return luCandidates; } - if (model.getModelNumber() != 2) { - list.add("IBM-3279-2-E"); - list.add("IBM-3279-2"); - list.add("IBM-3278-2"); - } - list.add("UNKNOWN"); + return list; } @@ -589,6 +620,9 @@ public class TelnetFSM { out.write(IAC); out.write(SE); sendBytes(out.toByteArray()); + if (termType.contains("@")) { + connectedLu = termType.substring(termType.indexOf('@') + 1).trim(); + } log.warning(">>> SENT SB TTYPE IS " + termType + " SE"); } } diff --git a/lib3270j/src/test/java/haus/nightmare/lib3270j/telnet/TelnetFSMTest.java b/lib3270j/src/test/java/haus/nightmare/lib3270j/telnet/TelnetFSMTest.java index 9038d14..356d57b 100644 --- a/lib3270j/src/test/java/haus/nightmare/lib3270j/telnet/TelnetFSMTest.java +++ b/lib3270j/src/test/java/haus/nightmare/lib3270j/telnet/TelnetFSMTest.java @@ -84,6 +84,41 @@ public class TelnetFSMTest { ConnectionConfig c4 = ConnectionConfig.parseHostString("non-e:vm.ibm.com", 23, TerminalModel.IBM_3279_4); assertFalse(c4.isTn3270eEnabled()); assertEquals("vm.ibm.com", c4.getHost()); + + ConnectionConfig c5 = ConnectionConfig.parseHostString("00C2@mvs.hugfreevikings.wtf:1023", 23, TerminalModel.IBM_3279_4); + assertEquals("mvs.hugfreevikings.wtf", c5.getHost()); + assertEquals(1023, c5.getPort()); + assertEquals("00C2", c5.getLuName()); + + ConnectionConfig c6 = ConnectionConfig.parseHostString("L:TSO01@secure.mvs.com:992", 23, TerminalModel.IBM_3279_4); + assertTrue(c6.isUseTls()); + assertEquals("secure.mvs.com", c6.getHost()); + assertEquals(992, c6.getPort()); + assertEquals("TSO01", c6.getLuName()); + } + + @Test + public void testPlainTn3270TTypeWithLuName() { + config.setTn3270eEnabled(false); + config.setLuName("00C2"); + fsm.onConnected(); + + feedBytes(TelnetConstants.IAC, TelnetConstants.DO, TelnetConstants.TELOPT_TTYPE); + // Host sends SB TTYPE SEND + feedBytes(TelnetConstants.IAC, TelnetConstants.SB, TelnetConstants.TELOPT_TTYPE, + TelnetConstants.TELQUAL_SEND, + TelnetConstants.IAC, TelnetConstants.SE); + + boolean foundTtypeLu = false; + for (byte[] pkt : connection.sentData) { + String s = new String(pkt, java.nio.charset.StandardCharsets.ISO_8859_1); + if (s.contains("IBM-3279-4-E@00C2")) { + foundTtypeLu = true; + break; + } + } + assertTrue(foundTtypeLu, "Plain TN3270 TTYPE IS must append @ when configured"); + assertEquals("00C2", fsm.getConnectedLu()); } @Test