From 80166c477b73b42b426824b4647406b8fae02af4 Mon Sep 17 00:00:00 2001 From: Rudi Date: Thu, 20 Aug 2026 17:24:55 -0400 Subject: [PATCH] cleaning and adding updates --- .gitignore | 1 + .gradle/8.5/checksums/checksums.lock | Bin 17 -> 0 bytes .gradle/8.5/checksums/md5-checksums.bin | Bin 19397 -> 0 bytes .gradle/8.5/checksums/sha1-checksums.bin | Bin 23033 -> 0 bytes .../dependencies-accessors.lock | Bin 17 -> 0 bytes .gradle/8.5/fileChanges/last-build.bin | Bin 1 -> 0 bytes .gradle/8.5/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .gradle/8.5/gc.properties | 0 .gradle/9.2.0/checksums/checksums.lock | Bin 17 -> 0 bytes .gradle/9.2.0/checksums/md5-checksums.bin | Bin 19397 -> 0 bytes .gradle/9.2.0/checksums/sha1-checksums.bin | Bin 21089 -> 0 bytes .gradle/9.2.0/fileChanges/last-build.bin | Bin 1 -> 0 bytes .gradle/9.2.0/fileHashes/fileHashes.bin | Bin 18547 -> 0 bytes .gradle/9.2.0/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .gradle/9.2.0/gc.properties | 0 .../buildOutputCleanup.lock | Bin 17 -> 0 bytes .gradle/buildOutputCleanup/cache.properties | 2 - .gradle/vcs-1/gc.properties | 0 bugs.txt | 1 + build.gradle | 34 ++- build/j3270/org/pubvm/j3270/J3270App$1.class | Bin 960 -> 960 bytes build/j3270/org/pubvm/j3270/J3270App$2.class | Bin 3088 -> 3088 bytes build/j3270/org/pubvm/j3270/J3270App.class | Bin 16789 -> 16841 bytes .../config/Settings$StartupBehavior.class | Bin 1286 -> 1286 bytes .../org/pubvm/j3270/config/Settings.class | Bin 9784 -> 9784 bytes .../org/pubvm/j3270/ui/ConnectDialog.class | Bin 5795 -> 5795 bytes .../org/pubvm/j3270/ui/SettingsDialog$1.class | Bin 1599 -> 1599 bytes .../org/pubvm/j3270/ui/SettingsDialog$2.class | Bin 1802 -> 1802 bytes .../org/pubvm/j3270/ui/SettingsDialog$3.class | Bin 665 -> 665 bytes .../org/pubvm/j3270/ui/SettingsDialog$4.class | Bin 1355 -> 1355 bytes .../org/pubvm/j3270/ui/SettingsDialog.class | Bin 21254 -> 21258 bytes .../org/pubvm/j3270/ui/StatusBar$1.class | Bin 1152 -> 1152 bytes .../j3270/org/pubvm/j3270/ui/StatusBar.class | Bin 4176 -> 4176 bytes .../org/pubvm/j3270/ui/TerminalPanel$1.class | Bin 2347 -> 2347 bytes .../org/pubvm/j3270/ui/TerminalPanel$2.class | Bin 689 -> 689 bytes .../org/pubvm/j3270/ui/TerminalPanel.class | Bin 22584 -> 22589 bytes .../org/lib3270j/ConnectionConfig.class | Bin 2493 -> 2493 bytes .../org/lib3270j/ConnectionState.class | Bin 2509 -> 2509 bytes .../org/lib3270j/DiagnosticClient$1.class | Bin 1559 -> 1559 bytes .../org/lib3270j/DiagnosticClient$2.class | Bin 1612 -> 1612 bytes .../org/lib3270j/DiagnosticClient.class | Bin 5432 -> 5432 bytes .../org/lib3270j/Telnet3270Client.class | Bin 6466 -> 6552 bytes .../lib3270j/org/lib3270j/TerminalModel.class | Bin 3598 -> 3598 bytes .../lib3270j/charset/EbcdicTranslator.class | Bin 3139 -> 3139 bytes .../DataStreamProcessor$OutputSender.class | Bin 375 -> 375 bytes .../datastream/DataStreamProcessor.class | Bin 14246 -> 14623 bytes .../datastream/QueryReplyBuilder.class | Bin 3971 -> 3971 bytes .../org/lib3270j/input/InputProcessor.class | Bin 6652 -> 7603 bytes .../listener/ConnectionListener.class | Bin 420 -> 420 bytes .../listener/ScreenUpdateListener.class | Bin 378 -> 378 bytes .../lib3270j/protocol/DS3270Constants.class | Bin 9902 -> 9902 bytes .../lib3270j/protocol/TN3270EConstants.class | Bin 4119 -> 4119 bytes .../lib3270j/protocol/TelnetConstants.class | Bin 3231 -> 3231 bytes .../lib3270j/screen/ExtendedAttribute.class | Bin 1298 -> 1298 bytes .../org/lib3270j/screen/ScreenBuffer.class | Bin 6938 -> 6938 bytes .../lib3270j/telnet/TelnetConnection.class | Bin 5634 -> 5634 bytes .../telnet/TelnetFSM$TN3270ESubmode.class | Bin 1287 -> 1287 bytes .../org/lib3270j/telnet/TelnetFSM.class | Bin 17208 -> 17208 bytes build_all.sh | 37 +++ gradle.properties | 2 + .../main/java/org/pubvm/j3270/J3270App.java | 10 +- .../java/org/pubvm/j3270/ft/FileTransfer.java | 55 +++- .../java/org/lib3270j/Telnet3270Client.java | 1 + .../datastream/DataStreamProcessor.java | 21 ++ .../java/org/lib3270j/ft/FTConstants.java | 12 + .../src/main/java/org/lib3270j/ft/FTCut.java | 226 +++++++------- .../src/main/java/org/lib3270j/ft/FTDft.java | 280 ++++++++++-------- .../org/lib3270j/input/InputProcessor.java | 72 ++++- .../gc.properties => nohup.out | 0 settings.gradle | 1 + 70 files changed, 471 insertions(+), 284 deletions(-) delete mode 100644 .gradle/8.5/checksums/checksums.lock delete mode 100644 .gradle/8.5/checksums/md5-checksums.bin delete mode 100644 .gradle/8.5/checksums/sha1-checksums.bin delete mode 100644 .gradle/8.5/dependencies-accessors/dependencies-accessors.lock delete mode 100644 .gradle/8.5/fileChanges/last-build.bin delete mode 100644 .gradle/8.5/fileHashes/fileHashes.lock delete mode 100644 .gradle/8.5/gc.properties delete mode 100644 .gradle/9.2.0/checksums/checksums.lock delete mode 100644 .gradle/9.2.0/checksums/md5-checksums.bin delete mode 100644 .gradle/9.2.0/checksums/sha1-checksums.bin delete mode 100644 .gradle/9.2.0/fileChanges/last-build.bin delete mode 100644 .gradle/9.2.0/fileHashes/fileHashes.bin delete mode 100644 .gradle/9.2.0/fileHashes/fileHashes.lock delete mode 100644 .gradle/9.2.0/gc.properties delete mode 100644 .gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 .gradle/buildOutputCleanup/cache.properties delete mode 100644 .gradle/vcs-1/gc.properties create mode 100755 build_all.sh create mode 100644 gradle.properties rename .gradle/8.5/dependencies-accessors/gc.properties => nohup.out (100%) diff --git a/.gitignore b/.gitignore index 18a179c..01b729c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store *.jar build +.gradle diff --git a/.gradle/8.5/checksums/checksums.lock b/.gradle/8.5/checksums/checksums.lock deleted file mode 100644 index a20b0af561aa33341131d807c8a23a8581de8339..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 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 k8U_YOo^O#Iw z9ozZR&XwB~bt;{et&un}UpBkUsU*+i^ZBgl=`Y~@+3tCsz3=mWo_k);^V>a76vuhF zbUpIWum>eNcUj_G9oA6z$deSNVb{w&FrPAtE9CI0S`^g~G`S7}&Y zZ1ArfdEld!?x!EiOB9a|)Hr4~lRUbC<%Tc1RgK5j_|pA{v%Kv2aKp9Khc$FRAuKPC zi));-H$qG2Z(zBlb*H1kI&Ln_pRv6D;k%r4&aicV#WVTz;Cezxs_SY{X zPoAa?`hJ0Qv$#=aPdm5FcR!bx?7XP7_KA!%bc4w;oK50}bIn4#SJR?eeM_k&rT?Xi zv@xADWGZn(zH(UNsfke;l3%&;1AY};rj5m<;Uc^((ZfoXXq%CopEhvDwJ)CAD>}Ss zLpWo8xC`$g^k~#dr<Vck51dA*y=yNh>TLP6p%vzHTyOVo=b(&%0b@NT+|c+$9Q>L3jy4{U KhV&-C4*U%!jo}gi diff --git a/.gradle/9.2.0/checksums/sha1-checksums.bin b/.gradle/9.2.0/checksums/sha1-checksums.bin deleted file mode 100644 index 77e51ad39949c19caff06ae48665bd3095a8cf06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21089 zcmeI4do)!09>BL(9FM%ipoj7}s3wn6>bePe3}bS1D`k4C$g?DrBh)k}PH`lU6Y7MD zM0u1)LQc`4BBN6}Lpe$+QE~Ke_nzPH=iED^wff`!b=PmNWoFiA_Gf?h{_L5lwajKm z5SmJ3a3TI))c<~nAK?PH04{(F-~zY+E`ST*0=NJ!fD7OPxBxDI3*Z8{04{(F-~zb7 z|4RW+@<3$4!DyO_Qx6pP5CmPGd_a%(95s60b2bP(?Usywe{f)CW!U@8FCzhW;UONI z*b$mzTJHk5dj#Tf8{V!pYFtwRxN8;ST;_Kpsa}q$aQokm^FHTt%MT%^0cY++{HLJQ zt>-M1I{|mxgLry{Tb8q!)L6&qJvR5^F^E#Qtz5w9vt&{$_u zPzyNA1My#NWSj0DW*q?BDGu>lmpLl?`+vI(_zDxmA2bc7wX$>z;QDV6=j$uHpu6AI z2HbTB@h*vY+Pt6kT>+eRc$_yo)t0l3UI5P6i}=%2#%N_%i6Pv+7UI3V%y$X2&_KYQ zlMsJ)sZ+#VT_g=)`j*1=ZSzfUNZik8Z=NsHhMP|(30e96#T-w7uZmzMxJir+} z<2)%sQoYoO0oOl-xLom=($XyrjetAfLR{fo1WPM{u@G>VY{b<{&AKH*ut(AJx2j|YeIbfk|%?!SD3Qlb{-&ZC25p? zWdBJ;z#R(^x306{dGCKz3b?x>;&vgeH*DI50{~~~BJSq3c6W`X!wkUP*ob>-&6@nf zefevEI~yXtvLsE9D`pG#hxHC|KhNH&Ya(@{!TO9s#DgtvXKx7JS_il*3-R5L$D~il znWzHJx`sHqCkV-7;5mGY3*Z8{04{(F-~zY+E`ST*0=NJ!fD7OPxBxDI3*Z8{04{(F z-~zY+E`ST*0=NJ!fD7OPxBxDI3*Z8{04{(F-~zY+E`ST*0$)?WoLp%(`J+$$sGZ)C zq+)HLaU1Hy^uB7BH@r$GV4x*%$n_c*PU-%@;WdETGZJk7d3D4 zM#yST-qze;Hhe3yc&BRp{hP@e7MZ@J74FJ$JRy(>srO%Pk!Sg0?w75QpINE9<;mkJvILg0hUgx~=*S)HtZlYh zsN)sgx79@cQ;lgewBT9RBws7SXZeF?dv|45$PoKptX^-5=faIjp0A;GP%ulviu^-*A>J5+EV~xpK|M5Dc9T%PT1&f+h2KI0wYhH@F^E7$R?+*3h8K**(^Y`E2rNA2Z z1eVyz5z$$e$INaT|7?>NZnm!UWvey&kpzwFDva#zfT8j7{b`r)6Bp^lY0X zZTe2tu`!eZtV znWEOUFZ20*uVJRti1<*G54q$`98Uf4`~GFP^*x zMPN~%G6W%EzFgFL`Nw@-ucB;D_mbOANy?hq^rCbQu;7(Kl6{7v7K@&8{f>Rz&&8v* zXP7Yx%T^`rB(E=_W|hQJqX@Bi+eEE2zKUe9F^BW8!D{5V{7&hbT}ANKTWT$^h$+-n zLP8DQ_P*L6JGPpa&els@@whdytnJ6UU{)!-hDw9_BoML;xNB@=l9mqaX497~;FcuDc2S)XPRbDQbHOX|YsKpNpPu=5?Z?@^A+)$HYVSF>!g4{OM@QOep2(5lm zOLw#(B6@mfcmq9WRbuAVzh3y5Z-&+;pvjZ}S_s$JV{RXMSG=Bc;J91b%Jrs!b7H6Z zL5o_OT-4&p8=;2n`{q|Co_#dy5W8aHhQ?b2o)Xk}3jK}_`j4IWdydu@@Vj(5QA z+x=0RNA-$&;iu@8DqyJ=koQ8f?pt5xH%HB&IUSM;v-sx*m(hVg=73r70yK%~)L%^$ zvfhk*PN`b;%yav6wzSHww$-)uBfmjwonV$k1$EwpEG1R%Ep+ja*$Q)$XB>UC{1L&m zeFdzF-2zK0D^Jwg$PCKkZHODpkDtld=38}M?jDy9ttNpbPB2BSS(7IjM%=0HS4()Z zHm&_%rQRC@GJsV{-jmBW4e6p5$4@JY-SWI|;BIHPY0wQ BJ1zhK diff --git a/.gradle/9.2.0/fileChanges/last-build.bin b/.gradle/9.2.0/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/.gradle/9.2.0/fileHashes/fileHashes.bin b/.gradle/9.2.0/fileHashes/fileHashes.bin deleted file mode 100644 index 7412165b8db753a863f0b4cb7b4af878ff863b75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18547 zcmeI(A&Npl7y#gT27?G%gjbD%h#(scE(R~Kw=f6>i8^Z(40|NrXD3`0ok*?olPXgpIH0RjXF5FkK+009C72oNAZfB*pk1PBly z@Gb&hv5`vAOxiBxNo^KFw;Ge=XIuT7Z>Hnocr1^_`q29E#$ diff --git a/build/j3270/org/pubvm/j3270/J3270App$2.class b/build/j3270/org/pubvm/j3270/J3270App$2.class index 5113d3fcd68b2b38fd2ca82a055035b4e5ed598b..554b90f85e303a0e311daa6ac37e7c893c8c3d61 100644 GIT binary patch delta 17 ZcmbOrF+qak)W2Q(7#J8FH*#?B002AM1*ZT2 delta 17 ZcmbOrF+qak)W2Q(7#J8_Hga(A002Ab1*!l5 diff --git a/build/j3270/org/pubvm/j3270/J3270App.class b/build/j3270/org/pubvm/j3270/J3270App.class index fe40d61c8cb8e982427fef42d038dbcbd4cb8d25..d7ec86044ac5bac4115cf15e4f51e6c0e4911ce0 100644 GIT binary patch delta 3244 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 delta 3254 zcmZ`*33yc16+Y+OByVPT3E7iLNHST-BoneH1Og) zYw6D#{e{C+xuG-MGu_#BZqKyr2bw(|_msLC8fDpG}gu% zPxbJ+8h3*Ybb3*zmmnG;$Xz|7xv^xu5kGN|+DLDvXX=4o*%}up+*<))Pn}(!UAoP=KQ)B(u94%i1a`FTY-j??p(Ij|UcpGf5prPBw{-y-btne_OKSf%Qx(=pm(5%JviUZYi` zMyuGtk<@AtiSk^!)0M3JQ*`8VQK64>%mpNH?vpg%S zn&p#O8Q9Tg&2B^nb8}kQa5E=|<*eLTmdE5)vAiKSBWefVAr`!hSR=CRY zH*9;Ib}J9o#sTsdz~8k6DmJo!q(TA=;X*}wX<>x6R}p1u>kG5ve5K*NpyPOm!~58_kM2i^Ufj6JN3J`- z0|8ji0SCb#$ktR2P@S^5Iuo0L}(KT*8$u zg;0D7l2JkdE`w3H9PY;zFa@868Mub6#>zmLEvvDh|#CBNA>+{$FTX8$Q zjyvEW?u4Vb3y$M%_yqUB89WG|;a<3a``{|>hb}yT0uP}T52KFnVi3O9f>C$`6Y(f! z;4v&9KT@MO6Z&>RU+~xH5Nfzc!?Qd>4nKRC?R)U=f(WqmSTtO$(R;`a*C6H|MqT{4 zdPTAZNIBuvF35#|A4kfl;$V#rwb78Q;_&W<%;d2J`~WQYA$R*YH{%2(;z>xsk0A>` zg`s#FO7Rqw;aM1o=ioj(4-er5n1-M86SxR<_ys(MozQ|`!a}?Ri|{h6!zmZ_@4 zmCc9i@_q@#3ZVyi|Cxo|nm9YE@H5#xaZsjfuKB@f04ZYOrGs zIB*&`aXJ&N<$^+tiy<_S_vNe7sOs&Z{VEp$lXc9ck4mpDGIBNfedu=Tz=a-&xmOD!9gZ^qV z?dex2ZwN4-t69KT=0YCn*4sS`;$VJ(`huVTKf$v(cn$~8<=}a}gZW)-1P7KTaW8X9 zBU<=f?JK-{Vl-FqEibLRv+!T=-u#+3o#V~%3UK-V58p@Gm;WG`zUkZ%)o`oJi)Esn zl6q1H$-Si^8vpq)syb0>Z)tUT>E%@rVKAc&tD#Rf$LW9SAy+9!SEldk!s8$RjQZAqX{^6Qpbc+q@Hn@XccbD8L5=`tc?MY^)PSM{drI|h%qEhkf6q%+X#|+9daiJ*Z q?&R?-kLHy>+#};7MxYRP2Uw{Ni^ZtB>@-!WgDqmTxJQfw`+otu7|7-T diff --git a/build/j3270/org/pubvm/j3270/config/Settings$StartupBehavior.class b/build/j3270/org/pubvm/j3270/config/Settings$StartupBehavior.class index 6839a76aa4efdea34c6fed76ab55fcdd67e6924b..936d123ad739c2a63e449c811e981b1c59ded7a7 100644 GIT binary patch delta 17 YcmZqUYUAQK^>5cc1_lPljU4}206N+RWdHyG delta 17 YcmZqUYUAQK^>5cc1_lO~jU4}206OUgXaE2J diff --git a/build/j3270/org/pubvm/j3270/config/Settings.class b/build/j3270/org/pubvm/j3270/config/Settings.class index 0614591c8b5cbae174358edfbe43aca39e8f0d41..9c8e953d5526f702b40194d80fa7aab3409cdfcb 100644 GIT binary patch delta 17 Zcmdntv%`nu)W2Q(7#J8FH*y%L0RTr_2B81| delta 17 Zcmdntv%`nu)W2Q(7#J8_HgXuK0RTs92BZK0 diff --git a/build/j3270/org/pubvm/j3270/ui/ConnectDialog.class b/build/j3270/org/pubvm/j3270/ui/ConnectDialog.class index e8ba19b84576350a7c485f813e8b1bd7f28870f4..53ed31e7d1688f92798bc878b62cef8f68c40574 100644 GIT binary patch delta 17 ZcmZ3iyI7aw)W2Q(7#J8FH*(At0{}tb29y8* delta 17 ZcmZ3iyI7aw)W2Q(7#J8_Hge1s0{}tq2A2Q; diff --git a/build/j3270/org/pubvm/j3270/ui/SettingsDialog$1.class b/build/j3270/org/pubvm/j3270/ui/SettingsDialog$1.class index 145519e0393abf553f8601b369119d2375640a07..edfecf8971ac4dd2e3ec081862fc93da35b1d52d 100644 GIT binary patch delta 210 zcmdnbv!93K)W2Q(7#J8FCvuoioT1Cb$-u;L6Cuqk%0{)lbp2is5^@nP!j`#fB;Afm!>)`)nz2j delta 209 zcmdnbv!93K)W2Q(7#J8_CUTfhtWYuL;9=lo;9_LpEKAH$$;?Yhtzcwe^yFkTf*i&f>+&z{bEJAOO-2rh%%#G*Ai90wy39W6%TA z`aqTukY)waQd&A&85p%>w=%G6NwREZ;MUUK%D^`{jMY`2QELkW`z{6v1_mI5ZwrGA ah;OumLCII=7=r|om`*T|!#(*FYbgNJ`6R9Y diff --git a/build/j3270/org/pubvm/j3270/ui/SettingsDialog$2.class b/build/j3270/org/pubvm/j3270/ui/SettingsDialog$2.class index 7e3d3e9698d26b787b5985cf27102e379a2f12d4..d336d30153498df2714550060902505996469f84 100644 GIT binary patch delta 206 zcmeC;>*C`$^>5cc1_lPli5%t=m+5kGGB7c4@Gx*Pa80yTW8>jr;AP;On5o1sz{4QO zz{SYGR+gBflAN^h@(&g-pdtna0RfN_Fbz}yrdb)-fF?2lu^59DkhTW0jDR#Nke1TY z-patJrL&cRT}yW>1GknW%T@;d$)aqo*6dna7`S&aNH8z}8H`&PWI+6#3`$H42N*PV cFlhPe9Al70lG549V8F}}4iw>^Je92!05K>etpET3 delta 205 zcmeC;>*C`$^>5cc1_lO~i5%t=D^%Dxco;YtxF#-AlH}oG;ALQAWMC^x%uz{B;$&cA z;OAiwU=W;WtH1H`4;C+01~vu;0RfPDFbz}VEyN=ys~7&LY; bX!+_KV~|CX(%H#iz|0U16ycscm8}#2JZvPn diff --git a/build/j3270/org/pubvm/j3270/ui/SettingsDialog$3.class b/build/j3270/org/pubvm/j3270/ui/SettingsDialog$3.class index f5efe874ac53b801f14bb4ebb7805c43e4899c71..f7a00f1d3ff37a126525124d14a39a087b99674b 100644 GIT binary patch delta 17 ZcmbQqI+K;-)W2Q(7#J8FH*!p50suS61`+@O delta 17 ZcmbQqI+K;-)W2Q(7#J8_HgZg40suSL1{DAR diff --git a/build/j3270/org/pubvm/j3270/ui/SettingsDialog$4.class b/build/j3270/org/pubvm/j3270/ui/SettingsDialog$4.class index 3d9b553e552c820eede85ecf02c72b614e3373ff..e9e7d8a9f010e35feabf69b76174ab5ec754e54b 100644 GIT binary patch delta 17 ZcmX@jb()Lg)W2Q(7#J8FH*z?$0suk<1~mWx delta 17 ZcmX@jb()Lg)W2Q(7#J8_HgY(#0sul31~>o! diff --git a/build/j3270/org/pubvm/j3270/ui/SettingsDialog.class b/build/j3270/org/pubvm/j3270/ui/SettingsDialog.class index d925b0d3889a3041dc9737fdffb259fe8f21a936..c9bb75718bdff399999d0ad113993437ef781cf8 100644 GIT binary patch delta 181 zcmZo$#@Mxtk>k|AUHcdq7#ufpDCsgvPu{2}$!2KG$RMvVIZsY(a=b1VOwfpt!B}Im zm7LV%5;*~c1goJTBLh^Q0V6{YNQv=eZ9OX%OGXBb$s2`4CfDj2Fj`EWs3*f{4kB61 z7#WO!62g=B8?jAp)8v~hq_56u%E%C|F?pe?@MIq;)yZZ0HtZ(s%%>R{q$cOfi2|)- K-F#W!SQ!AzYc9?J delta 119 zcmeBL#@M!uk>k|AUHcdq7+f}TDCthVs3*m0&d4CIFFip7kP!Fcj-UFpfDdM1pf zlh5nPFd9$(pxOrbs?<) diff --git a/build/j3270/org/pubvm/j3270/ui/StatusBar$1.class b/build/j3270/org/pubvm/j3270/ui/StatusBar$1.class index c4929f9d94af6c3bf58f197e58a8cf20f6a41ad0..25ecac03c86645ba36bb31b4919e2fe5843850ac 100644 GIT binary patch delta 17 YcmZqRY~bWL^>5cc1_lPljT{v$066dk(EtDd delta 17 YcmZqRY~bWL^>5cc1_lO~jT{v$066~z)Bpeg diff --git a/build/j3270/org/pubvm/j3270/ui/StatusBar.class b/build/j3270/org/pubvm/j3270/ui/StatusBar.class index e1574137ed7a7bda89d1f43513b1b519911a6749..c7a9935c05b7d3c14832742a590815678b39e13f 100644 GIT binary patch delta 17 Zcmcbha6y6N)W2Q(7#J8FH*$Cg002c!273Si delta 17 Zcmcbha6y6N)W2Q(7#J8_Hgb3f002c@27Ukl diff --git a/build/j3270/org/pubvm/j3270/ui/TerminalPanel$1.class b/build/j3270/org/pubvm/j3270/ui/TerminalPanel$1.class index c0bbf6061a580ad937c213e3d7aeb034bf522b73..7cb704de708c9713485d015cbfdedd10d6689f85 100644 GIT binary patch delta 17 ZcmZ22v|5Pc)W2Q(7#J8FH*zR*0sua_1?d0) delta 17 ZcmZ22v|5Pc)W2Q(7#J8_HgYI)0sub91?&I- diff --git a/build/j3270/org/pubvm/j3270/ui/TerminalPanel$2.class b/build/j3270/org/pubvm/j3270/ui/TerminalPanel$2.class index c26fa2c1e00e46b0164e61e62672cdc1778672e3..371789c6aaf6e267e71eb6d715c36c093d5ad0fb 100644 GIT binary patch delta 17 ZcmdnUx{;OR)W2Q(7#J8FH*&0G0subv23i0B delta 17 ZcmdnUx{;OR)W2Q(7#J8_Hgc?F0sub;23-IE diff --git a/build/j3270/org/pubvm/j3270/ui/TerminalPanel.class b/build/j3270/org/pubvm/j3270/ui/TerminalPanel.class index a8bfd05278131494b1f3812764287f1e6fafd30b..7cd527f3edd2baefcf25a4696675fce743202723 100644 GIT binary patch delta 94 zcmdn7fpPB!MvhbecI{(eU~t^XaZXKIDkm{FDJ4;*IJKm-z`3-jIKRj#Co?Zw#n626 q2emjxv&sJIGK{8R(gaKzgUHE#>Q5&x)(~Mdo~*AawfT}pnmzzzl^{L< delta 105 zcmdnHfpNzMMvhbecI{(eU~t*UaZXK2GAA)NDJ4;*IJKm-z`3-jIKRj#Co?Zw#bEMB ywYbTL)t^q%kYqHT{7+q)(FjZ$f=CGiMg|e6*7VZEqLkE>fW%~=uFZQj8uS5R{3hc7 diff --git a/build/lib3270j/org/lib3270j/ConnectionConfig.class b/build/lib3270j/org/lib3270j/ConnectionConfig.class index c724b820cca4b0461e36dc6792dabb73a37e6897..0cc933d760393d8dcfe73a79f0eb5056e7fdd817 100644 GIT binary patch delta 17 ZcmdlhyjPgx)W2Q(7#J8FH*##{1OP%i2B81| delta 17 ZcmdlhyjPgx)W2Q(7#J8_Hgas`1OP%x2BZK0 diff --git a/build/lib3270j/org/lib3270j/ConnectionState.class b/build/lib3270j/org/lib3270j/ConnectionState.class index 6b99c5dae722c1cd14f2bd92ed15dd428dd3180c..73e6adb3d00bfdbb53f1da2d2180c48a1f4b6db1 100644 GIT binary patch delta 17 ZcmX>rd{&s_)W2Q(7#J8FH*y^11OP-^2GIZj delta 17 ZcmX>rd{&s_)W2Q(7#J8_HgX*01OP;82Gjrm diff --git a/build/lib3270j/org/lib3270j/DiagnosticClient$1.class b/build/lib3270j/org/lib3270j/DiagnosticClient$1.class index f97f10235ee85b7e2159440a9ce58316ac809073..47eb1aae30e75796393e12276c4bd505d93b0f0b 100644 GIT binary patch delta 17 ZcmbQvGo6Ry)W2Q(7#J8FH*)Z^0RTH%1)cx^ delta 17 ZcmbQvGo6Ry)W2Q(7#J8_HgfQ@0RTH`1)%@{ diff --git a/build/lib3270j/org/lib3270j/DiagnosticClient$2.class b/build/lib3270j/org/lib3270j/DiagnosticClient$2.class index 8ba4e60eeaa2863c559b5ac13f65c40e2ba3e27e..495f49bc2e1952ba4c1b402719f09ea9eda351f7 100644 GIT binary patch delta 17 ZcmX@ZbB2fG)W2Q(7#J8FH*&bJ0RTc|20Z`( delta 17 ZcmX@ZbB2fG)W2Q(7#J8_HgdSI0RTdC20#D+ diff --git a/build/lib3270j/org/lib3270j/DiagnosticClient.class b/build/lib3270j/org/lib3270j/DiagnosticClient.class index f4c643d0b5ba6917bbb25136ae7fc9ad61ef32ea..86dc20e3669b050a6e4878e3835fc61f87c16fce 100644 GIT binary patch delta 17 Zcmdm?wL^>J)W2Q(7#J8FH*y$=0suo#2220| delta 17 Zcmdm?wL^>J)W2Q(7#J8_HgXt<0suo^22TJ0 diff --git a/build/lib3270j/org/lib3270j/Telnet3270Client.class b/build/lib3270j/org/lib3270j/Telnet3270Client.class index 27c975362c8686990a4886ed0d0bdacc72f9936c..8ada1316dd4b77a334def7f87134d67ae2536b5c 100644 GIT binary patch delta 2494 zcmZuy2~<>782%pc=E38#npmP}AUL3>j&-PWIGz%)j(AXUBb71-7?FS(9ERMov2sh( zv}f*1YA)rHh>nJ4N@ixclDzD z-n0)uuA(&Pd(>1NY3L`=9|II5)Y;tyj@o*6k;_?Tud8#q6l7S9fg(+07Dpix0|f?Q zuyI`NY8fg}j0cQsYI@pmfe|QCpjFu2MNXGnLAW)uK*vKEso`OPQLq`kEqyIz0_Ct9 z3oOH;D=(sM${N)tD_oD0Ts0ha;?S*(aD&prCVGAb#NPv zT8`yWfpHjbT-5IIRAZvRBv=@}%;|90%iKD;W3s^GQWx!Xw z;7W$Jku9GPj+rjj-lt7Rxp*6IhNFjN*36>0Fn~HbG8j zmgMWm#wvjqP{r)*HTBgtx81iy8rB$>qPlxt6j+D#tiI0fD9^1dmv#lxZ8kOvyd0{B9E1Bfqs$TUpf*Q}>#{KB-e(cJfWfejL!yEbs>DbWTr+ ztiYQBhwzq>7(Gil+PEUxrYN5qH-x+WX&PBe@-mC#RQxELd`94YoQ}lL#+;Z=vFCLB zg7X@F75EJo8k=HNCHA6@OZY>>pOSl*jia$AmA{PDafQl1#`(Cch#Lx0j0P;>}q*VC9qJMPUP#3XX8hf^KwANcT*` z-PDkhG?1oK=|-U}+KwU`XghVirclmG+aFodvGD(?S zvh;ljab^flmg0}>#gj5ln6JVlR>C@m z^Xoml&rwDSgvLwgeSugfQ9K6x*v^#FZKTY~i|2wpyEuCiA4s$@w@s2qvdWBEPu++3 zNX`Vsv<5pFPteEsBm`6ohE5`gCzBs~Ye1iKlD$~it+iQZ7E_4)6jgrwNa8KbrYrlp z)aZXxvS;Dc2xY^KGp&S4B;(`;XoqR&OqoG`NV3Er>^h<~e5NQ@$RI_YZ+@?VtDQs7 zD_fH=S9>;BOj6^E77k}H5!u#Eoqf%TpX|ljV5516!hC|h#CjR0F`;dSQshIK%+4bP zfQ6{VB3>Me8DI&P^1l(wc+f4!0jwZBR?>bI&NADpSglyFMoGk4(te$iOuxsB8A(>{ zlo`SBCgpho0;F)$0GoKKY(^@!z>2N7jYsb7Xy9?N-PaWzY6n$SuSvQo`09W4ndQ}l zD9_9CcF~5%y)2KBB-K3sagFEHhSrXlYuQ8qFMb}Phe14~kpK!&mzshs`Z%Y)e J;W|Cv@-NO3@p%9M delta 2460 zcmZ{l3s_V|6vzJqyL)%<4zPkeMC~IH0^^IUP`}kkz%2Su@tKb@R=6%G?BcR$YPvnh z3M;EAMJ!)gl#fD@^+9TAYT3ie-fCr;S=#%hX4aX#o9wp{d^>aRxxe|(IWuR@G+e#= zD)qpH?K=Ss!CxEIHe*){%oxTo93vPaE8R|pOlhfOImY2; z2F0m)i`^bC;Tf5QDkfl}f=L{=;8wBFbd%{ejuJS;VbgePDasUR98=*Gxym3z1w(IP zGbW1$h4XSu=P;s@AumI;TarX}lp+o)X(ktk8`a{RVmEm>YTy-ib8cZdW^&Aei5w_( zyIfkSS49?PbIg%8tJ_teTeUJ3<+y`mp0ulF6*VEakK<0!ZjLjT<8F?7P$!OiXuy~wO;Bk;&=p)iYCjT@q*)VJi!pD zj+4uep>#1>j##T#X6UTFb_;lkC_bit*ujN=5VlL9A z(kkU(1IG)}Y}M&e70&X2y_sWU02e3JXsv}~vwVy6I;O}`evU2jU76x2ojyjlZR6N3 zZAOn)qmjl-*r8x2$1aR!h?(Y?>Bz2hxSZJqm5!PkJy(W1sx%d)Xy@3CJz|2jp1sy` z-0EQLLoqbUd&4nO%b1j(IWESCFXfsa=NO7(W}IN?7TnYdmovrdPGNSIQspkwDz9ZR zCY)694Zc-yisLlCYhlqw7X5>YAMuldpJfvMBD%&LGW^akKwN1YAX05z3}+eA#Ne2; zNCkh25?lXB%6rjh%jroOM~9*Z$Qiss?Ou9ofe8`R&lRU_bD}oV6T?1g(_sg7dL>xvV8DnsOtdU@Gq(ldYTA!4*(}R>w z)TO)V(swO|VrYUPay@<0Wu-5`#DI(u5%GiNI68LJN}V*qX7-b#E5g4&l8{RFv=u=MY4-DTrPgvXu7jemvH(GJK*CT#5REwIf)P*3}|km!#tW^Xz z!|*Xy%XwOy@#(BMK~;a(vlfSbNcykdIxcIoyaWu*Ow6S_2Kv~;^>y?oPIH!ZYPdzq0Z?|p>!br zJp|Gv)j8f8ic1&w5=Ylp=k(TadOv02k&AS18YTaDtl5vYt$2BO3yQ*r^rF&pl%NQF liqEKzrKhjS_Bp676&^>5cc1_lPljT~%z06Y){s{jB1 delta 17 YcmeB^>676&^>5cc1_lO~jT~%z06ZTBt^fc4 diff --git a/build/lib3270j/org/lib3270j/charset/EbcdicTranslator.class b/build/lib3270j/org/lib3270j/charset/EbcdicTranslator.class index 2469a256fa6115f71134d38f9fe9ad404c3659aa..e21435338ed7b6e5461d4b1bf7e63bcd65db9e5f 100644 GIT binary patch delta 17 ZcmX>saae-m)W2Q(7#J8FH*#3>002Uu20#D+ delta 17 ZcmX>saae-m)W2Q(7#J8_HgZ_=002U-215V< diff --git a/build/lib3270j/org/lib3270j/datastream/DataStreamProcessor$OutputSender.class b/build/lib3270j/org/lib3270j/datastream/DataStreamProcessor$OutputSender.class index cfce635d94f9a3c31641d3fd26fb53575b821853..b5b120b77aeb595a9f68854c8f3cf535b951a710 100644 GIT binary patch delta 17 Zcmey)^qq<0)W2Q(7#J8FH*(}N0suzo2BiQ1 delta 17 Zcmey)^qq<0)W2Q(7#J8_Hge=M0suz%2B-i4 diff --git a/build/lib3270j/org/lib3270j/datastream/DataStreamProcessor.class b/build/lib3270j/org/lib3270j/datastream/DataStreamProcessor.class index 725d46d852020ccd3e172507c32392f8b72e1f68..da1d3aab164847d8971178cf42f1021d83e0394c 100644 GIT binary patch literal 14623 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 ChZq3> literal 14246 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 delta 17 YcmZpcZ5cc1_lO~jU3hd06YW+6aWAK diff --git a/build/lib3270j/org/lib3270j/input/InputProcessor.class b/build/lib3270j/org/lib3270j/input/InputProcessor.class index 0158a88263cdf05831c50f942b4aa9c1d0df4fcd..6ec5520e5755762ba09cb2dc71fe61a5440329f6 100644 GIT binary patch literal 7603 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 diff --git a/build/lib3270j/org/lib3270j/listener/ConnectionListener.class b/build/lib3270j/org/lib3270j/listener/ConnectionListener.class index e55630749e869e625aeff7841c3711ebba25deae..515815c5313f79306576af60617a9fd97adefbd8 100644 GIT binary patch delta 17 ZcmZ3&yo8zK)W2Q(7#J8FH*(Bj1OPn&1}*>q delta 17 ZcmZ3&yo8zK)W2Q(7#J8_Hge2i1OPn{1~C8t diff --git a/build/lib3270j/org/lib3270j/listener/ScreenUpdateListener.class b/build/lib3270j/org/lib3270j/listener/ScreenUpdateListener.class index 706455b14bf147fdea6f9439738299365d2160ac..d589c15c7801709409eddb5a067f99cec8644153 100644 GIT binary patch delta 17 Zcmeyx^oxn()W2Q(7#J8FH*yp)0su!(2Ce`A delta 17 Zcmeyx^oxn()W2Q(7#J8_HgXg(0su!|2C)DD diff --git a/build/lib3270j/org/lib3270j/protocol/DS3270Constants.class b/build/lib3270j/org/lib3270j/protocol/DS3270Constants.class index 1fdbea2390673139afb6d865ff6fff3ac318e8c4..6280c87f7b4810072fbdce6ac94af1b4605d1eda 100644 GIT binary patch delta 17 ZcmZ4IyUv&6)W2Q(7#J8FH*zdf0{}-R2L%8C delta 17 ZcmZ4IyUv&6)W2Q(7#J8_HgYUe0{}-g2M7QF diff --git a/build/lib3270j/org/lib3270j/protocol/TN3270EConstants.class b/build/lib3270j/org/lib3270j/protocol/TN3270EConstants.class index 0de4f6972d84c5e0f0cf70b09944fe2f5b2b5e98..23866402678c26b47aaa6f9080194c0a9a6b7244 100644 GIT binary patch delta 17 ZcmbQPFkOM;)W2Q(7#J8FH*)X`002F_1<(Kh delta 17 ZcmbQPFkOM;)W2Q(7#J8_HgfO_002G91=9ck diff --git a/build/lib3270j/org/lib3270j/protocol/TelnetConstants.class b/build/lib3270j/org/lib3270j/protocol/TelnetConstants.class index f95779f11dd8039f003a8cbcbf08063090a7e49f..e9ecbdfe4e40c9fada55dfdc926a77a67e5e1a0d 100644 GIT binary patch delta 17 ZcmbO)IbV|F)W2Q(7#J8FH*!qp0RTSs237z7 delta 17 ZcmbO)IbV|F)W2Q(7#J8_HgZho0RTS*23Y_A diff --git a/build/lib3270j/org/lib3270j/screen/ExtendedAttribute.class b/build/lib3270j/org/lib3270j/screen/ExtendedAttribute.class index 63a37cfb2d827c1e686ba3cdc8b71f7bfeaa4060..eac570f04e063aa0f7bcb900e2ac18da0756abe6 100644 GIT binary patch delta 17 ZcmbQlHHnMk)W2Q(7#J8FH*#>X0suO51&ROw delta 17 ZcmbQlHHnMk)W2Q(7#J8_Hga&W0suOK1&sgz diff --git a/build/lib3270j/org/lib3270j/screen/ScreenBuffer.class b/build/lib3270j/org/lib3270j/screen/ScreenBuffer.class index 2dbf12c1ed172c3694f0d303f3857cd0f56bc900..aaf779b61bd2f01c6bc5f41038860bb9ff8fde62 100644 GIT binary patch delta 17 ZcmbPbHp`6T)W2Q(7#J8FH*yF`0{}q51`q%M delta 17 ZcmbPbHp`6T)W2Q(7#J8_HgX6_0{}qK1`_}P diff --git a/build/lib3270j/org/lib3270j/telnet/TelnetConnection.class b/build/lib3270j/org/lib3270j/telnet/TelnetConnection.class index 3671d4353d966dba207f995d3471a5695b6e17c8..735db9f31f2b804d0079aea67649d72c32e247c7 100644 GIT binary patch delta 17 YcmZqDY0}|1^>5cc1_lPljU2y30X|;_t^fc4 delta 17 YcmZqDY0}|1^>5cc1_lO~jU2y30X}X9u>b%7 diff --git a/build/lib3270j/org/lib3270j/telnet/TelnetFSM$TN3270ESubmode.class b/build/lib3270j/org/lib3270j/telnet/TelnetFSM$TN3270ESubmode.class index 89f0eb331a4ea9216ffd9b6b050297f782e3ac3c..241800d5cf57fb39df3a7c78de4c17ba1be10c4b 100644 GIT binary patch delta 17 YcmZqYYUkoO^>5cc1_lPljU4}306P2zXaE2J delta 17 YcmZqYYUkoO^>5cc1_lO~jU4}306Pl?YXATM diff --git a/build/lib3270j/org/lib3270j/telnet/TelnetFSM.class b/build/lib3270j/org/lib3270j/telnet/TelnetFSM.class index 58aed75b3c66a8efdc2ca329d99c0cd89d6796fc..4a3210d68468c68cb591178db913e35baf827234 100644 GIT binary patch delta 19 bcmdnd#<-)6k>k|AUHcdq7#ufp7&rp}QXmI3 delta 19 bcmdnd#<-)6k>k|AUHcdq7+f}T7&rp}QZENL diff --git a/build_all.sh b/build_all.sh new file mode 100755 index 0000000..f11c32f --- /dev/null +++ b/build_all.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -e + +echo "=== Building j3270 (Desktop JAR) and a3270 (Android APK) ===" + +export JAVA_HOME="/Users/rudi/.sdkman/candidates/java/21.0.6-sem" +export ANDROID_HOME="/Users/rudi/Library/Android/sdk" + +GRADLE_BIN="/Users/rudi/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/bin/gradle" +BUILD_DIR="$(pwd)/build" + +mkdir -p "$BUILD_DIR" + +echo "Building Android APK (a3270)..." +"$GRADLE_BIN" :a3270:assembleDebug + +echo "Building Desktop App JAR (j3270)..." +mkdir -p "$BUILD_DIR/lib3270j" "$BUILD_DIR/j3270" +"$JAVA_HOME/bin/javac" -d "$BUILD_DIR/lib3270j" $(find lib3270j/src -name "*.java") +"$JAVA_HOME/bin/javac" -cp "$BUILD_DIR/lib3270j" -d "$BUILD_DIR/j3270" $(find j3270/src -name "*.java") + +echo "Main-Class: org.pubvm.j3270.J3270App" > "$BUILD_DIR/MANIFEST.MF" +echo "" >> "$BUILD_DIR/MANIFEST.MF" + +"$JAVA_HOME/bin/jar" cvfm "$BUILD_DIR/j3270.jar" "$BUILD_DIR/MANIFEST.MF" \ + -C "$BUILD_DIR/lib3270j" . \ + -C "$BUILD_DIR/j3270" . + +# Copy APK to build/ +if [ -f "a3270/build/outputs/apk/debug/a3270-debug.apk" ]; then + cp "a3270/build/outputs/apk/debug/a3270-debug.apk" "$BUILD_DIR/a3270.apk" + echo "Copied a3270-debug.apk to $BUILD_DIR/a3270.apk" +fi + +echo "=== Build Complete ===" +echo "Artifacts in $BUILD_DIR:" +ls -lh "$BUILD_DIR"/*.jar "$BUILD_DIR"/*.apk 2>/dev/null || true diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..50234ab --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +android.useAndroidX=true +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m diff --git a/j3270/src/main/java/org/pubvm/j3270/J3270App.java b/j3270/src/main/java/org/pubvm/j3270/J3270App.java index d9e3345..829ae1f 100644 --- a/j3270/src/main/java/org/pubvm/j3270/J3270App.java +++ b/j3270/src/main/java/org/pubvm/j3270/J3270App.java @@ -350,12 +350,16 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate @Override public void onScreenUpdated() { SwingUtilities.invokeLater(() -> { - if (client != null) { - client.getInputProcessor().setKeyboardLocked(false); - } + // During an active file transfer, let the CUT/DFT handler drive + // keyboard state. In x3270, ft_cut_data() runs before WCC + // keyboard-restore is applied — the keyboard stays locked for the + // entire CUT transfer. if (fileTransfer != null) { fileTransfer.onScreenUpdated(); } + if (client != null && (fileTransfer == null || !fileTransfer.isTransferActive())) { + client.getInputProcessor().setKeyboardLocked(false); + } terminalPanel.repaint(); statusBar.updateStatus(); }); diff --git a/j3270/src/main/java/org/pubvm/j3270/ft/FileTransfer.java b/j3270/src/main/java/org/pubvm/j3270/ft/FileTransfer.java index 02cbb33..affed6f 100644 --- a/j3270/src/main/java/org/pubvm/j3270/ft/FileTransfer.java +++ b/j3270/src/main/java/org/pubvm/j3270/ft/FileTransfer.java @@ -22,6 +22,10 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { private static final Logger log = Logger.getLogger(FileTransfer.class.getName()); + public enum FTMode { + UNKNOWN, CUT, DFT + } + public interface FileTransferCallback { void onTransferStarted(); void onTransferRunning(); @@ -36,6 +40,7 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { private FTConfig currentConfig; private File localFile; private FTState state = FTState.NONE; + private FTMode activeMode = FTMode.UNKNOWN; private FTCut cutHandler; private FTDft dftHandler; @@ -64,6 +69,7 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { this.currentConfig = config; this.localFile = new File(config.getLocalFilename()); + this.activeMode = FTMode.UNKNOWN; // Check overwrite if (config.isReceive() && !config.isAppend() && !config.isOverwrite()) { @@ -83,14 +89,6 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { client.getDataStreamProcessor().setFTDft(dftHandler); } - try { - cutHandler.initTransfer(localFile); - dftHandler.initTransfer(localFile); - } catch (IOException e) { - cleanupHandlers(false); - return "Failed to open local file: " + e.getMessage(); - } - // Build and type the IND$FILE command String command = config.buildCommand(); log.info("Starting IND$FILE transfer with command: " + command); @@ -130,9 +128,19 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { } } + /** Check whether a file transfer is currently active. */ + public boolean isTransferActive() { + return state != FTState.NONE; + } + + public FTMode getActiveMode() { + return activeMode; + } + /** Must be called after every screen update to drive CUT mode. */ public void onScreenUpdated() { - if (state == FTState.AWAIT_ACK || state == FTState.RUNNING || state == FTState.ABORT_WAIT) { + if ((activeMode == FTMode.CUT || activeMode == FTMode.UNKNOWN) && + (state == FTState.AWAIT_ACK || state == FTState.RUNNING || state == FTState.ABORT_WAIT)) { cutHandler.processScreenUpdate(); } } @@ -179,6 +187,7 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { boolean success = (errorMessage == null); cleanupHandlers(success); setState(FTState.NONE); + activeMode = FTMode.UNKNOWN; currentConfig = null; } @@ -186,6 +195,32 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { @Override public void onTransferRunning() { + // Mode detection check + StackTraceElement[] st = Thread.currentThread().getStackTrace(); + boolean isDft = false; + for (StackTraceElement elem : st) { + if (elem.getClassName().contains("FTDft")) { + isDft = true; + break; + } + } + + if (activeMode == FTMode.UNKNOWN) { + activeMode = isDft ? FTMode.DFT : FTMode.CUT; + log.info("FT mode established: " + activeMode); + try { + if (activeMode == FTMode.DFT) { + dftHandler.initTransfer(localFile); + } else { + cutHandler.initTransfer(localFile); + } + } catch (IOException e) { + log.warning("Failed to open local file for " + activeMode + ": " + e.getMessage()); + onTransferAborted("Failed to open local file: " + e.getMessage()); + return; + } + } + cancelTimeout(); setState(FTState.RUNNING); SwingUtilities.invokeLater(callback::onTransferRunning); @@ -193,7 +228,7 @@ public class FileTransfer implements FTCut.FTCutListener, FTDft.FTDftListener { @Override public void onTransferComplete(String errorMessage) { - completeTransfer(null); + completeTransfer(errorMessage); SwingUtilities.invokeLater(() -> { if (errorMessage == null) { callback.onTransferComplete("Transfer complete."); diff --git a/lib3270j/src/main/java/org/lib3270j/Telnet3270Client.java b/lib3270j/src/main/java/org/lib3270j/Telnet3270Client.java index 06d879d..06119f2 100644 --- a/lib3270j/src/main/java/org/lib3270j/Telnet3270Client.java +++ b/lib3270j/src/main/java/org/lib3270j/Telnet3270Client.java @@ -51,6 +51,7 @@ public class Telnet3270Client { // Wire up the output sender: DSProcessor -> FSM -> TelnetConnection dsProcessor.setOutputSender(fsm::send3270Data); + dsProcessor.setInputProcessor(inputProcessor); } /** diff --git a/lib3270j/src/main/java/org/lib3270j/datastream/DataStreamProcessor.java b/lib3270j/src/main/java/org/lib3270j/datastream/DataStreamProcessor.java index b2ecec3..8acac23 100644 --- a/lib3270j/src/main/java/org/lib3270j/datastream/DataStreamProcessor.java +++ b/lib3270j/src/main/java/org/lib3270j/datastream/DataStreamProcessor.java @@ -34,6 +34,9 @@ public class DataStreamProcessor { // File Transfer DFT handler private org.lib3270j.ft.FTDft ftDft; + // Input processor reference to manage keyboard locking state + private org.lib3270j.input.InputProcessor inputProcessor; + /** Functional interface for sending output back through the telnet stack. */ @FunctionalInterface public interface OutputSender { @@ -56,6 +59,10 @@ public class DataStreamProcessor { this.ftDft = ftDft; } + public void setInputProcessor(org.lib3270j.input.InputProcessor inputProcessor) { + this.inputProcessor = inputProcessor; + } + public void addScreenUpdateListener(ScreenUpdateListener l) { screenListeners.add(l); } @@ -231,6 +238,12 @@ public class DataStreamProcessor { log.fine("WCC: " + String.format("0x%02x", wcc) + " reset=" + wccReset(wcc) + " alarm=" + alarm + " kbdRestore=" + kbdRestore + " resetMdt=" + resetMdt); + if (kbdRestore || inputProcessor != null) { + if (inputProcessor != null) { + inputProcessor.setKeyboardLocked(false); + } + } + if (resetMdt) { resetAllMDT(); } @@ -471,6 +484,10 @@ public class DataStreamProcessor { if (!faIsProtected(faVal & 0xFF)) { ea.ec = 0; ea.ucs4 = 0; + ea.fg = 0; + ea.bg = 0; + ea.gr = 0; + ea.cs = 0; } } baddr = (baddr + 1) % size; @@ -614,6 +631,10 @@ public class DataStreamProcessor { // ========== Read Modified ========== private void processReadModified(boolean all) { + if (ftDft != null) { + ftDft.readModified(); + } + outputPos = 0; int aid = AID_NO; // Last AID diff --git a/lib3270j/src/main/java/org/lib3270j/ft/FTConstants.java b/lib3270j/src/main/java/org/lib3270j/ft/FTConstants.java index 62d12ec..a10a3e3 100644 --- a/lib3270j/src/main/java/org/lib3270j/ft/FTConstants.java +++ b/lib3270j/src/main/java/org/lib3270j/ft/FTConstants.java @@ -183,6 +183,12 @@ public final class FTConstants { * Decode a CUT-mode base-64 encoded integer from EBCDIC. * Converts a table6-encoded EBCDIC character to its 6-bit value. */ + public static int from6(int ebcdicByte, org.lib3270j.charset.EbcdicTranslator translator) { + char ascii = translator.ebcdicToUnicode(ebcdicByte & 0xFF); + int idx = TABLE6.indexOf(ascii); + return idx >= 0 ? idx : 0; + } + public static int from6(int ebcdicByte) { // First convert EBCDIC to ASCII via IND$FILE's table int ascii = FT2ASC[ebcdicByte & 0xFF]; @@ -193,6 +199,12 @@ public final class FTConstants { /** * Encode a 6-bit value into a table6-encoded EBCDIC character. */ + public static int to6(int value, org.lib3270j.charset.EbcdicTranslator translator) { + char ascii = TABLE6.charAt(value & 0x3F); + int ebc = translator.unicodeToEbcdic(ascii); + return ebc >= 0 ? ebc : ASC2FT[ascii & 0xFF]; + } + public static int to6(int value) { char ascii = TABLE6.charAt(value & 0x3F); return ASC2FT[ascii & 0xFF]; diff --git a/lib3270j/src/main/java/org/lib3270j/ft/FTCut.java b/lib3270j/src/main/java/org/lib3270j/ft/FTCut.java index 8733608..2001f12 100644 --- a/lib3270j/src/main/java/org/lib3270j/ft/FTCut.java +++ b/lib3270j/src/main/java/org/lib3270j/ft/FTCut.java @@ -7,6 +7,7 @@ import static org.lib3270j.ft.FTConstants.*; import static org.lib3270j.protocol.DS3270Constants.*; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.logging.Logger; /** @@ -49,10 +50,10 @@ public class FTCut { private static final String ALPHAS = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%&_()<+,-./:>?"; - private static final int SELECTOR_0 = 0x5E; // ';' - private static final int SELECTOR_1 = 0x7E; // '=' - private static final int SELECTOR_2 = 0x5C; // '*' - private static final int SELECTOR_3 = 0x7D; // '\'' + private static final int SELECTOR_0 = 0x5E; // ';' (EBCDIC) + private static final int SELECTOR_1 = 0x7E; // '=' (EBCDIC) + private static final int SELECTOR_2 = 0x5C; // '*' (EBCDIC) + private static final int SELECTOR_3 = 0x7D; // '\'' (EBCDIC) private static final int[] XLATE_0 = { 0x40,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2, @@ -110,6 +111,55 @@ public class FTCut { this.listener = listener; } + /** + * Initialize CUT mode with active streams. + */ + public void initTransfer(InputStream in, OutputStream out) { + this.inputStream = in; + this.outputStream = out; + resetState(); + } + + /** + * Initialize CUT mode for a new transfer. + */ + public void initTransfer(File localFile) throws IOException { + FTConfig config = listener.getConfig(); + resetState(); + + if (config.isReceive()) { + boolean append = config.isAppend(); + outputStream = new FileOutputStream(localFile, append); + inputStream = null; + } else { + inputStream = new FileInputStream(localFile); + outputStream = null; + } + } + + private void resetState() { + xferInProgress = false; + expandedLength = 0; + quadrant = -1; + xlateBuffered = 0; + xlateBufIx = 0; + cutEof = false; + lastCr = false; + } + + /** + * Clean up CUT mode resources. + */ + public void cleanup() { + xferInProgress = false; + try { + if (inputStream != null) { inputStream.close(); inputStream = null; } + if (outputStream != null) { outputStream.close(); outputStream = null; } + } catch (IOException e) { + log.warning("Error closing file: " + e.getMessage()); + } + } + /** * Process a CUT-mode screen update. * Called by the transfer coordinator when the screen changes during a transfer. @@ -120,7 +170,12 @@ public class FTCut { // CUT frames MUST have a skip field attribute at O_SF (1919) byte sfAttr = screen.getCellFAByte(O_SF); if (sfAttr == 0 || !isSkip(sfAttr)) { - // Not a CUT frame (likely local echo or intermediate screen), ignore + // Not a CUT frame (likely local echo, menu return, or intermediate screen) + if (xferInProgress) { + log.warning("CUT: Received non-CUT frame while transfer in progress. Host aborted."); + xferInProgress = false; + listener.onTransferAborted("Host aborted transfer (returned to menu)"); + } return; } @@ -149,42 +204,6 @@ public class FTCut { return (attr & FA_PROTECT) != 0 && (attr & FA_NUMERIC) != 0; } - /** - * Initialize CUT mode for a new transfer. - */ - public void initTransfer(File localFile) throws IOException { - FTConfig config = listener.getConfig(); - xferInProgress = false; - expandedLength = 0; - quadrant = -1; - xlateBuffered = 0; - xlateBufIx = 0; - cutEof = false; - lastCr = false; - - if (config.isReceive()) { - boolean append = config.isAppend(); - outputStream = new FileOutputStream(localFile, append); - inputStream = null; - } else { - inputStream = new FileInputStream(localFile); - outputStream = null; - } - } - - /** - * Clean up CUT mode resources. - */ - public void cleanup() { - xferInProgress = false; - try { - if (inputStream != null) { inputStream.close(); inputStream = null; } - if (outputStream != null) { outputStream.close(); outputStream = null; } - } catch (IOException e) { - log.warning("Error closing file: " + e.getMessage()); - } - } - // ========== Control Code Processing ========== private void cutControlCode() { @@ -218,7 +237,6 @@ public class FTCut { xferInProgress = false; cutAck(); - // Extract error message from the host (positions 4-83) String msg = extractHostMessage(); listener.onTransferAborted(msg); break; @@ -242,7 +260,6 @@ public class FTCut { char ch = translator.ebcdicToUnicode(ebc); sb.append(ch); } - // Trim trailing spaces and '$' String msg = sb.toString().stripTrailing(); if (msg.endsWith("$")) { msg = msg.substring(0, msg.length() - 1).stripTrailing(); @@ -252,12 +269,10 @@ public class FTCut { // ========== Data Request (Upload) ========== - /** - * Process a data request from the host (upload: send data to host). - */ private void cutDataRequest() { - int seq = screen.getCellEC(O_DR_FRAME_SEQ); - log.fine("CUT: DATA_REQUEST seq=" + from6(seq)); + int seqEbc = screen.getCellEC(O_DR_FRAME_SEQ); + int seq = FTConstants.from6(seqEbc, translator); + log.fine("CUT: DATA_REQUEST seq=" + seq); if (listener.getCurrentState() == FTState.ABORT_WAIT) { cutAbort("Transfer cancelled by user", SC_ABORT_FILE); @@ -266,7 +281,6 @@ public class FTCut { FTConfig config = listener.getConfig(); - // Read data from local file into screen buffer int count = 0; try { while (count < O_UP_MAX && !cutEof) { @@ -284,32 +298,28 @@ public class FTCut { return; } - // EOF with no data → send EOF marker if (count == 0 && cutEof) { screen.setCell(O_UP_DATA, EOF_DATA1); screen.setCell(O_UP_DATA + 1, EOF_DATA2); count = 2; } - // Compute frame fields - screen.setCell(O_UP_FRAME_SEQ, seq); + screen.setCell(O_UP_FRAME_SEQ, seqEbc); - // Checksum int cs = 0; for (int i = 0; i < count; i++) { cs ^= screen.getCellEC(O_UP_DATA + i); } - screen.setCell(O_UP_CSUM, to6(cs)); - screen.setCell(O_UP_LEN, to6((count >> 6) & 0x3F)); - screen.setCell(O_UP_LEN + 1, to6(count & 0x3F)); + screen.setCell(O_UP_CSUM, FTConstants.to6(cs & 0x3F, translator)); + screen.setCell(O_UP_LEN, FTConstants.to6((count >> 6) & 0x3F, translator)); + screen.setCell(O_UP_LEN + 1, FTConstants.to6(count & 0x3F, translator)); - // Hide the data field (change SF attribute to zero intensity) + // Hide data field by setting zero intensity on field attribute byte attr = screen.getCellFAByte(O_DR_SF); - attr = (byte) ((attr & ~FA_INTENSITY) | FA_INT_ZERO_NSEL); + attr = (byte) ((attr & ~FA_INTENSITY) | FA_INT_ZERO_NSEL | FA_MODIFY); screen.setCellFA(O_DR_SF, attr); - // Send it - log.fine("CUT: > DATA seq=" + from6(seq) + " len=" + count); + log.fine("CUT: > DATA seq=" + seq + " len=" + count); expandedLength += count; listener.onBytesTransferred(expandedLength); input.sendAidForFT(AID_ENTER); @@ -317,9 +327,6 @@ public class FTCut { // ========== Data (Download) ========== - /** - * Process data from the host (download: receive data from host). - */ private void cutData() { log.fine("CUT: DATA"); @@ -330,9 +337,8 @@ public class FTCut { FTConfig config = listener.getConfig(); - // Extract raw data - int rawLength = (from6(screen.getCellEC(O_DT_LEN)) << 6) | - from6(screen.getCellEC(O_DT_LEN + 1)); + int rawLength = (FTConstants.from6(screen.getCellEC(O_DT_LEN), translator) << 6) | + FTConstants.from6(screen.getCellEC(O_DT_LEN + 1), translator); if (rawLength > O_RESPONSE - O_DT_DATA) { cutAbort("Oversized CUT data frame", SC_ABORT_XMIT); @@ -344,7 +350,6 @@ public class FTCut { rawData[i] = (byte) screen.getCellEC(O_DT_DATA + i); } - // Check for EOF marker if (rawLength == 2 && (rawData[0] & 0xFF) == EOF_DATA1 && (rawData[1] & 0xFF) == EOF_DATA2) { log.fine("CUT: EOF marker received"); @@ -352,7 +357,6 @@ public class FTCut { return; } - // Convert and write to local file try { byte[] converted = convertDownload(rawData, rawLength, config); if (outputStream != null) { @@ -386,31 +390,20 @@ public class FTCut { private void cutAbort(String message, int reason) { log.warning("CUT: ABORT — " + message); - // Write abort frame to the response area screen.setCell(RO_FRAME_TYPE, RFT_CONTROL_CODE); screen.setCell(RO_FRAME_SEQ, screen.getCellEC(O_DT_FRAME_SEQ)); screen.setCell(RO_REASON_CODE, (reason >> 8) & 0xFF); screen.setCell(RO_REASON_CODE + 1, reason & 0xFF); - // Send PF2 to signal abort input.sendAidForFT(AID_PF2); - listener.onTransferAborted(message); } // ========== Character Translation ========== /** - * Convert received EBCDIC data to local format. - * Handles ASCII mode (with optional CR processing and remapping) - * and binary mode (raw passthrough). - * - * The quadrant tables decode wire bytes into IND$FILE's "pseudo-ASCII" - * representation. For the remap path, control codes (< 0x20 and - * 0x80-0x9E) are treated as direct Unicode codepoints, while printable - * characters are re-mapped through ASC2FT (inverting IND$FILE's built-in - * EBCDIC→ASCII table) back to real EBCDIC, then to Unicode. - * This matches x3270's upload_convert() logic. + * Convert received CUT EBCDIC data to local format. + * Matching x3270 upload_convert logic. */ private byte[] convertDownload(byte[] rawData, int length, FTConfig config) throws IOException { @@ -421,81 +414,59 @@ public class FTCut { while (true) { if (quadrant < 0) { - // Find the quadrant for (quadrant = 0; quadrant < 4; quadrant++) { if (c == SELECTORS[quadrant]) break; } if (quadrant >= 4) { throw new IOException("CUT conversion error (quadrant selector not found)"); } - break; // continue outer loop + break; } if (c < 0x40 || c > 0xF9) { throw new IOException("CUT conversion error (data out of bounds)"); } - char asciiChar = translator.ebcdicToUnicode(c); + char asciiChar = (char) FT2ASC[c & 0xFF]; int ix = ALPHAS.indexOf(asciiChar); if (ix < 0) { - // Try a different quadrant quadrant = -1; - continue; // retry loop + continue; } - if (quadrant != 2 && c != 0xC1 && QUADS[quadrant][ix] == 0) { - // Try a different quadrant + if (!(quadrant == 2 && c == 0xC1) && QUADS[quadrant][ix] == 0) { quadrant = -1; - continue; // retry + continue; } - // Map the character — this produces IND$FILE's pseudo-ASCII byte int decoded = QUADS[quadrant][ix]; if (config.isAscii() && config.isCrFlag() && (decoded == 0x0D || decoded == 0x1A)) { - break; // Ignore bare CR and EOF markers in ASCII stream + break; } if (!config.isAscii() || !config.isRemapFlag()) { - // Binary or ASCII-no-remap: emit the decoded byte as-is out.write(decoded); break; } - /* - * ASCII with remap: invert IND$FILE's EBCDIC→ASCII translation. - * - * Control codes (< 0x20) and high control range (0x80-0x9E, - * except 0x9F) are treated as direct Unicode codepoints. - * IND$FILE maps EBCDIC 0xE1 to pseudo-ASCII 0x9F, so - * 0xFF is the special marker that maps back to U+009F. - * Everything else is a printable character that needs - * the ASC2FT→ebcdicToUnicode remap chain. - */ if (decoded < 0x20 || (decoded >= 0x80 && decoded < 0xA0 && decoded != 0x9F)) { - // Control code — emit as its Unicode codepoint directly - out.write(String.valueOf((char) decoded).getBytes( - java.nio.charset.StandardCharsets.UTF_8)); + out.write(String.valueOf((char) decoded).getBytes(StandardCharsets.UTF_8)); } else if (decoded == 0xFF) { - // Special case: 0xFF → U+009F - out.write(String.valueOf((char) 0x9F).getBytes( - java.nio.charset.StandardCharsets.UTF_8)); + out.write(String.valueOf((char) 0x9F).getBytes(StandardCharsets.UTF_8)); } else { - // Displayable character: invert IND$FILE's table - int ebc = FTConstants.ASC2FT[decoded & 0xFF]; + int ebc = ASC2FT[decoded & 0xFF]; char unicodeChar = translator.ebcdicToUnicode(ebc); - out.write(String.valueOf(unicodeChar).getBytes( - java.nio.charset.StandardCharsets.UTF_8)); + out.write(String.valueOf(unicodeChar).getBytes(StandardCharsets.UTF_8)); } break; - } // end while(true) chunk + } } return out.toByteArray(); } private int xlateGetc(FTConfig config) throws IOException { - // Return buffered data first if (xlateBuffered > 0) { int r = xlateBuf[xlateBufIx++]; xlateBuffered--; @@ -509,7 +480,7 @@ public class FTCut { int localByte = c & 0xFF; int nc = 0; - int[] cbuf = new int[4]; // max 4 bytes (2 for \r + 2 for \n if quadrant encoded) + int[] cbuf = new int[4]; if (config.isAscii()) { if (config.isCrFlag() && !lastCr && localByte == '\n') { @@ -532,7 +503,6 @@ public class FTCut { private int uploadConvert(int localByte, int[] cbuf, int offset, FTConfig config) { int ebc; if (localByte == 0) { - // Nulls are special in the 'OTHER_2' quadrant if (quadrant != 2) { quadrant = 2; // OTHER_2 cbuf[offset] = SELECTORS[quadrant]; @@ -545,25 +515,25 @@ public class FTCut { } if (!config.isAscii() || !config.isRemapFlag()) { - // Binary or Ascii without remap: treat byte directly ebc = localByte & 0xFF; } else { - // Ascii with remap: locally read ASCII translates to actual EBCDIC, then maps to IND$FILE's pseudo-ASCII int standardEbc = translator.unicodeToEbcdic((char) localByte); if (standardEbc < 0) { - standardEbc = 0x40; // Space as fallback + standardEbc = 0x40; } - ebc = org.lib3270j.ft.FTConstants.FT2ASC[standardEbc & 0xFF]; + ebc = FTConstants.FT2ASC[standardEbc & 0xFF]; } return storeUpload(ebc, cbuf, offset); } - private int storeUpload(int ebc, int[] obBuf, int offset) { + private int storeUpload(int pseudoAsciiByte, int[] obBuf, int offset) { if (quadrant >= 0) { for (int i = 0; i < 77; i++) { - if (QUADS[quadrant][i] == ebc) { - obBuf[offset] = translator.unicodeToEbcdic(ALPHAS.charAt(i)); + if (QUADS[quadrant][i] == pseudoAsciiByte) { + char ch = ALPHAS.charAt(i); + int ebc = translator.unicodeToEbcdic(ch); + obBuf[offset] = ebc >= 0 ? ebc : 0x40; return 1; } } @@ -572,16 +542,18 @@ public class FTCut { for (quadrant = 0; quadrant < 4; quadrant++) { if (quadrant == oq) continue; for (int i = 0; i < 77; i++) { - if (QUADS[quadrant][i] == ebc) { + if (QUADS[quadrant][i] == pseudoAsciiByte) { + char ch = ALPHAS.charAt(i); + int ebc = translator.unicodeToEbcdic(ch); obBuf[offset] = SELECTORS[quadrant]; - obBuf[offset + 1] = translator.unicodeToEbcdic(ALPHAS.charAt(i)); + obBuf[offset + 1] = ebc >= 0 ? ebc : 0x40; return 2; } } } quadrant = -1; - // Fallback safety measure - obBuf[offset] = translator.unicodeToEbcdic('?'); + int questionEbc = translator.unicodeToEbcdic('?'); + obBuf[offset] = questionEbc >= 0 ? questionEbc : 0x6F; return 1; } } diff --git a/lib3270j/src/main/java/org/lib3270j/ft/FTDft.java b/lib3270j/src/main/java/org/lib3270j/ft/FTDft.java index 9aa5c6a..bc1079e 100644 --- a/lib3270j/src/main/java/org/lib3270j/ft/FTDft.java +++ b/lib3270j/src/main/java/org/lib3270j/ft/FTDft.java @@ -5,6 +5,7 @@ import org.lib3270j.charset.EbcdicTranslator; import static org.lib3270j.ft.FTConstants.*; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.logging.Logger; /** @@ -17,6 +18,9 @@ public class FTDft { private static final Logger log = Logger.getLogger(FTDft.class.getName()); + private static final String OPEN_MSG = "FT:MSG"; + private static final String END_TRANSFER = "TRANS03"; + /** Callback for transfer events (shared interface with CUT) */ public interface FTDftListener { void onTransferRunning(); @@ -34,7 +38,7 @@ public class FTDft { private final FTDftListener listener; // DFT state - private long recnum = 0; + private long recnum = 1; private boolean dftEof = false; private boolean messageFlag = false; private long bytesTransferred = 0; @@ -56,17 +60,20 @@ public class FTDft { } /** - * Initialize DFT mode for a new transfer. + * Initialize DFT mode with active streams. + */ + public void initTransfer(InputStream in, OutputStream out) { + this.inputStream = in; + this.outputStream = out; + resetState(); + } + + /** + * Initialize DFT mode for a new transfer from file. */ public void initTransfer(File localFile) throws IOException { FTConfig config = listener.getConfig(); - recnum = 0; - dftEof = false; - messageFlag = false; - bytesTransferred = 0; - dftSaveBuf = null; - dftSaveBufLen = 0; - lastCr = false; + resetState(); if (config.isReceive()) { outputStream = new FileOutputStream(localFile, config.isAppend()); @@ -77,6 +84,16 @@ public class FTDft { } } + private void resetState() { + recnum = 1; + dftEof = false; + messageFlag = false; + bytesTransferred = 0; + dftSaveBuf = null; + dftSaveBufLen = 0; + lastCr = false; + } + /** * Clean up DFT mode resources. */ @@ -115,7 +132,7 @@ public class FTDft { switch (requestCode) { case TR_OPEN_REQ: - dftOpenRequest(); + dftOpenRequest(data, offset, length); break; case TR_INSERT_REQ: dftInsertRequest(data, payloadStart, offset + length - payloadStart); @@ -142,11 +159,53 @@ public class FTDft { // ========== Open Request ========== - private void dftOpenRequest() { - log.fine("DFT: Open"); - listener.onTransferRunning(); - // Send acknowledgement - dftDataAck(); + private void dftOpenRequest(byte[] data, int sfOffset, int sfLength) { + log.fine("DFT: Open request"); + + // Parse open request payload matching x3270 + // sfLength is the 2-byte length value at sfOffset + int sfLenVal = ((data[sfOffset] & 0xFF) << 8) | (data[sfOffset + 1] & 0xFF); + String nameBuf = ""; + + if (sfLenVal == 0x23 && sfOffset + 3 + 25 <= data.length) { + nameBuf = extractName(data, sfOffset + 3 + 25, 7); + } else if (sfLenVal == 0x29 && sfOffset + 3 + 31 <= data.length) { + nameBuf = extractName(data, sfOffset + 3 + 31, 7); + } + + if (OPEN_MSG.equalsIgnoreCase(nameBuf)) { + messageFlag = true; + log.info("DFT: Open request for message stream"); + } else { + messageFlag = false; + listener.onTransferRunning(); + } + + dftEof = false; + recnum = 1; + + // Acknowledge Open matching x3270 (SF_TRANSFER_DATA + 0x0009) + dftOpenAck(); + } + + private String extractName(byte[] data, int start, int maxLen) { + StringBuilder sb = 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); + } + return sb.toString().trim(); + } + + private void dftOpenAck() { + ByteArrayOutputStream out = new ByteArrayOutputStream(6); + out.write(AID_SF); + out.write(0); out.write(5); // SF length + out.write(SF_TRANSFER_DATA); + out.write(0); out.write(9); // OpenAck response code 0x0009 + input.sendStructuredFieldData(out.toByteArray()); } // ========== Insert Request (host sending data for download) ========== @@ -159,12 +218,11 @@ public class FTDft { private void dftDataInsert(byte[] data, int offset, int length) { FTConfig config = listener.getConfig(); - if (listener.getCurrentState() == FTState.ABORT_WAIT) { + if (!messageFlag && listener.getCurrentState() == FTState.ABORT_WAIT) { dftAbort("Transfer cancelled by user", TR_DATA_INSERT); return; } - // Parse the SF payload to find data // Skip the 2-byte request code int pos = offset + 2; int end = offset + length; @@ -174,13 +232,19 @@ public class FTDft { int headerCode = data[pos] & 0xFF; if (headerCode == TR_BEGIN_DATA) { - // Next 2 bytes are data length (including the 3-byte header) if (pos + 3 > end) break; int dataLen = ((data[pos + 1] & 0xFF) << 8) | (data[pos + 2] & 0xFF); - int actualDataLen = dataLen - 3; // subtract header + int actualDataLen = dataLen - 3; pos += 3; if (actualDataLen > 0 && pos + actualDataLen <= end) { + if (messageFlag) { + // Handle message payload from host + dftDataAck(); + handleHostMessage(data, pos, actualDataLen); + return; + } + try { writeDownloadData(data, pos, actualDataLen, config); bytesTransferred += actualDataLen; @@ -192,74 +256,84 @@ public class FTDft { } pos += Math.max(0, actualDataLen); } else if (pos + 1 < end) { - // Skip other headers (2-byte code + length-based skip) - // Most headers are 4-6 bytes, but we just skip based on known patterns int hdrCode16 = ((data[pos] & 0xFF) << 8) | (data[pos + 1] & 0xFF); if (hdrCode16 == TR_RECNUM_HDR) { - pos += 6; // 2-byte code + 4-byte record number + pos += 6; } else if (hdrCode16 == TR_NOT_COMPRESSED) { pos += 2; } else { - pos += 2; // skip unknown 2-byte header + pos += 2; } } else { pos++; } } - // Send acknowledgement + // Send acknowledgement for file data dftDataAck(); } + private void handleHostMessage(byte[] data, int offset, int length) { + StringBuilder sb = 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); + } + String msg = sb.toString().trim(); + log.info("DFT message: " + msg); + + if (msg.startsWith(END_TRANSFER)) { + listener.onTransferComplete(null); + } else if (listener.getCurrentState() == FTState.ABORT_SENT) { + listener.onTransferAborted(msg.isEmpty() ? "Transfer aborted" : msg); + } else { + listener.onTransferComplete(msg); + } + } + /** * Write download data to the local file, handling ASCII conversion. + * Matching x3270 upload_convert logic. */ private void writeDownloadData(byte[] data, int offset, int length, FTConfig config) throws IOException { if (outputStream == null) return; if (!config.isAscii()) { - // Binary: write raw outputStream.write(data, offset, length); return; } - // ASCII mode with optional CR stripping and remapping for (int i = 0; i < length; i++) { int b = data[offset + i] & 0xFF; - if (config.isRemapFlag()) { - // Use IND$FILE's EBCDIC→ASCII table - int ascii = FT2ASC[b]; + if (config.isCrFlag() && (b == '\r' || b == 0x1A)) { + continue; // Strip CR and EOF ^Z + } - if (config.isCrFlag()) { - if (ascii == '\r') { - lastCr = true; - continue; - } - if (lastCr) { - lastCr = false; - if (ascii == '\n') { - outputStream.write('\n'); - continue; - } - outputStream.write('\r'); - } - } - outputStream.write(ascii); + if (!config.isRemapFlag()) { + outputStream.write(b); + continue; + } + + /* + * ASCII mode with remap: + * Host IND$FILE sends pseudo-ASCII byte b. + * Map pseudo-ASCII b to EBCDIC byte via ASC2FT[b], + * then convert EBCDIC byte to Unicode UTF-8 character. + */ + if (b < 0x20 || (b >= 0x80 && b < 0xA0 && b != 0x9F)) { + // Control code — write as Unicode directly + outputStream.write(String.valueOf((char) b).getBytes(StandardCharsets.UTF_8)); + } else if (b == 0xFF) { + // Special 0xFF -> U+009F + outputStream.write(String.valueOf((char) 0x9F).getBytes(StandardCharsets.UTF_8)); } else { - // Standard EBCDIC→Unicode - char ch = translator.ebcdicToUnicode(b); - if (config.isCrFlag()) { - if (ch == '\r') { lastCr = true; continue; } - if (lastCr) { - lastCr = false; - if (ch == '\n') { outputStream.write('\n'); continue; } - outputStream.write('\r'); - } - } - outputStream.write(String.valueOf(ch).getBytes( - java.nio.charset.StandardCharsets.UTF_8)); + int ebc = ASC2FT[b & 0xFF]; + char ch = translator.ebcdicToUnicode(ebc); + outputStream.write(String.valueOf(ch).getBytes(StandardCharsets.UTF_8)); } } } @@ -276,7 +350,7 @@ public class FTDft { } int bufferSize = config.getDftBufferSize(); - int numbytes = bufferSize - 27; // reserve space for headers + int numbytes = bufferSize - 27; byte[] readBuf = new byte[numbytes]; int totalRead = 0; @@ -290,7 +364,6 @@ public class FTDft { } readBuf[totalRead++] = (byte) b; } else { - // Binary read if (inputStream == null) { dftEof = true; break; } int n = inputStream.read(readBuf, totalRead, numbytes - totalRead); if (n <= 0) { @@ -305,25 +378,20 @@ public class FTDft { return; } - // Build SF response ByteArrayOutputStream out = new ByteArrayOutputStream(bufferSize); + out.write(AID_SF); - out.write(AID_SF); // AID byte - - // Placeholder for SF length (2 bytes, filled in later) int sfLenPos = out.size(); out.write(0); out.write(0); - out.write(SF_TRANSFER_DATA); // SF type + out.write(SF_TRANSFER_DATA); if (totalRead > 0) { log.fine("DFT: > GetReply rec=" + recnum + " " + totalRead + " bytes"); - // TR_GET_REPLY out.write((TR_GET_REPLY >> 8) & 0xFF); out.write(TR_GET_REPLY & 0xFF); - // Record number header out.write((TR_RECNUM_HDR >> 8) & 0xFF); out.write(TR_RECNUM_HDR & 0xFF); out.write((int) ((recnum >> 24) & 0xFF)); @@ -332,56 +400,47 @@ public class FTDft { out.write((int) (recnum & 0xFF)); recnum++; - // Not compressed out.write((TR_NOT_COMPRESSED >> 8) & 0xFF); out.write(TR_NOT_COMPRESSED & 0xFF); - // Begin data out.write(TR_BEGIN_DATA); int dataFieldLen = totalRead + 5; out.write((dataFieldLen >> 8) & 0xFF); out.write(dataFieldLen & 0xFF); - // The actual data out.write(readBuf, 0, totalRead); bytesTransferred += totalRead; } else { log.fine("DFT: > GetReply EOF"); - // EOF reply out.write((TR_GET_REQ >> 8) & 0xFF); out.write(TR_ERROR_REPLY & 0xFF); - // Error header out.write((TR_ERROR_HDR >> 8) & 0xFF); out.write(TR_ERROR_HDR & 0xFF); - // EOF error code out.write((TR_ERR_EOF >> 8) & 0xFF); out.write(TR_ERR_EOF & 0xFF); dftEof = true; } - // Set the SF length byte[] result = out.toByteArray(); - int sfLen = result.length - 1; // exclude AID byte + int sfLen = result.length - 1; result[sfLenPos] = (byte) ((sfLen >> 8) & 0xFF); result[sfLenPos + 1] = (byte) (sfLen & 0xFF); - // Save for potential Read Modified retransmit dftSaveBuf = result.clone(); dftSaveBufLen = result.length; - // Send it input.sendStructuredFieldData(result); listener.onBytesTransferred(bytesTransferred); } /** - * Read a byte from the local file in ASCII mode with CR expansion and remapping. - * Returns -1 for EOF. + * Read a byte from local file for upload, handling ASCII conversion and remapping. + * Matching x3270 dft_ascii_read logic. */ private int dftAsciiRead(FTConfig config) throws IOException { if (inputStream == null) return -1; @@ -389,30 +448,35 @@ public class FTDft { int c = inputStream.read(); if (c == -1) return -1; - if (config.isRemapFlag()) { - // CR expansion: insert \r before \n - if (config.isCrFlag() && !lastCr && c == '\n') { - // We need to return \r now and buffer \n - lastCr = false; - // Can't easily buffer here, so return \r and push \n back - // Actually, let's handle this inline - // Return the CR equivalent, then handle NL next call - return ASC2FT['\r' & 0xFF]; - // Note: the \n will be read on next call naturally - } - lastCr = (c == '\r'); - return ASC2FT[c & 0xFF]; - } else { - // No remap — convert to standard EBCDIC - if (config.isCrFlag() && !lastCr && c == '\n') { - lastCr = false; - int ebc = translator.unicodeToEbcdic('\r'); - return ebc >= 0 ? ebc : 0x0D; - } - lastCr = (c == '\r'); + if (config.isCrFlag() && !lastCr && c == '\n') { + lastCr = false; + // Expand \n to \r\n: return \r byte now + int rEbc = translator.unicodeToEbcdic('\r'); + if (rEbc < 0) rEbc = 0x0D; + return config.isRemapFlag() ? FT2ASC[rEbc & 0xFF] : rEbc; + } + lastCr = (c == '\r'); + + if (!config.isRemapFlag()) { int ebc = translator.unicodeToEbcdic((char) c); return ebc >= 0 ? ebc : 0x40; } + + /* + * ASCII mode with remap: + * Translate Unicode char c -> EBCDIC -> host pseudo-ASCII FT2ASC[ebc]. + */ + int ebc; + if (c < 0x20 || (c >= 0x80 && c < 0x9F)) { + ebc = ASC2FT[c & 0xFF]; + } else if (c == 0x9F) { + ebc = 0xFF; + } else { + ebc = translator.unicodeToEbcdic((char) c); + } + if (ebc < 0) ebc = 0x40; + + return FT2ASC[ebc & 0xFF]; } // ========== Close Request ========== @@ -420,16 +484,10 @@ public class FTDft { private void dftCloseRequest() { log.fine("DFT: Close"); - // Send close acknowledgement ByteArrayOutputStream out = new ByteArrayOutputStream(6); out.write(AID_SF); - - // SF length out.write(0); out.write(5); - out.write(SF_TRANSFER_DATA); - - // TR_CLOSE_REPLY out.write((TR_CLOSE_REPLY >> 8) & 0xFF); out.write(TR_CLOSE_REPLY & 0xFF); @@ -441,13 +499,8 @@ public class FTDft { private void dftDataAck() { ByteArrayOutputStream out = new ByteArrayOutputStream(6); out.write(AID_SF); - - // SF length out.write(0); out.write(5); - out.write(SF_TRANSFER_DATA); - - // TR_NORMAL_REPLY out.write((TR_NORMAL_REPLY >> 8) & 0xFF); out.write(TR_NORMAL_REPLY & 0xFF); @@ -461,21 +514,12 @@ public class FTDft { ByteArrayOutputStream out = new ByteArrayOutputStream(10); out.write(AID_SF); - - // SF length out.write(0); out.write(9); - out.write(SF_TRANSFER_DATA); - - // Error reply code out.write((code >> 8) & 0xFF); out.write(TR_ERROR_REPLY & 0xFF); - - // Error header out.write((TR_ERROR_HDR >> 8) & 0xFF); out.write(TR_ERROR_HDR & 0xFF); - - // Command failed out.write((TR_ERR_CMDFAIL >> 8) & 0xFF); out.write(TR_ERR_CMDFAIL & 0xFF); diff --git a/lib3270j/src/main/java/org/lib3270j/input/InputProcessor.java b/lib3270j/src/main/java/org/lib3270j/input/InputProcessor.java index 0d13427..25f2777 100644 --- a/lib3270j/src/main/java/org/lib3270j/input/InputProcessor.java +++ b/lib3270j/src/main/java/org/lib3270j/input/InputProcessor.java @@ -30,8 +30,46 @@ public class InputProcessor { this.fsm = fsm; } + public enum OiaStatus { + NOT_CONNECTED("OFFLINE"), + X_SYSTEM("X SYSTEM"), + X_PROT("X PROT"), + READY("READY"); + + private final String label; + OiaStatus(String label) { this.label = label; } + public String getLabel() { return label; } + } + + public OiaStatus getOiaStatus() { + if (fsm == null || fsm.getConnectionState() == null || !fsm.getConnectionState().isConnected()) { + return OiaStatus.NOT_CONNECTED; + } + if (keyboardLocked) { + return OiaStatus.X_SYSTEM; + } + return OiaStatus.READY; + } + + public interface LockStateListener { + void onLockStateChanged(boolean locked); + } + + private LockStateListener lockStateListener; + + public void setLockStateListener(LockStateListener listener) { + this.lockStateListener = listener; + } + public boolean isKeyboardLocked() { return keyboardLocked; } - public void setKeyboardLocked(boolean locked) { this.keyboardLocked = locked; } + public void setKeyboardLocked(boolean locked) { + if (this.keyboardLocked != locked) { + this.keyboardLocked = locked; + if (lockStateListener != null) { + lockStateListener.onLockStateChanged(locked); + } + } + } public boolean isInsertMode() { return insertMode; } public void setInsertMode(boolean insert) { this.insertMode = insert; } @@ -115,7 +153,7 @@ public class InputProcessor { if (keyboardLocked && aidCode != AID_CLEAR) return; lastAid = aidCode; - keyboardLocked = true; + setKeyboardLocked(true); if (aidCode == AID_CLEAR) { screen.clear(); @@ -149,8 +187,6 @@ public class InputProcessor { for (int i = 0; i < size; i++) { ExtendedAttribute ea = screen.getCell(i); if (ea.isFieldAttribute() && faIsModified(ea.fa & 0xFF)) { - if (faIsProtected(ea.fa & 0xFF)) continue; - int fieldStart = (i + 1) % size; // First, collect field data and find last non-null byte @@ -169,14 +205,14 @@ public class InputProcessor { if (pos == fieldStart) break; } - // Only send if there's actual data (strip trailing nulls) - if (lastNonNull >= 0) { - out.write(ORDER_SBA); - byte[] addr = encodeAddress(fieldStart, screen.getRows(), screen.getCols()); - out.write(addr[0] & 0xFF); - out.write(addr[1] & 0xFF); + // Always send SBA and address + out.write(ORDER_SBA); + byte[] addr = encodeAddress(fieldStart, screen.getRows(), screen.getCols()); + out.write(addr[0] & 0xFF); + out.write(addr[1] & 0xFF); - // Write only up to the last non-null byte + // Only send data if there is any (strip trailing nulls) + if (lastNonNull >= 0) { byte[] allData = fieldData.toByteArray(); out.write(allData, 0, lastNonNull + 1); } @@ -260,6 +296,17 @@ public class InputProcessor { } public void eraseEof() { + if (!screen.isFormatted()) { + int addr = screen.getCursorAddress(); + int size = screen.getRows() * screen.getCols(); + for (int i = addr; i < size; i++) { + ExtendedAttribute ea = screen.getCell(i); + ea.ec = 0; + ea.ucs4 = 0; + } + screen.markAllChanged(); + return; + } int addr = screen.getCursorAddress(); int size = screen.getRows() * screen.getCols(); byte faVal = screen.getFieldAttributeAt(addr); @@ -282,6 +329,7 @@ public class InputProcessor { } public void deleteChar() { + if (!screen.isFormatted()) return; int addr = screen.getCursorAddress(); byte faVal = screen.getFieldAttributeAt(addr); if (faIsProtected(faVal & 0xFF)) return; @@ -316,7 +364,7 @@ public class InputProcessor { /** Reset (unlock keyboard, cancel insert mode). */ public void reset() { - keyboardLocked = false; + setKeyboardLocked(false); insertMode = false; } diff --git a/.gradle/8.5/dependencies-accessors/gc.properties b/nohup.out similarity index 100% rename from .gradle/8.5/dependencies-accessors/gc.properties rename to nohup.out diff --git a/settings.gradle b/settings.gradle index 27331d1..0d6bc4d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,3 +2,4 @@ rootProject.name = 'j3270-project' include 'lib3270j' include 'j3270' +include 'a3270'