|
|
|
@@ -106,6 +106,7 @@ public class FTDft {
|
|
|
|
|
}
|
|
|
|
|
dftSaveBuf = null;
|
|
|
|
|
dftSaveBufLen = 0;
|
|
|
|
|
resetState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -173,9 +174,9 @@ public class FTDft {
|
|
|
|
|
nameBuf = extractName(data, sfOffset + 3 + 31, 7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (OPEN_MSG.equalsIgnoreCase(nameBuf)) {
|
|
|
|
|
if (isMessageStream(nameBuf)) {
|
|
|
|
|
messageFlag = true;
|
|
|
|
|
log.info("DFT: Open request for message stream");
|
|
|
|
|
log.info("DFT: Open request for message stream (" + nameBuf + ")");
|
|
|
|
|
} else {
|
|
|
|
|
messageFlag = false;
|
|
|
|
|
listener.onDftRunning();
|
|
|
|
@@ -188,15 +189,36 @@ public class FTDft {
|
|
|
|
|
dftOpenAck();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isMessageStream(String name) {
|
|
|
|
|
if (name == null) return false;
|
|
|
|
|
String u = name.toUpperCase();
|
|
|
|
|
return u.contains(OPEN_MSG) || u.contains("MSG");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isDataStream(String name) {
|
|
|
|
|
if (name == null) return false;
|
|
|
|
|
String u = name.toUpperCase();
|
|
|
|
|
return u.contains("FT:DATA") || u.contains("DATA");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String extractName(byte[] data, int start, int maxLen) {
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
StringBuilder asciiSb = new StringBuilder();
|
|
|
|
|
StringBuilder ebcdicSb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < maxLen && (start + i) < data.length; i++) {
|
|
|
|
|
int b = data[start + i] & 0xFF;
|
|
|
|
|
if (b == 0) break;
|
|
|
|
|
char ch = translator.ebcdicToUnicode(b);
|
|
|
|
|
sb.append(ch);
|
|
|
|
|
asciiSb.append((char) b);
|
|
|
|
|
ebcdicSb.append(translator.ebcdicToUnicode(b));
|
|
|
|
|
}
|
|
|
|
|
return sb.toString().trim();
|
|
|
|
|
String ascii = asciiSb.toString().trim();
|
|
|
|
|
String ebcdic = ebcdicSb.toString().trim();
|
|
|
|
|
if (isMessageStream(ascii) || isDataStream(ascii)) {
|
|
|
|
|
return ascii;
|
|
|
|
|
}
|
|
|
|
|
if (isMessageStream(ebcdic) || isDataStream(ebcdic)) {
|
|
|
|
|
return ebcdic;
|
|
|
|
|
}
|
|
|
|
|
return ascii;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void dftOpenAck() {
|
|
|
|
@@ -227,6 +249,7 @@ public class FTDft {
|
|
|
|
|
int pos = offset + 2;
|
|
|
|
|
int end = offset + length;
|
|
|
|
|
|
|
|
|
|
boolean dataFound = false;
|
|
|
|
|
// Look for TR_BEGIN_DATA marker
|
|
|
|
|
while (pos < end) {
|
|
|
|
|
int headerCode = data[pos] & 0xFF;
|
|
|
|
@@ -234,10 +257,11 @@ public class FTDft {
|
|
|
|
|
if (headerCode == TR_BEGIN_DATA) {
|
|
|
|
|
if (pos + 3 > end) break;
|
|
|
|
|
int dataLen = ((data[pos + 1] & 0xFF) << 8) | (data[pos + 2] & 0xFF);
|
|
|
|
|
int actualDataLen = dataLen - 3;
|
|
|
|
|
int actualDataLen = (dataLen > 5) ? Math.min(dataLen - 5, end - (pos + 3)) : (end - (pos + 3));
|
|
|
|
|
pos += 3;
|
|
|
|
|
|
|
|
|
|
if (actualDataLen > 0 && pos + actualDataLen <= end) {
|
|
|
|
|
dataFound = true;
|
|
|
|
|
if (messageFlag) {
|
|
|
|
|
// Handle message payload from host
|
|
|
|
|
dftDataAck();
|
|
|
|
@@ -269,25 +293,46 @@ public class FTDft {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send acknowledgement for file data
|
|
|
|
|
dftDataAck();
|
|
|
|
|
// Send acknowledgement only if file data was actually received and processed
|
|
|
|
|
if (dataFound) {
|
|
|
|
|
dftDataAck();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void handleHostMessage(byte[] data, int offset, int length) {
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
StringBuilder asciiSb = new StringBuilder();
|
|
|
|
|
StringBuilder ebcdicSb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
|
int b = data[offset + i] & 0xFF;
|
|
|
|
|
if (b == 0 || b == '$') break;
|
|
|
|
|
char ch = translator.ebcdicToUnicode(b);
|
|
|
|
|
sb.append(ch);
|
|
|
|
|
asciiSb.append((char) b);
|
|
|
|
|
ebcdicSb.append(translator.ebcdicToUnicode(b));
|
|
|
|
|
}
|
|
|
|
|
String msg = sb.toString().trim();
|
|
|
|
|
log.info("DFT message: " + msg);
|
|
|
|
|
String asciiMsg = asciiSb.toString().trim();
|
|
|
|
|
String ebcdicMsg = ebcdicSb.toString().trim();
|
|
|
|
|
|
|
|
|
|
String msgLower = msg.toLowerCase();
|
|
|
|
|
if (msg.startsWith(END_TRANSFER) || msgLower.contains("complete") || msgLower.contains("transferred") || msgLower.contains("success")) {
|
|
|
|
|
// Determine if message is ASCII or EBCDIC
|
|
|
|
|
String msg = asciiMsg;
|
|
|
|
|
if (asciiMsg.toUpperCase().startsWith("TRANS") || asciiMsg.toLowerCase().contains("file") || asciiMsg.toLowerCase().contains("error")) {
|
|
|
|
|
msg = asciiMsg;
|
|
|
|
|
} else if (ebcdicMsg.toUpperCase().startsWith("TRANS") || ebcdicMsg.toLowerCase().contains("file") || ebcdicMsg.toLowerCase().contains("error")) {
|
|
|
|
|
msg = ebcdicMsg;
|
|
|
|
|
} else {
|
|
|
|
|
int asciiPrintable = 0;
|
|
|
|
|
for (char c : asciiMsg.toCharArray()) {
|
|
|
|
|
if (c >= 32 && c <= 126) asciiPrintable++;
|
|
|
|
|
}
|
|
|
|
|
if (asciiPrintable < asciiMsg.length() / 2 && !ebcdicMsg.isEmpty()) {
|
|
|
|
|
msg = ebcdicMsg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.info("DFT host message: " + msg);
|
|
|
|
|
|
|
|
|
|
String msgUpper = msg.toUpperCase();
|
|
|
|
|
if (msgUpper.startsWith(END_TRANSFER) || msgUpper.contains("COMPLETE") || msgUpper.contains("TRANSFERRED") || msgUpper.contains("SUCCESS")) {
|
|
|
|
|
listener.onTransferComplete(null);
|
|
|
|
|
} else if (listener.getCurrentState() == FTState.ABORT_SENT || msgLower.contains("error") || msgLower.contains("failed") || msgLower.contains("abort")) {
|
|
|
|
|
} else if (msgUpper.startsWith("TRANS") || msgUpper.contains("ERROR") || msgUpper.contains("FAILED") || msgUpper.contains("ABORT") || msgUpper.contains("NOT FOUND") || listener.getCurrentState() == FTState.ABORT_SENT) {
|
|
|
|
|
listener.onTransferAborted(msg.isEmpty() ? "Transfer aborted" : msg);
|
|
|
|
|
} else {
|
|
|
|
|
// Informational message (default success)
|
|
|
|
@@ -495,7 +540,7 @@ public class FTDft {
|
|
|
|
|
|
|
|
|
|
input.sendStructuredFieldData(out.toByteArray());
|
|
|
|
|
|
|
|
|
|
if (!messageFlag) {
|
|
|
|
|
if (listener.getCurrentState() != FTState.NONE) {
|
|
|
|
|
log.info("DFT: File transfer completed on close request (" + bytesTransferred + " bytes)");
|
|
|
|
|
listener.onTransferComplete(null);
|
|
|
|
|
}
|
|
|
|
@@ -504,13 +549,20 @@ public class FTDft {
|
|
|
|
|
// ========== Data Acknowledgement ==========
|
|
|
|
|
|
|
|
|
|
private void dftDataAck() {
|
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream(6);
|
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream(12);
|
|
|
|
|
out.write(AID_SF);
|
|
|
|
|
out.write(0); out.write(5);
|
|
|
|
|
out.write(0); out.write(11); // SF length = 11 (0x000B)
|
|
|
|
|
out.write(SF_TRANSFER_DATA);
|
|
|
|
|
out.write((TR_NORMAL_REPLY >> 8) & 0xFF);
|
|
|
|
|
out.write(TR_NORMAL_REPLY & 0xFF);
|
|
|
|
|
out.write((TR_RECNUM_HDR >> 8) & 0xFF);
|
|
|
|
|
out.write(TR_RECNUM_HDR & 0xFF);
|
|
|
|
|
out.write((int) ((recnum >> 24) & 0xFF));
|
|
|
|
|
out.write((int) ((recnum >> 16) & 0xFF));
|
|
|
|
|
out.write((int) ((recnum >> 8) & 0xFF));
|
|
|
|
|
out.write((int) (recnum & 0xFF));
|
|
|
|
|
|
|
|
|
|
recnum++;
|
|
|
|
|
input.sendStructuredFieldData(out.toByteArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|