Mercurial > 510Connectbot
comparison app/src/main/java/org/tn5250j/framework/tn5250/tnvt.java @ 438:d29cce60f393
migrate from Eclipse to Android Studio
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 03 Dec 2015 11:23:55 -0800 |
parents | src/org/tn5250j/framework/tn5250/tnvt.java@09c1d3aae3f0 |
children | 8fa8e73e2f5c |
comparison
equal
deleted
inserted
replaced
437:208b31032318 | 438:d29cce60f393 |
---|---|
1 /** | |
2 * Title: tnvt.java | |
3 * Copyright: Copyright (c) 2001 Company: | |
4 * | |
5 * @author Kenneth J. Pouncey | |
6 * @version 0.5 | |
7 * | |
8 * Description: | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify it under | |
11 * the terms of the GNU General Public License as published by the Free Software | |
12 * Foundation; either version 2, or (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, but WITHOUT | |
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
17 * details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License along with | |
20 * this software; see the file COPYING. If not, write to the Free Software | |
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 * | |
23 */ | |
24 package org.tn5250j.framework.tn5250; | |
25 | |
26 import static java.lang.Math.max; | |
27 import static java.lang.Math.min; | |
28 import static org.tn5250j.TN5250jConstants.AID_HELP; | |
29 import static org.tn5250j.TN5250jConstants.AID_PRINT; | |
30 import static org.tn5250j.TN5250jConstants.CMD_CLEAR_FORMAT_TABLE; | |
31 import static org.tn5250j.TN5250jConstants.CMD_CLEAR_UNIT; | |
32 import static org.tn5250j.TN5250jConstants.CMD_CLEAR_UNIT_ALTERNATE; | |
33 import static org.tn5250j.TN5250jConstants.CMD_READ_INPUT_FIELDS; | |
34 import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_FIELDS; | |
35 import static org.tn5250j.TN5250jConstants.CMD_READ_MDT_IMMEDIATE_ALT; | |
36 import static org.tn5250j.TN5250jConstants.CMD_READ_SCREEN_IMMEDIATE; | |
37 import static org.tn5250j.TN5250jConstants.CMD_READ_SCREEN_TO_PRINT; | |
38 import static org.tn5250j.TN5250jConstants.CMD_RESTORE_SCREEN; | |
39 import static org.tn5250j.TN5250jConstants.CMD_ROLL; | |
40 import static org.tn5250j.TN5250jConstants.CMD_SAVE_SCREEN; | |
41 import static org.tn5250j.TN5250jConstants.CMD_WRITE_ERROR_CODE; | |
42 import static org.tn5250j.TN5250jConstants.CMD_WRITE_ERROR_CODE_TO_WINDOW; | |
43 import static org.tn5250j.TN5250jConstants.CMD_WRITE_STRUCTURED_FIELD; | |
44 import static org.tn5250j.TN5250jConstants.CMD_WRITE_TO_DISPLAY; | |
45 import static org.tn5250j.TN5250jConstants.NR_REQUEST_ERROR; | |
46 import static org.tn5250j.TN5250jConstants.PF1; | |
47 import static org.tn5250j.TN5250jConstants.PF10; | |
48 import static org.tn5250j.TN5250jConstants.PF11; | |
49 import static org.tn5250j.TN5250jConstants.PF12; | |
50 import static org.tn5250j.TN5250jConstants.PF13; | |
51 import static org.tn5250j.TN5250jConstants.PF14; | |
52 import static org.tn5250j.TN5250jConstants.PF15; | |
53 import static org.tn5250j.TN5250jConstants.PF16; | |
54 import static org.tn5250j.TN5250jConstants.PF17; | |
55 import static org.tn5250j.TN5250jConstants.PF18; | |
56 import static org.tn5250j.TN5250jConstants.PF19; | |
57 import static org.tn5250j.TN5250jConstants.PF2; | |
58 import static org.tn5250j.TN5250jConstants.PF20; | |
59 import static org.tn5250j.TN5250jConstants.PF21; | |
60 import static org.tn5250j.TN5250jConstants.PF22; | |
61 import static org.tn5250j.TN5250jConstants.PF23; | |
62 import static org.tn5250j.TN5250jConstants.PF24; | |
63 import static org.tn5250j.TN5250jConstants.PF3; | |
64 import static org.tn5250j.TN5250jConstants.PF4; | |
65 import static org.tn5250j.TN5250jConstants.PF5; | |
66 import static org.tn5250j.TN5250jConstants.PF6; | |
67 import static org.tn5250j.TN5250jConstants.PF7; | |
68 import static org.tn5250j.TN5250jConstants.PF8; | |
69 import static org.tn5250j.TN5250jConstants.PF9; | |
70 | |
71 import java.io.BufferedInputStream; | |
72 import java.io.BufferedOutputStream; | |
73 import java.io.ByteArrayOutputStream; | |
74 import java.io.IOException; | |
75 import java.io.InputStream; | |
76 import java.io.OutputStream; | |
77 import java.net.Socket; | |
78 import java.util.Arrays; | |
79 import java.util.Properties; | |
80 import java.util.concurrent.ArrayBlockingQueue; | |
81 import java.util.concurrent.BlockingQueue; | |
82 import java.util.concurrent.TimeUnit; | |
83 import javax.net.ssl.SSLSocket; | |
84 | |
85 import android.content.Intent; | |
86 import android.net.Uri; | |
87 import android.util.Log; | |
88 | |
89 import com.five_ten_sg.connectbot.R; | |
90 import com.five_ten_sg.connectbot.bean.HostBean; | |
91 import com.five_ten_sg.connectbot.service.TerminalBridge; | |
92 import com.five_ten_sg.connectbot.service.TerminalManager; | |
93 import de.mud.terminal.vt320; | |
94 | |
95 import org.tn5250j.TN5250jConstants; | |
96 import org.tn5250j.encoding.CharMappings; | |
97 import org.tn5250j.encoding.ICodePage; | |
98 import org.tn5250j.framework.transport.SocketConnector; | |
99 | |
100 | |
101 public final class tnvt implements Runnable { | |
102 private static final String TAG = "tnvt"; | |
103 // negotiating commands | |
104 private static final byte IAC = (byte) - 1; // 255 FF | |
105 private static final byte DONT = (byte) - 2; //254 FE | |
106 private static final byte DO = (byte) - 3; //253 FD | |
107 private static final byte WONT = (byte) - 4; //252 FC | |
108 private static final byte WILL = (byte) - 5; //251 FB | |
109 private static final byte SB = (byte) - 6; //250 Sub Begin FA | |
110 private static final byte SE = (byte) - 16; //240 Sub End F0 | |
111 private static final byte EOR = (byte) - 17; //239 End of Record EF | |
112 private static final byte TERMINAL_TYPE = (byte) 24; // 18 | |
113 private static final byte OPT_END_OF_RECORD = (byte) 25; // 19 | |
114 private static final byte TRANSMIT_BINARY = (byte) 0; // 0 | |
115 private static final byte QUAL_IS = (byte) 0; // 0 | |
116 private static final byte TIMING_MARK = (byte) 6; // 6 | |
117 private static final byte NEW_ENVIRONMENT = (byte) 39; // 27 | |
118 private static final byte IS = (byte) 0; // 0 | |
119 private static final byte SEND = (byte) 1; // 1 | |
120 private static final byte INFO = (byte) 2; // 2 | |
121 private static final byte VAR = (byte) 0; // 0 | |
122 private static final byte VALUE = (byte) 1; // 1 | |
123 private static final byte NEGOTIATE_ESC = (byte) 2; // 2 | |
124 private static final byte USERVAR = (byte) 3; // 3 | |
125 | |
126 // miscellaneous | |
127 private static final byte ESC = 0x04; // 04 | |
128 | |
129 private Socket sock; | |
130 public BufferedInputStream bin; | |
131 public BufferedOutputStream bout; | |
132 private final BlockingQueue<Object> dsq = new ArrayBlockingQueue<Object>(25); | |
133 private Stream5250 bk; | |
134 private DataStreamProducer producer; | |
135 protected Screen5250 screen52; | |
136 private boolean waitingForInput; | |
137 private boolean invited; | |
138 private boolean negotiated = false; | |
139 private Thread me; | |
140 private Thread pthread; | |
141 private int readType; | |
142 private boolean enhanced = true; | |
143 private boolean cursorOn = false; | |
144 private String hostname = ""; | |
145 private int port = 23; | |
146 private vt320 buffer; | |
147 private boolean connected = false; | |
148 private boolean support132 = true; | |
149 private ByteArrayOutputStream baosp = null; | |
150 private ByteArrayOutputStream baosrsp = null; | |
151 private int devSeq = -1; | |
152 private String devName; | |
153 private String devNameUsed; | |
154 private KbdTypesCodePages kbdTypesCodePage; | |
155 // WVL - LDC : TR.000300 : Callback scenario from 5250 | |
156 private boolean scan; // = false; | |
157 private static int STRSCAN = 1; | |
158 // WVL - LDC : 05/08/2005 : TFX.006253 - support STRPCCMD | |
159 private boolean strpccmd; // = false; | |
160 private String encryption; | |
161 private String user; | |
162 private String password = null; | |
163 private String library; | |
164 private String initialMenu; | |
165 private String program; | |
166 private boolean keepTrucking = true; | |
167 private boolean pendingUnlock = false; | |
168 private boolean[] dataIncluded; | |
169 protected ICodePage codePage; | |
170 private String sslType; | |
171 private WTDSFParser sfParser; | |
172 private TerminalBridge bridge; | |
173 private TerminalManager manager; | |
174 | |
175 | |
176 | |
177 /** | |
178 * @param screen52 | |
179 * @param enhanced | |
180 * @param support132 | |
181 * @param bridge | |
182 * @param manager | |
183 */ | |
184 public tnvt(Screen5250 screen52, boolean enhanced, boolean support132, TerminalBridge bridge, TerminalManager manager) { | |
185 this.screen52 = screen52; | |
186 this.support132 = support132; | |
187 this.enhanced = enhanced; | |
188 this.bridge = bridge; | |
189 this.manager = manager; | |
190 setCodePage("37"); | |
191 dataIncluded = new boolean[24]; | |
192 baosp = new ByteArrayOutputStream(); | |
193 baosrsp = new ByteArrayOutputStream(); | |
194 } | |
195 | |
196 public void showURL(String url) { | |
197 if (url.indexOf("://") < 0) url = "http://" + url; | |
198 | |
199 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); | |
200 manager.startActivity(intent); | |
201 } | |
202 | |
203 public String getHostName() { | |
204 return hostname; | |
205 } | |
206 | |
207 public void setDeviceName(String name) { | |
208 devName = name; | |
209 } | |
210 | |
211 public String getDeviceName() { | |
212 return devName; | |
213 } | |
214 | |
215 public String getAllocatedDeviceName() { | |
216 return devNameUsed; | |
217 } | |
218 | |
219 public boolean isConnected() { | |
220 return connected; | |
221 } | |
222 | |
223 /** | |
224 * @return true when SSL is used and socket is connected. | |
225 * @see {@link #isConnected()} | |
226 */ | |
227 public boolean isSslSocket() { | |
228 if (this.connected && this.sock != null && this.sock instanceof SSLSocket) { | |
229 return true; | |
230 } | |
231 else { | |
232 return false; | |
233 } | |
234 } | |
235 | |
236 public final void setProxy(String proxyHost, String proxyPort) { | |
237 Properties systemProperties = System.getProperties(); | |
238 systemProperties.put("socksProxySet", "true"); | |
239 systemProperties.put("socksProxyHost", proxyHost); | |
240 systemProperties.put("socksProxyPort", proxyPort); | |
241 System.setProperties(systemProperties); | |
242 Log.i(TAG, " socks set "); | |
243 } | |
244 | |
245 private String fixer(String value, String def) { | |
246 if ((value == null) || (value.length() == 0)) return def; | |
247 | |
248 return value; | |
249 } | |
250 | |
251 public final boolean connect(HostBean host, String homeDirectory, vt320 buffer) { | |
252 try { | |
253 this.hostname = host.getHostname(); | |
254 this.port = host.getPort(); | |
255 this.buffer = buffer; | |
256 this.encryption = fixer(host.getEncryption5250(), "NONE"); | |
257 this.user = host.getUsername(); | |
258 this.library = host.getLibrary(); | |
259 this.initialMenu = host.getInitialMenu(); | |
260 this.program = host.getProgram(); | |
261 | |
262 try { | |
263 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
264 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED, "X - Connecting"); | |
265 } | |
266 catch (Exception exc) { | |
267 Log.w(TAG, "setStatus(ON) " + exc.getMessage()); | |
268 } | |
269 | |
270 SocketConnector sc = new SocketConnector(); | |
271 sock = sc.createSocket(hostname, port, encryption, homeDirectory, bridge, manager); | |
272 | |
273 if (sock == null) { | |
274 Log.w(TAG, "I did not get a socket"); | |
275 disconnect(); | |
276 return false; | |
277 } | |
278 | |
279 connected = true; | |
280 // used for JDK1.3 | |
281 sock.setKeepAlive(true); | |
282 sock.setTcpNoDelay(true); | |
283 sock.setSoLinger(false, 0); | |
284 InputStream in = sock.getInputStream(); | |
285 OutputStream out = sock.getOutputStream(); | |
286 bin = new BufferedInputStream(in, 8192); | |
287 bout = new BufferedOutputStream(out); | |
288 byte abyte0[]; | |
289 | |
290 while (negotiate(abyte0 = readNegotiations())); | |
291 | |
292 negotiated = true; | |
293 | |
294 try { | |
295 screen52.setCursorActive(false); | |
296 } | |
297 catch (Exception excc) { | |
298 Log.w(TAG, "setCursorOff " + excc.getMessage()); | |
299 } | |
300 | |
301 producer = new DataStreamProducer(this, bin, dsq, abyte0); | |
302 pthread = new Thread(producer); | |
303 // pthread.setPriority(pthread.MIN_PRIORITY); | |
304 pthread.setPriority(Thread.NORM_PRIORITY); | |
305 // pthread.setPriority(Thread.NORM_PRIORITY / 2); | |
306 pthread.start(); | |
307 | |
308 try { | |
309 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED, | |
310 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); | |
311 } | |
312 catch (Exception exc) { | |
313 Log.w(TAG, "setStatus(OFF) " + exc.getMessage()); | |
314 } | |
315 | |
316 keepTrucking = true; | |
317 me = new Thread(this); | |
318 me.start(); | |
319 } | |
320 catch (Exception exception) { | |
321 if (exception.getMessage() == null) | |
322 exception.printStackTrace(); | |
323 | |
324 Log.w(TAG, "connect() " + exception.getMessage()); | |
325 | |
326 if (sock == null) | |
327 Log.w(TAG, "I did not get a socket"); | |
328 | |
329 disconnect(); | |
330 return false; | |
331 } | |
332 | |
333 return true; | |
334 } | |
335 | |
336 public final boolean disconnect() { | |
337 if (!connected) { | |
338 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
339 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED, "X - Disconnected"); | |
340 return false; | |
341 } | |
342 | |
343 if (me != null && me.isAlive()) { | |
344 me.interrupt(); | |
345 keepTrucking = false; | |
346 pthread.interrupt(); | |
347 } | |
348 | |
349 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
350 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED, "X - Disconnected"); | |
351 screen52.getOIA().setKeyBoardLocked(false); | |
352 pendingUnlock = false; | |
353 | |
354 try { | |
355 if (sock != null) { | |
356 Log.i(TAG, "Closing socket"); | |
357 sock.close(); | |
358 } | |
359 | |
360 if (bin != null) bin.close(); | |
361 | |
362 if (bout != null) bout.close(); | |
363 | |
364 connected = false; | |
365 // WVL - LDC : TR.000345 : properly disconnect and clear screen | |
366 // Is this the right place to set screen realestate on disconnect? | |
367 //controller.getScreen().clearAll(); | |
368 screen52.goto_XY(0); | |
369 screen52.setCursorActive(false); | |
370 screen52.clearAll(); | |
371 screen52.restoreScreen(); | |
372 } | |
373 catch (Exception exception) { | |
374 Log.w(TAG, exception.getMessage()); | |
375 connected = false; | |
376 devSeq = -1; | |
377 return false; | |
378 } | |
379 | |
380 devSeq = -1; | |
381 return true; | |
382 } | |
383 | |
384 private final ByteArrayOutputStream appendByteStream(byte abyte0[]) { | |
385 ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); | |
386 | |
387 for (int i = 0; i < abyte0.length; i++) { | |
388 bytearrayoutputstream.write(abyte0[i]); | |
389 | |
390 if (abyte0[i] == -1) | |
391 bytearrayoutputstream.write(-1); | |
392 } | |
393 | |
394 return bytearrayoutputstream; | |
395 } | |
396 | |
397 private final byte[] readNegotiations() throws IOException { | |
398 int i = bin.read(); | |
399 | |
400 if (i < 0) { | |
401 throw new IOException("Connection closed."); | |
402 } | |
403 else { | |
404 int j = bin.available(); | |
405 byte abyte0[] = new byte[j + 1]; | |
406 abyte0[0] = (byte) i; | |
407 bin.read(abyte0, 1, j); | |
408 return abyte0; | |
409 } | |
410 } | |
411 | |
412 private final void writeByte(byte abyte0[]) throws IOException { | |
413 bout.write(abyte0); | |
414 bout.flush(); | |
415 } | |
416 | |
417 private final void readImmediate(int readType) { | |
418 if (screen52.isStatusErrorCode()) { | |
419 screen52.restoreErrorLine(); | |
420 screen52.setStatus(Screen5250.STATUS_ERROR_CODE, | |
421 Screen5250.STATUS_VALUE_OFF, null); | |
422 } | |
423 | |
424 if (!enhanced) { | |
425 screen52.setCursorActive(false); | |
426 } | |
427 | |
428 // screen52.setStatus(Screen5250.STATUS_SYSTEM, | |
429 // Screen5250.STATUS_VALUE_ON, null); | |
430 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
431 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); | |
432 screen52.getOIA().setKeyBoardLocked(true); | |
433 pendingUnlock = false; | |
434 invited = false; | |
435 screen52.getScreenFields().readFormatTable(baosp, readType, codePage); | |
436 | |
437 try { | |
438 Log.i(TAG, "readImmediate() writeGDS()"); | |
439 writeGDS(0, 3, baosp.toByteArray()); | |
440 } | |
441 catch (IOException ioe) { | |
442 Log.w(TAG, ioe.getMessage()); | |
443 } | |
444 | |
445 baosp.reset(); | |
446 } | |
447 | |
448 public final boolean sendAidKey(int aid) { | |
449 if (screen52.isStatusErrorCode()) { | |
450 screen52.restoreErrorLine(); | |
451 screen52.setStatus(Screen5250.STATUS_ERROR_CODE, | |
452 Screen5250.STATUS_VALUE_OFF, null); | |
453 } | |
454 | |
455 if (!enhanced) { | |
456 screen52.setCursorActive(false); | |
457 } | |
458 | |
459 // screen52.setStatus(Screen5250.STATUS_SYSTEM, | |
460 // Screen5250.STATUS_VALUE_ON, null); | |
461 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
462 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); | |
463 screen52.getOIA().setKeyBoardLocked(true); | |
464 pendingUnlock = false; | |
465 invited = false; | |
466 baosp.write(screen52.getCurrentRow()); | |
467 baosp.write(screen52.getCurrentCol()); | |
468 baosp.write(aid); | |
469 | |
470 if (dataIncluded(aid)) | |
471 screen52.getScreenFields().readFormatTable(baosp, readType, | |
472 codePage); | |
473 | |
474 try { | |
475 Log.i(TAG, "sendAidKey() writeGDS()"); | |
476 writeGDS(0, 3, baosp.toByteArray()); | |
477 } | |
478 catch (IOException ioe) { | |
479 Log.w(TAG, ioe.getMessage()); | |
480 baosp.reset(); | |
481 return false; | |
482 } | |
483 | |
484 baosp.reset(); | |
485 return true; | |
486 } | |
487 | |
488 private boolean dataIncluded(int aid) { | |
489 switch (aid) { | |
490 case PF1: | |
491 return !dataIncluded[0]; | |
492 | |
493 case PF2: | |
494 return !dataIncluded[1]; | |
495 | |
496 case PF3: | |
497 return !dataIncluded[2]; | |
498 | |
499 case PF4: | |
500 return !dataIncluded[3]; | |
501 | |
502 case PF5: | |
503 return !dataIncluded[4]; | |
504 | |
505 case PF6: | |
506 return !dataIncluded[5]; | |
507 | |
508 case PF7: | |
509 return !dataIncluded[6]; | |
510 | |
511 case PF8: | |
512 return !dataIncluded[7]; | |
513 | |
514 case PF9: | |
515 return !dataIncluded[8]; | |
516 | |
517 case PF10: | |
518 return !dataIncluded[9]; | |
519 | |
520 case PF11: | |
521 return !dataIncluded[10]; | |
522 | |
523 case PF12: | |
524 return !dataIncluded[11]; | |
525 | |
526 case PF13: | |
527 return !dataIncluded[12]; | |
528 | |
529 case PF14: | |
530 return !dataIncluded[13]; | |
531 | |
532 case PF15: | |
533 return !dataIncluded[14]; | |
534 | |
535 case PF16: | |
536 return !dataIncluded[15]; | |
537 | |
538 case PF17: | |
539 return !dataIncluded[16]; | |
540 | |
541 case PF18: | |
542 return !dataIncluded[17]; | |
543 | |
544 case PF19: | |
545 return !dataIncluded[18]; | |
546 | |
547 case PF20: | |
548 return !dataIncluded[19]; | |
549 | |
550 case PF21: | |
551 return !dataIncluded[20]; | |
552 | |
553 case PF22: | |
554 return !dataIncluded[21]; | |
555 | |
556 case PF23: | |
557 return !dataIncluded[22]; | |
558 | |
559 case PF24: | |
560 return !dataIncluded[23]; | |
561 | |
562 default: | |
563 return true; | |
564 } | |
565 } | |
566 | |
567 /** | |
568 * Help request - | |
569 * | |
570 * | |
571 * See notes inside method | |
572 */ | |
573 public final void sendHelpRequest() { | |
574 // Client sends header 000D12A0000004000003####F3FFEF | |
575 // operation code 3 | |
576 // row - first ## | |
577 // column - second ## | |
578 // F3 - Help Aid Key | |
579 // System.out.println("Help request sent"); | |
580 baosp.write(screen52.getCurrentRow()); | |
581 baosp.write(screen52.getCurrentCol()); | |
582 baosp.write(AID_HELP); | |
583 | |
584 try { | |
585 Log.i(TAG, "sendHelpRequest() writeGDS()"); | |
586 writeGDS(0, 3, baosp.toByteArray()); | |
587 } | |
588 catch (IOException ioe) { | |
589 Log.w(TAG, ioe.getMessage()); | |
590 } | |
591 | |
592 baosp.reset(); | |
593 } | |
594 | |
595 /** | |
596 * Attention Key - | |
597 * | |
598 * | |
599 * See notes inside method | |
600 */ | |
601 public final void sendAttentionKey() { | |
602 // Client sends header 000A12A000004400000FFEF | |
603 // 0x40 -> 01000000 | |
604 // | |
605 // flags | |
606 // bit 0 - ERR | |
607 // bit 1 - ATN Attention | |
608 // bits 2-4 - reserved | |
609 // bit 5 - SRQ system request | |
610 // bit 6 - TRQ Test request key | |
611 // bit 7 - HLP | |
612 | |
613 // System.out.println("Attention key sent"); | |
614 try { | |
615 Log.i(TAG, "sendAttentionKey() writeGDS()"); | |
616 writeGDS(0x40, 0, null); | |
617 } | |
618 catch (IOException ioe) { | |
619 Log.w(TAG, ioe.getMessage()); | |
620 } | |
621 } | |
622 | |
623 /** | |
624 * Opens a dialog and asks the user before sending a request | |
625 * | |
626 * @see {@link #systemRequest(String)} | |
627 */ | |
628 public final void systemRequest() { | |
629 String ask = manager.res.getString(R.string.prompt_sys_request); | |
630 String sysreq = bridge.promptHelper.requestStringPrompt(null, ask); | |
631 systemRequest(sysreq); | |
632 } | |
633 | |
634 /** | |
635 * @param sr - system request option | |
636 * @see {@link #systemRequest(String)} | |
637 */ | |
638 public final void systemRequest(char sr) { | |
639 systemRequest(Character.toString(sr)); | |
640 } | |
641 | |
642 /** | |
643 * System request, taken from the rfc1205, 5250 Telnet interface section 4.3 | |
644 * | |
645 * @param sr system request option (allowed to be null, but than nothing happens) | |
646 */ | |
647 public final void systemRequest(String sr) { | |
648 byte[] bytes = null; | |
649 | |
650 if ((sr != null) && (sr.length() > 0)) { | |
651 // XXX: Not sure, if this is a sufficient check for 'clear dataq' | |
652 if (sr.charAt(0) == '2') { | |
653 dsq.clear(); | |
654 } | |
655 | |
656 for (int i = 0, l = sr.length(); i < l; i++) { | |
657 baosp.write(codePage.uni2ebcdic(sr.charAt(i))); | |
658 } | |
659 | |
660 bytes = baosp.toByteArray(); | |
661 } | |
662 | |
663 try { | |
664 Log.i(TAG, "systemRequest() writeGDS()"); | |
665 writeGDS(4, 0, bytes); | |
666 } | |
667 catch (IOException ioe) { | |
668 Log.i(TAG, ioe.getMessage()); | |
669 } | |
670 | |
671 baosp.reset(); | |
672 } | |
673 | |
674 /** | |
675 * Cancel Invite - taken from the rfc1205 - 5250 Telnet interface section | |
676 * 4.3 | |
677 * | |
678 * See notes inside method | |
679 */ | |
680 public final void cancelInvite() { | |
681 // screen52.setStatus(Screen5250.STATUS_SYSTEM, | |
682 // Screen5250.STATUS_VALUE_ON, null); | |
683 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
684 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); | |
685 | |
686 // from rfc1205 section 4.3 | |
687 // Server: Sends header with the 000A12A0 00000400 000AFFEF | |
688 // Opcode = Cancel Invite. | |
689 | |
690 // Client: sends header with the 000A12A0 00000400 000AFFEF | |
691 // Opcode = Cancel Invite to | |
692 // indicate that the work station is | |
693 // no longer invited. | |
694 try { | |
695 Log.i(TAG, "cancelInvite() writeGDS()"); | |
696 writeGDS(0, 10, null); | |
697 } | |
698 catch (IOException ioe) { | |
699 Log.w(TAG, ioe.getMessage()); | |
700 } | |
701 } | |
702 | |
703 public final void hostPrint(int aid) { | |
704 if (screen52.isStatusErrorCode()) { | |
705 screen52.restoreErrorLine(); | |
706 screen52.setStatus(Screen5250.STATUS_ERROR_CODE, | |
707 Screen5250.STATUS_VALUE_OFF, null); | |
708 } | |
709 | |
710 screen52.setCursorActive(false); | |
711 // screen52.setStatus(Screen5250.STATUS_SYSTEM, | |
712 // Screen5250.STATUS_VALUE_ON, null); | |
713 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_SYSTEM_WAIT, | |
714 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); | |
715 // From client access ip capture | |
716 // it seems to use an operation code of 3 and 4 | |
717 // also note that the flag field that says reserved is being sent as | |
718 // well | |
719 // with a value of 0x80 | |
720 // | |
721 // I have tried with not setting these flags and sending with 3 or 1 | |
722 // there is no effect and I still get a host print screen. Go figure | |
723 //0000: 000D 12A0 0000 0400 8003 1407 F6FFEF | |
724 //0000: 000D 12A0 0000 0400 8001 110E F6FFEF | |
725 // | |
726 // Client sends header 000D12A0000004000003####F6FFEF | |
727 // operation code 3 | |
728 // row - first ## | |
729 // column - second ## | |
730 // F6 - Print Aid Key | |
731 baosp.write(screen52.getCurrentRow()); | |
732 baosp.write(screen52.getCurrentCol()); | |
733 baosp.write(AID_PRINT); // aid key | |
734 | |
735 try { | |
736 Log.i(TAG, "hostPrint() writeGDS()"); | |
737 writeGDS(0, 3, baosp.toByteArray()); | |
738 } | |
739 catch (IOException ioe) { | |
740 Log.w(TAG, ioe.getMessage()); | |
741 } | |
742 | |
743 baosp.reset(); | |
744 } | |
745 | |
746 public final void toggleDebug() { | |
747 producer.toggleDebug(codePage); | |
748 } | |
749 | |
750 // write gerneral data stream | |
751 private final void writeGDS(int flags, int opcode, byte abyte0[]) | |
752 throws IOException { | |
753 // Added to fix for JDK 1.4 this was null coming from another method. | |
754 // There was a weird keyRelease event coming from another panel when | |
755 // using a key instead of the mouse to select button. | |
756 // The other method was fixed as well but this check should be here | |
757 // anyway. | |
758 if (bout == null) | |
759 return; | |
760 | |
761 int length; | |
762 | |
763 if (abyte0 != null) | |
764 length = abyte0.length + 10; | |
765 else | |
766 length = 10; | |
767 | |
768 // refer to rfc1205 - 5250 Telnet interface | |
769 // Section 3. Data Stream Format | |
770 // Logical Record Length - 16 bits | |
771 baosrsp.write(length >> 8); // Length LL | |
772 baosrsp.write(length & 0xff); // LL | |
773 // Record Type - 16 bits | |
774 // It should always be set to '12A0'X to indicate the | |
775 // General Data Stream (GDS) record type. | |
776 baosrsp.write(18); // 0x12 | |
777 baosrsp.write(160); // 0xA0 | |
778 // the next 16 bits are not used | |
779 baosrsp.write(0); // 0x00 | |
780 baosrsp.write(0); // 0x00 | |
781 // The second part is meant to be variable in length | |
782 // currently this portion is 4 octets long (1 byte or 8 bits for us ;-O) | |
783 baosrsp.write(4); // 0x04 | |
784 baosrsp.write(flags); // flags | |
785 // bit 0 - ERR | |
786 // bit 1 - ATN Attention | |
787 // bits 2-4 - reserved | |
788 // bit 5 - SRQ system request | |
789 // bit 6 - TRQ Test request key | |
790 // bit 7 - HLP | |
791 baosrsp.write(0); // reserved - set to 0x00 | |
792 baosrsp.write(opcode); // opcode | |
793 | |
794 if (abyte0 != null) | |
795 baosrsp.write(abyte0, 0, abyte0.length); | |
796 | |
797 baosrsp = appendByteStream(baosrsp.toByteArray()); | |
798 // make sure we indicate no more to be sent | |
799 baosrsp.write(IAC); | |
800 baosrsp.write(EOR); | |
801 baosrsp.writeTo(bout); | |
802 bout.flush(); | |
803 baosrsp.reset(); | |
804 } | |
805 | |
806 protected final int getOpCode() { | |
807 return bk.getOpCode(); | |
808 } | |
809 | |
810 protected boolean[] getActiveAidKeys() { | |
811 boolean aids[] = new boolean[dataIncluded.length]; | |
812 System.arraycopy(dataIncluded, 0, aids, 0, dataIncluded.length); | |
813 return aids; | |
814 } | |
815 | |
816 private final void setInvited() { | |
817 Log.d(TAG, "invited"); | |
818 if (!screen52.isStatusErrorCode()) | |
819 screen52.getOIA().setInputInhibited(ScreenOIA.INPUTINHIBITED_NOTINHIBITED, | |
820 ScreenOIA.OIA_LEVEL_INPUT_INHIBITED); | |
821 invited = true; | |
822 screen52.updateDirty(); | |
823 buffer.testChanged(); | |
824 } | |
825 | |
826 // WVL - LDC : 05/08/2005 : TFX.006253 - Support STRPCCMD | |
827 private void strpccmd() { | |
828 try { | |
829 int str = 11; | |
830 char c; | |
831 ScreenPlanes planes = screen52.getPlanes(); | |
832 c = planes.getChar(str); | |
833 boolean waitFor = !(c == 'a'); | |
834 StringBuffer command = new StringBuffer(); | |
835 | |
836 for (int i = str + 1; i < 132; i++) { | |
837 c = planes.getChar(i); | |
838 | |
839 if (Character.isISOControl(c)) | |
840 c = ' '; | |
841 | |
842 command.append(c); | |
843 } | |
844 | |
845 String cmd = command.toString().trim(); | |
846 run(cmd, waitFor); | |
847 } | |
848 finally { | |
849 strpccmd = false; | |
850 screen52.sendKeys(TN5250jConstants.MNEMONIC_ENTER); | |
851 } | |
852 } | |
853 | |
854 // WVL - LDC : 05/08/2005 : TFX.006253 - Support STRPCCMD | |
855 private void run(String cmd, boolean waitFor) { | |
856 try { | |
857 Log.d(TAG, "RUN cmd = " + cmd); | |
858 Log.d(TAG, "RUN wait = " + waitFor); | |
859 Runtime r = Runtime.getRuntime(); | |
860 Process p = r.exec(cmd); | |
861 | |
862 if (waitFor) { | |
863 int result = p.waitFor(); | |
864 Log.d(TAG, "RUN result = " + result); | |
865 } | |
866 } | |
867 catch (Throwable t) { | |
868 Log.e(TAG, "exception", t); | |
869 } | |
870 } | |
871 | |
872 | |
873 // WVL - LDC : TR.000300 : Callback scenario from 5250 | |
874 /** | |
875 * Activate or deactivate the command scanning behaviour. | |
876 * | |
877 * @param scan | |
878 * if true, scanning is enabled; disabled otherwise. | |
879 * | |
880 * @see scan4Cmd() | |
881 */ | |
882 public void setScanningEnabled(boolean scan) { | |
883 this.scan = scan; | |
884 } | |
885 | |
886 // WVL - LDC : TR.000300 : Callback scenario from 5250 | |
887 /** | |
888 * Checks whether command scanning is enabled. | |
889 * | |
890 * @return true is command scanning is enabled; false otherwise. | |
891 */ | |
892 public boolean isScanningEnabled() { | |
893 return this.scan; | |
894 } | |
895 | |
896 // WVL - LDC : TR.000300 : Callback scenario from 5250 | |
897 /** | |
898 * When command scanning is activated, the terminal reads the first and | |
899 * second character in the datastream (the zero position allows to | |
900 * devisualize the scan stream). If the sequence <code>#!</code> is | |
901 * encountered and if this sequence is <strong>not </strong> followed by a | |
902 * blank character, the {@link parseCommand(ScreenChar[])}is called. | |
903 */ | |
904 private void scan() { | |
905 // System.out.println("Checking command : " + | |
906 // screen52.screen[1].getChar() + screen52.screen[2].getChar()); | |
907 // ScreenChar[] screen = screen52.screen; | |
908 ScreenPlanes planes = screen52.getPlanes(); | |
909 | |
910 if ((planes.getChar(STRSCAN) == '#') | |
911 && (planes.getChar(STRSCAN + 1) == '!') | |
912 && (planes.getChar(STRSCAN + 2) != ' ')) { | |
913 try { | |
914 parseCommand(); | |
915 } | |
916 catch (Throwable t) { | |
917 Log.i(TAG, "Exec cmd: " + t.getMessage()); | |
918 t.printStackTrace(); | |
919 } | |
920 } | |
921 } | |
922 | |
923 // WVL - LDC : TR.000300 : Callback scenario from 5250 | |
924 /** | |
925 * The screen is parsed starting from second position until a white space is | |
926 * encountered. When found the Session#execCommand(String, int) is | |
927 * called with the parsed string. The position immediately following the | |
928 * encountered white space, separating the command from the rest of the | |
929 * screen, is passed as starting index. | |
930 * | |
931 * Note that the character at the starting position can potentially be a | |
932 * white space itself. The starting position in <code>execCommand</code> | |
933 * provided to make the scanning sequence more flexible. We'd like for | |
934 * example to embed also a <code>+</code> or <code>-</code> sign to | |
935 * indicate whether the tnvt should trigger a repaint or not. This would | |
936 * allow the flashing of command sequences without them becoming visible. | |
937 * | |
938 * <ul> | |
939 * <li><strong>PRE </strong> The screen character at position | |
940 * <code>STRSCAN + 2</code> is not a white space.</li> | |
941 * </ul> | |
942 */ | |
943 private void parseCommand() { | |
944 // Search for the command i.e. the first token in the stream | |
945 // after the #! sequence separated by a space from the rest | |
946 // of the screen. | |
947 char[] screen = screen52.getScreenAsChars(); | |
948 | |
949 for (int s = STRSCAN + 2, i = s; i < screen.length; i++) { | |
950 if (screen[i] == ' ') { | |
951 String command = new String(screen, s, i - s); | |
952 // Skip all white spaces between the command and the rest of | |
953 // the screen. | |
954 //for (; (i < screen.length) && (screen[i] == ' '); i++); | |
955 String remainder = new String(screen, i + 1, screen.length | |
956 - (i + 1)); | |
957 //controller.fireScanned(command, remainder); | |
958 Log.i(TAG, "trying to run " + command + " " + remainder); | |
959 break; | |
960 } | |
961 } | |
962 } | |
963 | |
964 public void run() { | |
965 if (enhanced) sfParser = new WTDSFParser(this); | |
966 | |
967 bk = new Stream5250(); | |
968 | |
969 while (keepTrucking) { | |
970 try { | |
971 Object e = dsq.take(); | |
972 | |
973 if ((e instanceof Integer) && ((Integer)e == 0)) { | |
974 screen52.updateDirty(); | |
975 buffer.testChanged(); | |
976 continue; | |
977 }; | |
978 | |
979 bk.initialize((byte[])e); | |
980 } | |
981 catch (InterruptedException ie) { | |
982 Log.w(TAG, " vt thread interrupted and stopping "); | |
983 keepTrucking = false; | |
984 continue; | |
985 } | |
986 | |
987 invited = false; | |
988 screen52.setCursorActive(false); | |
989 if (bk == null) continue; | |
990 | |
991 switch (bk.getOpCode()) { | |
992 case 00: | |
993 Log.d(TAG, "No operation"); | |
994 break; | |
995 | |
996 case 1: | |
997 Log.d(TAG, "Invite Operation"); | |
998 parseIncoming(); | |
999 pendingUnlock = true; | |
1000 cursorOn = true; | |
1001 setInvited(); | |
1002 break; | |
1003 | |
1004 case 2: | |
1005 Log.d(TAG, "Output Only"); | |
1006 parseIncoming(); | |
1007 screen52.updateDirty(); | |
1008 break; | |
1009 | |
1010 case 3: | |
1011 Log.d(TAG, "Put/Get Operation"); | |
1012 parseIncoming(); | |
1013 setInvited(); | |
1014 break; | |
1015 | |
1016 case 4: | |
1017 Log.d(TAG, "Save Screen Operation"); | |
1018 parseIncoming(); | |
1019 break; | |
1020 | |
1021 case 5: | |
1022 Log.d(TAG, "Restore Screen Operation"); | |
1023 parseIncoming(); | |
1024 break; | |
1025 | |
1026 case 6: | |
1027 Log.d(TAG, "Read Immediate"); | |
1028 sendAidKey(0); | |
1029 break; | |
1030 | |
1031 case 7: | |
1032 Log.d(TAG, "Reserved"); | |
1033 break; | |
1034 | |
1035 case 8: | |
1036 Log.d(TAG, "Read Screen Operation"); | |
1037 | |
1038 try { | |
1039 readScreen(); | |
1040 } | |
1041 catch (IOException ex) { | |
1042 Log.w(TAG, ex.getMessage()); | |
1043 } | |
1044 | |
1045 break; | |
1046 | |
1047 case 9: | |
1048 Log.d(TAG, "Reserved"); | |
1049 break; | |
1050 | |
1051 case 10: | |
1052 Log.d(TAG, "Cancel Invite Operation"); | |
1053 cancelInvite(); | |
1054 break; | |
1055 | |
1056 case 11: | |
1057 Log.d(TAG, "Turn on message light"); | |
1058 screen52.getOIA().setMessageLightOn(); | |
1059 screen52.setCursorActive(true); | |
1060 break; | |
1061 | |
1062 case 12: | |
1063 Log.d(TAG, "Turn off Message light"); | |
1064 screen52.getOIA().setMessageLightOff(); | |
1065 screen52.setCursorActive(true); | |
1066 break; | |
1067 | |
1068 default: | |
1069 break; | |
1070 } | |
1071 | |
1072 if (screen52.isUsingGuiInterface()) | |
1073 screen52.drawFields(); | |
1074 | |
1075 try { | |
1076 if (!strpccmd) { | |
1077 screen52.updateDirty(); | |
1078 } | |
1079 else { | |
1080 strpccmd(); | |
1081 } | |
1082 } | |
1083 catch (Exception exd) { | |
1084 Log.w(TAG, " tnvt.run: " + exd.getMessage()); | |
1085 exd.printStackTrace(); | |
1086 } | |
1087 | |
1088 if (pendingUnlock && !screen52.isStatusErrorCode()) { | |
1089 screen52.getOIA().setKeyBoardLocked(false); | |
1090 pendingUnlock = false; | |
1091 } | |
1092 | |
1093 if (cursorOn && !screen52.getOIA().isKeyBoardLocked()) { | |
1094 screen52.setCursorActive(true); | |
1095 cursorOn = false; | |
1096 } | |
1097 } | |
1098 } | |
1099 | |
1100 public void dumpStuff() { | |
1101 Log.d(TAG, " Pending unlock " + pendingUnlock); | |
1102 Log.d(TAG, " Status Error " + screen52.isStatusErrorCode()); | |
1103 Log.d(TAG, " Keyboard Locked " + screen52.getOIA().isKeyBoardLocked()); | |
1104 Log.d(TAG, " Cursor On " + cursorOn); | |
1105 Log.d(TAG, " Cursor Active " + screen52.cursorActive); | |
1106 } | |
1107 | |
1108 | |
1109 private final void readScreen() throws IOException { | |
1110 int rows = screen52.getRows(); | |
1111 int cols = screen52.getColumns(); | |
1112 byte abyte0[] = new byte[rows * cols]; | |
1113 fillScreenArray(abyte0, rows, cols); | |
1114 Log.i(TAG, "readScreen() writeGDS()"); | |
1115 writeGDS(0, 0, abyte0); | |
1116 abyte0 = null; | |
1117 } | |
1118 | |
1119 private final void fillScreenArray(byte[] sa, int rows, int cols) { | |
1120 int la = 32; | |
1121 int sac = 0; | |
1122 int len = rows * cols; | |
1123 ScreenPlanes planes = screen52.planes; | |
1124 | |
1125 try { | |
1126 for (int y = 0; y < len; y++) { // save the screen data | |
1127 if (planes.isAttributePlace(y)) { | |
1128 la = planes.getCharAttr(y); | |
1129 sa[sac++] = (byte) la; | |
1130 } | |
1131 else { | |
1132 // The characters on screen are in unicode | |
1133 char ch = planes.getChar(y); | |
1134 byte byteCh; | |
1135 if (isDataUnicode(ch)) byteCh = codePage.uni2ebcdic(ch); | |
1136 else byteCh = (byte) ch; | |
1137 sa[sac++] = byteCh; | |
1138 } | |
1139 } | |
1140 } | |
1141 catch (Exception exc) { | |
1142 Log.i(TAG, exc.getMessage()); | |
1143 exc.printStackTrace(); | |
1144 } | |
1145 } | |
1146 | |
1147 private final void fillRegenerationBuffer(ByteArrayOutputStream sc, int rows, int cols) | |
1148 throws IOException { | |
1149 int la = 32; | |
1150 int sac = 0; | |
1151 int len = rows * cols; | |
1152 ScreenPlanes planes = screen52.planes; | |
1153 byte[] sa = new byte[len]; | |
1154 | |
1155 try { | |
1156 boolean guiExists = sfParser != null && sfParser.isGuisExists(); | |
1157 | |
1158 for (int y = 0; y < len; y++) { // save the screen data | |
1159 if (guiExists) { | |
1160 byte[] guiSeg = sfParser.getSegmentAtPos(y); | |
1161 | |
1162 if (guiSeg != null) { | |
1163 //Log.i(TAG," gui saved at " + y + " - " + screen52.getRow(y) + "," + | |
1164 // screen52.getCol(y)); | |
1165 byte[] gsa = new byte[sa.length + guiSeg.length + 2]; | |
1166 System.arraycopy(sa, 0, gsa, 0, sa.length); | |
1167 System.arraycopy(guiSeg, 0, gsa, sac + 2, guiSeg.length); | |
1168 sa = new byte[gsa.length]; | |
1169 System.arraycopy(gsa, 0, sa, 0, gsa.length); | |
1170 sa[sac++] = (byte)0x04; | |
1171 sa[sac++] = (byte)0x11; | |
1172 sac += guiSeg.length; | |
1173 //y--; | |
1174 // continue; | |
1175 } | |
1176 } | |
1177 | |
1178 if (planes.isAttributePlace(y)) { | |
1179 la = planes.getCharAttr(y); | |
1180 sa[sac++] = (byte) la; | |
1181 } | |
1182 else { | |
1183 // The characters on screen are in unicode | |
1184 char ch = planes.getChar(y); | |
1185 byte byteCh; | |
1186 if (isDataUnicode(ch)) byteCh = codePage.uni2ebcdic(ch); | |
1187 else byteCh = (byte) ch; | |
1188 sa[sac++] = byteCh; | |
1189 } | |
1190 } | |
1191 } | |
1192 catch (Exception exc) { | |
1193 Log.i(TAG, exc.getMessage()); | |
1194 exc.printStackTrace(); | |
1195 } | |
1196 | |
1197 sc.write(sa); | |
1198 } | |
1199 | |
1200 public final void saveScreen() throws IOException { | |
1201 ByteArrayOutputStream sc = new ByteArrayOutputStream(); | |
1202 sc.write(4); | |
1203 sc.write(0x12); // 18 | |
1204 sc.write(0); // 18 | |
1205 sc.write(0); // 18 | |
1206 sc.write((byte) screen52.getRows()); // store the current size | |
1207 sc.write((byte) screen52.getColumns()); // "" | |
1208 int cp = screen52.getCurrentPos(); // save off current position | |
1209 // fix below submitted by Mitch Blevins | |
1210 //int cp = screen52.getScreenFields().getCurrentFieldPos(); | |
1211 // save off current position | |
1212 sc.write((byte)(cp >> 8 & 0xff)); // "" | |
1213 sc.write((byte)(cp & 0xff)); // "" | |
1214 sc.write((byte)(screen52.homePos >> 8 & 0xff)); // save home pos | |
1215 sc.write((byte)(screen52.homePos & 0xff)); // "" | |
1216 int rows = screen52.getRows(); // store the current size | |
1217 int cols = screen52.getColumns(); // "" | |
1218 // byte[] sa = new byte[rows * cols]; | |
1219 fillRegenerationBuffer(sc, rows, cols); | |
1220 // fillScreenArray(sa, rows, cols); | |
1221 // | |
1222 // sc.write(sa); | |
1223 // sa = null; | |
1224 int sizeFields = screen52.getScreenFields().getSize(); | |
1225 sc.write((byte)(sizeFields >> 8 & 0xff)); // "" | |
1226 sc.write((byte)(sizeFields & 0xff)); // "" | |
1227 | |
1228 if (sizeFields > 0) { | |
1229 int x = 0; | |
1230 int s = screen52.getScreenFields().getSize(); | |
1231 ScreenField sf = null; | |
1232 | |
1233 while (x < s) { | |
1234 sf = screen52.getScreenFields().getField(x); | |
1235 sc.write((byte) sf.getAttr()); // attribute | |
1236 int sp = sf.startPos(); | |
1237 sc.write((byte)(sp >> 8 & 0xff)); // "" | |
1238 sc.write((byte)(sp & 0xff)); // "" | |
1239 | |
1240 if (sf.mdt) | |
1241 sc.write((byte) 1); | |
1242 else | |
1243 sc.write((byte) 0); | |
1244 | |
1245 sc.write((byte)(sf.getLength() >> 8 & 0xff)); // "" | |
1246 sc.write((byte)(sf.getLength() & 0xff)); // "" | |
1247 sc.write((byte) sf.getFFW1() & 0xff); | |
1248 sc.write((byte) sf.getFFW2() & 0xff); | |
1249 sc.write((byte) sf.getFCW1() & 0xff); | |
1250 sc.write((byte) sf.getFCW2() & 0xff); | |
1251 Log.d(TAG, "Saved "); | |
1252 Log.d(TAG, sf.toString()); | |
1253 x++; | |
1254 } | |
1255 | |
1256 sf = null; | |
1257 } | |
1258 | |
1259 // The following two lines of code looks to have caused all sorts of | |
1260 // problems so for now we have commented them out. | |
1261 // screen52.getScreenFields().setCurrentField(null); // set it to null | |
1262 // for GC ? | |
1263 // screen52.clearTable(); | |
1264 | |
1265 try { | |
1266 Log.i(TAG, "saveScreen() writeGDS()"); | |
1267 writeGDS(0, 3, sc.toByteArray()); | |
1268 } | |
1269 catch (IOException ioe) { | |
1270 Log.w(TAG, ioe.getMessage()); | |
1271 } | |
1272 | |
1273 sc = null; | |
1274 Log.d(TAG, "Save Screen end "); | |
1275 } | |
1276 | |
1277 /** | |
1278 * | |
1279 * @throws IOException | |
1280 */ | |
1281 public final void restoreScreen() throws IOException { | |
1282 int which = 0; | |
1283 ScreenPlanes planes = screen52.planes; | |
1284 | |
1285 try { | |
1286 Log.d(TAG, "Restore "); | |
1287 bk.getNextByte(); | |
1288 bk.getNextByte(); | |
1289 int rows = bk.getNextByte() & 0xff; | |
1290 int cols = bk.getNextByte() & 0xff; | |
1291 int pos = bk.getNextByte() << 8 & 0xff00; // current position | |
1292 pos |= bk.getNextByte() & 0xff; | |
1293 int hPos = bk.getNextByte() << 8 & 0xff00; // home position | |
1294 hPos |= bk.getNextByte() & 0xff; | |
1295 | |
1296 if ((rows != screen52.getRows()) || (cols != screen52.getColumns())) | |
1297 screen52.setRowsCols(rows, cols); | |
1298 | |
1299 screen52.clearAll(); // initialize what we currenty have | |
1300 | |
1301 if (sfParser != null && sfParser.isGuisExists()) | |
1302 sfParser.clearGuiStructs(); | |
1303 | |
1304 int b = 32; | |
1305 int la = 32; | |
1306 int len = rows * cols; | |
1307 | |
1308 for (int y = 0; y < len; y++) { | |
1309 b = bk.getNextByte(); | |
1310 | |
1311 if (b == 0x04) { | |
1312 Log.i(TAG, " gui restored at " + y + " - " + screen52.getRow(y) + "," + | |
1313 screen52.getCol(y)); | |
1314 int command = bk.getNextByte(); | |
1315 byte[] seg = bk.getSegment(); | |
1316 | |
1317 if (seg.length > 0) { | |
1318 screen52.goto_XY(y); | |
1319 sfParser.parseWriteToDisplayStructuredField(seg); | |
1320 } | |
1321 | |
1322 y--; | |
1323 // screen52.goto_XY(y); | |
1324 } | |
1325 else { | |
1326 // b = bk.getNextByte(); | |
1327 if (planes.isUseGui(y)) | |
1328 continue; | |
1329 | |
1330 if (isAttribute(b)) { | |
1331 planes.setScreenCharAndAttr(y, planes.getChar(y), b, true); | |
1332 la = b; | |
1333 } | |
1334 else { | |
1335 // The characters on screen are in unicode | |
1336 char ch; | |
1337 if (isDataEBCDIC(b)) ch = codePage.ebcdic2uni(b); | |
1338 else ch = (char) b; | |
1339 planes.setScreenCharAndAttr(y, ch, la, false); | |
1340 } | |
1341 } | |
1342 } | |
1343 | |
1344 int numFields = bk.getNextByte() << 8 & 0xff00; | |
1345 numFields |= bk.getNextByte() & 0xff; | |
1346 Log.d(TAG, "number of fields " + numFields); | |
1347 | |
1348 if (numFields > 0) { | |
1349 int x = 0; | |
1350 int attr = 0; | |
1351 int fPos = 0; | |
1352 int fLen = 0; | |
1353 int ffw1 = 0; | |
1354 int ffw2 = 0; | |
1355 int fcw1 = 0; | |
1356 int fcw2 = 0; | |
1357 boolean mdt = false; | |
1358 ScreenField sf = null; | |
1359 | |
1360 while (x < numFields) { | |
1361 attr = bk.getNextByte(); | |
1362 fPos = bk.getNextByte() << 8 & 0xff00; | |
1363 fPos |= bk.getNextByte() & 0xff; | |
1364 | |
1365 if (bk.getNextByte() == 1) | |
1366 mdt = true; | |
1367 else | |
1368 mdt = false; | |
1369 | |
1370 fLen = bk.getNextByte() << 8 & 0xff00; | |
1371 fLen |= bk.getNextByte() & 0xff; | |
1372 ffw1 = bk.getNextByte(); | |
1373 ffw2 = bk.getNextByte(); | |
1374 fcw1 = bk.getNextByte(); | |
1375 fcw2 = bk.getNextByte(); | |
1376 sf = screen52.getScreenFields().setField(attr, | |
1377 screen52.getRow(fPos), screen52.getCol(fPos), fLen, | |
1378 ffw1, ffw2, fcw1, fcw2); | |
1379 | |
1380 while (fLen-- > 0) { | |
1381 // now we set the field plane attributes | |
1382 planes.setScreenFieldAttr(fPos++, ffw1); | |
1383 } | |
1384 | |
1385 if (mdt) { | |
1386 sf.setMDT(); | |
1387 screen52.getScreenFields().setMasterMDT(); | |
1388 } | |
1389 | |
1390 Log.d(TAG, "Restored "); | |
1391 Log.d(TAG, sf.toString()); | |
1392 x++; | |
1393 } | |
1394 } | |
1395 | |
1396 // Redraw the gui fields if we are in gui mode | |
1397 if (screen52.isUsingGuiInterface()) | |
1398 screen52.drawFields(); | |
1399 | |
1400 screen52.restoreScreen(); // display the screen | |
1401 // The position was saved with currentPos which 1,1 offset of the | |
1402 // screen position. | |
1403 // The setPendingInsert is the where the cursor position will be | |
1404 // displayed after the restore. | |
1405 screen52.setPendingInsert(true, screen52.getRow(pos + cols), screen52 | |
1406 .getCol(pos + cols)); | |
1407 // We need to offset the pos by -1 since the position is 1,1 based | |
1408 // and the goto_XY is 0,0 based. | |
1409 screen52.goto_XY(pos - 1); | |
1410 screen52.isInField(); | |
1411 // // Redraw the gui fields if we are in gui mode | |
1412 // if (screen52.isUsingGuiInterface()) | |
1413 // screen52.drawFields(); | |
1414 } | |
1415 catch (Exception e) { | |
1416 Log.w(TAG, "error restoring screen " + which + " with " | |
1417 + e.getMessage()); | |
1418 } | |
1419 } | |
1420 | |
1421 public final boolean waitingForInput() { | |
1422 return waitingForInput; | |
1423 } | |
1424 | |
1425 private void parseIncoming() { | |
1426 boolean done = false; | |
1427 boolean error = false; | |
1428 | |
1429 try { | |
1430 while (bk.hasNext() && !done) { | |
1431 byte b = bk.getNextByte(); | |
1432 | |
1433 switch (b) { | |
1434 case 0: | |
1435 case 1: | |
1436 break; | |
1437 | |
1438 case CMD_SAVE_SCREEN: // 0x02 2 Save Screen | |
1439 case 3: // 0x03 3 Save Partial Screen | |
1440 Log.d(TAG, "save screen partial"); | |
1441 saveScreen(); | |
1442 break; | |
1443 | |
1444 case ESC: // ESCAPE | |
1445 break; | |
1446 | |
1447 case 7: // audible bell | |
1448 manager.playBeep(); | |
1449 bk.getNextByte(); | |
1450 bk.getNextByte(); | |
1451 break; | |
1452 | |
1453 case CMD_WRITE_TO_DISPLAY: // 0x11 17 write to display | |
1454 error = writeToDisplay(true); | |
1455 | |
1456 // WVL - LDC : TR.000300 : Callback scenario from 5250 | |
1457 // Only scan when WRITE_TO_DISPLAY operation (i.e. refill | |
1458 // screen buffer) | |
1459 // has been issued! | |
1460 if (scan) | |
1461 scan(); | |
1462 | |
1463 break; | |
1464 | |
1465 case CMD_RESTORE_SCREEN: // 0x12 18 Restore Screen | |
1466 case 13: // 0x13 19 Restore Partial Screen | |
1467 Log.d(TAG, "restore screen partial"); | |
1468 restoreScreen(); | |
1469 break; | |
1470 | |
1471 case CMD_CLEAR_UNIT_ALTERNATE: // 0x20 32 clear unit alternate | |
1472 int param = bk.getNextByte(); | |
1473 | |
1474 if (param != 0) { | |
1475 Log.d(TAG, " clear unit alternate error " | |
1476 + Integer.toHexString(param)); | |
1477 sendNegResponse(NR_REQUEST_ERROR, 03, 01, 05, | |
1478 " clear unit alternate not supported"); | |
1479 done = true; | |
1480 } | |
1481 else { | |
1482 if (screen52.getRows() != 27) | |
1483 screen52.setRowsCols(27, 132); | |
1484 | |
1485 screen52.clearAll(); | |
1486 | |
1487 if (sfParser != null && sfParser.isGuisExists()) | |
1488 sfParser.clearGuiStructs(); | |
1489 } | |
1490 | |
1491 break; | |
1492 | |
1493 case CMD_WRITE_ERROR_CODE: // 0x21 33 Write Error Code | |
1494 writeErrorCode(); | |
1495 error = writeToDisplay(false); | |
1496 break; | |
1497 | |
1498 case CMD_WRITE_ERROR_CODE_TO_WINDOW: // 0x22 34 | |
1499 // Write Error Code to window | |
1500 writeErrorCodeToWindow(); | |
1501 error = writeToDisplay(false); | |
1502 break; | |
1503 | |
1504 case CMD_READ_SCREEN_IMMEDIATE: // 0x62 98 | |
1505 case CMD_READ_SCREEN_TO_PRINT: // 0x66 102 read screen to print | |
1506 readScreen(); | |
1507 break; | |
1508 | |
1509 case CMD_CLEAR_UNIT: // 64 0x40 clear unit | |
1510 if (screen52.getRows() != 24) | |
1511 screen52.setRowsCols(24, 80); | |
1512 | |
1513 screen52.clearAll(); | |
1514 | |
1515 if (sfParser != null && sfParser.isGuisExists()) | |
1516 sfParser.clearGuiStructs(); | |
1517 | |
1518 break; | |
1519 | |
1520 case CMD_CLEAR_FORMAT_TABLE: // 80 0x50 Clear format table | |
1521 screen52.clearTable(); | |
1522 break; | |
1523 | |
1524 case CMD_READ_INPUT_FIELDS: //0x42 66 read input fields | |
1525 case CMD_READ_MDT_FIELDS: // 0x52 82 read MDT Fields | |
1526 bk.getNextByte(); | |
1527 bk.getNextByte(); | |
1528 readType = b; | |
1529 screen52.goHome(); | |
1530 // do nothing with the cursor here it is taken care of | |
1531 // in the main loop. | |
1532 //////////////// screen52.setCursorOn(); | |
1533 waitingForInput = true; | |
1534 pendingUnlock = true; | |
1535 // screen52.setKeyboardLocked(false); | |
1536 break; | |
1537 | |
1538 case CMD_READ_MDT_IMMEDIATE_ALT: // 0x53 83 | |
1539 readType = b; | |
1540 // screen52.goHome(); | |
1541 // waitingForInput = true; | |
1542 // screen52.setKeyboardLocked(false); | |
1543 readImmediate(readType); | |
1544 break; | |
1545 | |
1546 case CMD_WRITE_STRUCTURED_FIELD: // 243 0xF3 -13 Write | |
1547 // structured field | |
1548 writeStructuredField(); | |
1549 break; | |
1550 | |
1551 case CMD_ROLL: // 0x23 35 Roll Not sure what it does right now | |
1552 int updown = bk.getNextByte(); | |
1553 int topline = bk.getNextByte(); | |
1554 int bottomline = bk.getNextByte(); | |
1555 screen52.rollScreen(updown, topline, bottomline); | |
1556 break; | |
1557 | |
1558 default: | |
1559 done = true; | |
1560 sendNegResponse(NR_REQUEST_ERROR, 03, 01, 01, | |
1561 "parseIncoming"); | |
1562 break; | |
1563 } | |
1564 | |
1565 if (error) | |
1566 done = true; | |
1567 } | |
1568 } | |
1569 catch (Exception exc) { | |
1570 Log.w(TAG, "incoming " + exc.getMessage()); | |
1571 } | |
1572 } | |
1573 | |
1574 /** | |
1575 * This routine handles sending negative responses back to the host. | |
1576 * | |
1577 * You can find a description of the types of responses to be sent back by | |
1578 * looking at section 12.4 of the 5250 Functions Reference manual | |
1579 * | |
1580 * | |
1581 * @param cat | |
1582 * @param modifier | |
1583 * @param uByte1 | |
1584 * @param uByte2 | |
1585 * @param from | |
1586 * | |
1587 */ | |
1588 protected void sendNegResponse(int cat, int modifier, int uByte1, | |
1589 int uByte2, String from) { | |
1590 try { | |
1591 int os = bk.getByteOffset(-1) & 0xf0; | |
1592 int cp = (bk.getCurrentPos() - 1); | |
1593 Log.i(TAG, "invalid " + from + " command " + os | |
1594 + " at pos " + cp); | |
1595 } | |
1596 catch (Exception e) { | |
1597 Log.w(TAG, "Send Negative Response error " + e.getMessage()); | |
1598 } | |
1599 | |
1600 baosp.write(cat); | |
1601 baosp.write(modifier); | |
1602 baosp.write(uByte1); | |
1603 baosp.write(uByte2); | |
1604 | |
1605 try { | |
1606 Log.i(TAG, "sendNegResponse() writeGDS()"); | |
1607 writeGDS(128, 0, baosp.toByteArray()); | |
1608 } | |
1609 catch (IOException ioe) { | |
1610 Log.w(TAG, ioe.getMessage()); | |
1611 } | |
1612 | |
1613 baosp.reset(); | |
1614 } | |
1615 | |
1616 public void sendNegResponse2(int ec) { | |
1617 screen52.setPrehelpState(true, true, false); | |
1618 baosp.write(0x00); | |
1619 baosp.write(ec); | |
1620 | |
1621 try { | |
1622 Log.i(TAG, "sendNegResponse2() writeGDS()"); | |
1623 writeGDS(1, 0, baosp.toByteArray()); | |
1624 } | |
1625 catch (IOException ioe) { | |
1626 Log.w(TAG, ioe.getMessage()); | |
1627 } | |
1628 | |
1629 baosp.reset(); | |
1630 } | |
1631 | |
1632 private boolean writeToDisplay(boolean controlsExist) { | |
1633 boolean error = false; | |
1634 boolean done = false; | |
1635 int attr; | |
1636 byte control0 = 0; | |
1637 byte control1 = 0; | |
1638 int saRows = screen52.getRows(); | |
1639 int saCols = screen52.getColumns(); | |
1640 | |
1641 try { | |
1642 if (controlsExist) { | |
1643 control0 = bk.getNextByte(); | |
1644 control1 = bk.getNextByte(); | |
1645 processCC0(control0); | |
1646 } | |
1647 | |
1648 while (bk.hasNext() && !done) { | |
1649 // pos = bk.getCurrentPos(); | |
1650 // int rowc = screen52.getCurrentRow(); | |
1651 // int colc = screen52.getCurrentCol(); | |
1652 byte bytebk = bk.getNextByte(); | |
1653 | |
1654 switch (bytebk) { | |
1655 case 1: // SOH - Start of Header Order | |
1656 Log.d(TAG, "SOH - Start of Header Order"); | |
1657 error = processSOH(); | |
1658 break; | |
1659 | |
1660 case 02: // RA - Repeat to address | |
1661 Log.d(TAG, "RA - Repeat to address"); | |
1662 int row = screen52.getCurrentRow(); | |
1663 int col = screen52.getCurrentCol(); | |
1664 int toRow = bk.getNextByte(); | |
1665 int toCol = bk.getNextByte() & 0xff; | |
1666 | |
1667 if (toRow >= row) { | |
1668 int repeat = bk.getNextByte(); | |
1669 | |
1670 // a little intelligence here I hope | |
1671 if (row == 1 && col == 2 && toRow == screen52.getRows() | |
1672 && toCol == screen52.getColumns()) | |
1673 screen52.clearScreen(); | |
1674 else { | |
1675 if (repeat != 0) { | |
1676 //LDC - 13/02/2003 - convert it to unicode | |
1677 repeat = codePage.ebcdic2uni(repeat); | |
1678 //repeat = getASCIIChar(repeat); | |
1679 } | |
1680 | |
1681 int times = ((toRow * screen52.getColumns()) + toCol) | |
1682 - ((row * screen52.getColumns()) + col); | |
1683 | |
1684 while (times-- >= 0) { | |
1685 screen52.setChar(repeat); | |
1686 } | |
1687 } | |
1688 } | |
1689 else { | |
1690 sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x23, | |
1691 " RA invalid"); | |
1692 error = true; | |
1693 } | |
1694 | |
1695 break; | |
1696 | |
1697 case 03: // EA - Erase to address | |
1698 Log.d(TAG, "EA - Erase to address"); | |
1699 int EArow = screen52.getCurrentRow(); | |
1700 int EAcol = screen52.getCurrentCol(); | |
1701 int toEARow = bk.getNextByte(); | |
1702 int toEACol = bk.getNextByte() & 0xff; | |
1703 int EALength = bk.getNextByte() & 0xff; | |
1704 | |
1705 while (--EALength > 0) { | |
1706 bk.getNextByte(); | |
1707 } | |
1708 | |
1709 char EAAttr = (char) 0; | |
1710 | |
1711 // a little intelligence here I hope | |
1712 if (EArow == 1 && EAcol == 2 | |
1713 && toEARow == screen52.getRows() | |
1714 && toEACol == screen52.getColumns()) | |
1715 screen52.clearScreen(); | |
1716 else { | |
1717 int times = ((toEARow * screen52.getColumns()) + toEACol) | |
1718 - ((EArow * screen52.getColumns()) + EAcol); | |
1719 | |
1720 while (times-- >= 0) { | |
1721 screen52.setChar(EAAttr); | |
1722 } | |
1723 } | |
1724 | |
1725 break; | |
1726 | |
1727 case 04: // Command - Escape | |
1728 Log.d(TAG, "Command - Escape"); | |
1729 done = true; | |
1730 break; | |
1731 | |
1732 case 16: // TD - Transparent Data | |
1733 Log.d(TAG, "TD - Transparent Data"); | |
1734 int j = (bk.getNextByte() & 0xff) << 8 | bk.getNextByte() | |
1735 & 0xff; // length | |
1736 break; | |
1737 | |
1738 case 17: // SBA - set buffer address order (row column) | |
1739 //Log.d(TAG,"SBA - set buffer address order (row column)"); | |
1740 int saRow = bk.getNextByte(); | |
1741 int saCol = bk.getNextByte() & 0xff; | |
1742 | |
1743 // make sure it is in bounds | |
1744 if (saRow >= 0 && saRow <= screen52.getRows() && saCol >= 0 | |
1745 && saCol <= screen52.getColumns()) { | |
1746 screen52.setCursor(saRow, saCol); // now set screen | |
1747 // position for output | |
1748 } | |
1749 else { | |
1750 sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x22, | |
1751 "invalid row/col order" + " saRow = " + saRow | |
1752 + " saRows = " + screen52.getRows() | |
1753 + " saCol = " + saCol); | |
1754 error = true; | |
1755 } | |
1756 | |
1757 break; | |
1758 | |
1759 case 18: // WEA - Extended Attribute | |
1760 Log.d(TAG, "WEA - Extended Attribute"); | |
1761 bk.getNextByte(); | |
1762 bk.getNextByte(); | |
1763 break; | |
1764 | |
1765 case 19: // IC - Insert Cursor | |
1766 Log.d(TAG, "IC - Insert Cursor"); | |
1767 int icX = bk.getNextByte(); | |
1768 int icY = bk.getNextByte() & 0xff; | |
1769 | |
1770 if (icX >= 0 && icX <= saRows && icY >= 0 && icY <= saCols) { | |
1771 Log.d(TAG, " IC " + icX + " " + icY); | |
1772 screen52.setPendingInsert(true, icX, icY); | |
1773 } | |
1774 else { | |
1775 sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x22, | |
1776 " IC/IM position invalid "); | |
1777 error = true; | |
1778 } | |
1779 | |
1780 break; | |
1781 | |
1782 case 20: // MC - Move Cursor | |
1783 Log.d(TAG, "MC - Move Cursor"); | |
1784 int imcX = bk.getNextByte(); | |
1785 int imcY = bk.getNextByte() & 0xff; | |
1786 | |
1787 if (imcX >= 0 && imcX <= saRows && imcY >= 0 | |
1788 && imcY <= saCols) { | |
1789 Log.d(TAG, " MC " + imcX + " " + imcY); | |
1790 screen52.setPendingInsert(false, imcX, imcY); | |
1791 } | |
1792 else { | |
1793 sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x22, | |
1794 " IC/IM position invalid "); | |
1795 error = true; | |
1796 } | |
1797 | |
1798 break; | |
1799 | |
1800 case 21: // WTDSF - Write To Display Structured Field order | |
1801 Log.d(TAG, "WTDSF - Write To Display Structured Field order"); | |
1802 byte[] seg = bk.getSegment(); | |
1803 error = sfParser.parseWriteToDisplayStructuredField(seg); | |
1804 break; | |
1805 | |
1806 case 29: // SF - Start of Field | |
1807 Log.d(TAG, "SF - Start of Field"); | |
1808 int fcw1 = 0; | |
1809 int fcw2 = 0; | |
1810 int ffw1 = 0; | |
1811 int ffw0 = bk.getNextByte() & 0xff; // FFW | |
1812 | |
1813 if ((ffw0 & 0x40) == 0x40) { | |
1814 ffw1 = bk.getNextByte() & 0xff; // FFW 1 | |
1815 fcw1 = bk.getNextByte() & 0xff; // check for field | |
1816 | |
1817 // control word | |
1818 | |
1819 // check if the first fcw1 is an 0x81 if it is then get | |
1820 // the next pair for checking | |
1821 if (fcw1 == 0x81) { | |
1822 bk.getNextByte(); | |
1823 fcw1 = bk.getNextByte() & 0xff; // check for field | |
1824 // control word | |
1825 } | |
1826 | |
1827 if (!isAttribute(fcw1)) { | |
1828 fcw2 = bk.getNextByte() & 0xff; // FCW 2 | |
1829 attr = bk.getNextByte() & 0xff; // attribute field | |
1830 | |
1831 while (!isAttribute(attr)) { | |
1832 Log.i(TAG, Integer.toHexString(fcw1) + " " | |
1833 + Integer.toHexString(fcw2) | |
1834 + " "); | |
1835 Log.i(TAG, Integer.toHexString(attr) | |
1836 + " " | |
1837 + Integer.toHexString(bk | |
1838 .getNextByte() & 0xff)); | |
1839 attr = bk.getNextByte() & 0xff; // attribute field | |
1840 } | |
1841 } | |
1842 else { | |
1843 attr = fcw1; // attribute of field | |
1844 fcw1 = 0; | |
1845 } | |
1846 } | |
1847 else { | |
1848 attr = ffw0; | |
1849 } | |
1850 | |
1851 int fLength = (bk.getNextByte() & 0xff) << 8 | |
1852 | bk.getNextByte() & 0xff; | |
1853 screen52.addField(attr, fLength, ffw0, ffw1, fcw1, fcw2); | |
1854 break; | |
1855 | |
1856 // WVL - LDC : 05/08/2005 : TFX.006253 - Support STRPCCMD | |
1857 case -128: //STRPCCMD | |
1858 // if (screen52.getCurrentPos() == 82) { | |
1859 Log.d(TAG, "STRPCCMD got a -128 command at " + screen52.getCurrentPos()); | |
1860 StringBuffer value = new StringBuffer(); | |
1861 int b; | |
1862 char c; | |
1863 int[] pco = new int[9]; | |
1864 int[] pcoOk = {0xfc, 0xd7, 0xc3, 0xd6, 0x40, 0x83, 0x80, 0xa1, 0x80}; | |
1865 | |
1866 for (int i = 0; i < 9; i++) { | |
1867 b = bk.getNextByte(); | |
1868 pco[i] = ((b & 0xff)); | |
1869 c = codePage.ebcdic2uni(b); | |
1870 value.append(c); | |
1871 } | |
1872 | |
1873 // Check "PCO-String" | |
1874 if (Arrays.equals(pco, pcoOk)) { | |
1875 strpccmd = true; | |
1876 } | |
1877 | |
1878 // we return in the stream to have all chars | |
1879 // arrive at the screen for later processing | |
1880 for (int i = 0; i < 9; i++) | |
1881 bk.setPrevByte(); | |
1882 | |
1883 //} | |
1884 // no break: so every chars arrives | |
1885 // on the screen for later parsing | |
1886 //break; | |
1887 | |
1888 default: // all others must be output to screen | |
1889 //Log.d(TAG,"all others must be output to screen"); | |
1890 byte byte0 = bk.getByteOffset(-1); | |
1891 | |
1892 if (isAttribute(byte0)) { | |
1893 screen52.setAttr(byte0); | |
1894 } | |
1895 else { | |
1896 if (!screen52.isStatusErrorCode()) { | |
1897 if (!isDataEBCDIC(byte0)) { | |
1898 // if (byte0 == 255) { | |
1899 // sendNegResponse(NR_REQUEST_ERROR,0x05,0x01,0x42, | |
1900 // " Attempt to send FF to screen"); | |
1901 // } | |
1902 // else | |
1903 screen52.setChar(byte0); | |
1904 } | |
1905 else | |
1906 //LDC - 13/02/2003 - Convert it to unicode | |
1907 //screen52.setChar(getASCIIChar(byte0)); | |
1908 screen52.setChar(codePage.ebcdic2uni(byte0)); | |
1909 } | |
1910 else { | |
1911 if (byte0 == 0) | |
1912 screen52.setChar(byte0); | |
1913 else | |
1914 //LDC - 13/02/2003 - Convert it to unicode | |
1915 //screen52.setChar(getASCIIChar(byte0)); | |
1916 screen52.setChar(codePage.ebcdic2uni(byte0)); | |
1917 } | |
1918 } | |
1919 | |
1920 break; | |
1921 } | |
1922 | |
1923 if (error) | |
1924 done = true; | |
1925 } | |
1926 } | |
1927 catch (Exception e) { | |
1928 Log.w(TAG, "write to display " + e.getMessage()); | |
1929 e.printStackTrace(); | |
1930 } | |
1931 | |
1932 ; | |
1933 | |
1934 processCC1(control1); | |
1935 | |
1936 return error; | |
1937 } | |
1938 | |
1939 private boolean processSOH() throws Exception { | |
1940 int l = bk.getNextByte(); // length | |
1941 Log.d(TAG, " byte 0 " + l); | |
1942 | |
1943 if (l > 0 && l <= 7) { | |
1944 bk.getNextByte(); // flag byte 2 | |
1945 bk.getNextByte(); // reserved | |
1946 bk.getNextByte(); // resequence fields | |
1947 screen52.clearTable(); | |
1948 | |
1949 // well that is the first time I have seen this. This fixes a | |
1950 // problem with S/36 command line. Finally got it. | |
1951 if (l <= 3) return false; | |
1952 | |
1953 screen52.setErrorLine(bk.getNextByte()); // error row | |
1954 int byte1 = 0; | |
1955 | |
1956 if (l >= 5) { | |
1957 byte1 = bk.getNextByte(); | |
1958 dataIncluded[23] = (byte1 & 0x80) == 0x80; | |
1959 dataIncluded[22] = (byte1 & 0x40) == 0x40; | |
1960 dataIncluded[21] = (byte1 & 0x20) == 0x20; | |
1961 dataIncluded[20] = (byte1 & 0x10) == 0x10; | |
1962 dataIncluded[19] = (byte1 & 0x8) == 0x8; | |
1963 dataIncluded[18] = (byte1 & 0x4) == 0x4; | |
1964 dataIncluded[17] = (byte1 & 0x2) == 0x2; | |
1965 dataIncluded[16] = (byte1 & 0x1) == 0x1; | |
1966 } | |
1967 | |
1968 if (l >= 6) { | |
1969 byte1 = bk.getNextByte(); | |
1970 dataIncluded[15] = (byte1 & 0x80) == 0x80; | |
1971 dataIncluded[14] = (byte1 & 0x40) == 0x40; | |
1972 dataIncluded[13] = (byte1 & 0x20) == 0x20; | |
1973 dataIncluded[12] = (byte1 & 0x10) == 0x10; | |
1974 dataIncluded[11] = (byte1 & 0x8) == 0x8; | |
1975 dataIncluded[10] = (byte1 & 0x4) == 0x4; | |
1976 dataIncluded[9] = (byte1 & 0x2) == 0x2; | |
1977 dataIncluded[8] = (byte1 & 0x1) == 0x1; | |
1978 } | |
1979 | |
1980 if (l >= 7) { | |
1981 byte1 = bk.getNextByte(); | |
1982 dataIncluded[7] = (byte1 & 0x80) == 0x80; | |
1983 dataIncluded[6] = (byte1 & 0x40) == 0x40; | |
1984 dataIncluded[5] = (byte1 & 0x20) == 0x20; | |
1985 dataIncluded[4] = (byte1 & 0x10) == 0x10; | |
1986 dataIncluded[3] = (byte1 & 0x8) == 0x8; | |
1987 dataIncluded[2] = (byte1 & 0x4) == 0x4; | |
1988 dataIncluded[1] = (byte1 & 0x2) == 0x2; | |
1989 dataIncluded[0] = (byte1 & 0x1) == 0x1; | |
1990 } | |
1991 | |
1992 return false; | |
1993 } | |
1994 else { | |
1995 sendNegResponse(NR_REQUEST_ERROR, 0x05, 0x01, 0x2B, | |
1996 "invalid SOH length"); | |
1997 return true; | |
1998 } | |
1999 } | |
2000 | |
2001 private void processCC0(byte byte0) { | |
2002 Log.d(TAG, " Control byte0 " + Integer.toBinaryString(byte0 & 0xff)); | |
2003 boolean lockKeyboard = true; | |
2004 boolean resetMDT = false; | |
2005 boolean resetMDTAll = false; | |
2006 boolean nullMDT = false; | |
2007 boolean nullAll = false; | |
2008 | |
2009 // Bits 3 to 6 are reserved and should be set to '0000' | |
2010 // 0xE0 = '11100000' - only the first 3 bits are tested | |
2011 if ((byte0 & 0xE0) == 0x00) { | |
2012 lockKeyboard = false; | |
2013 } | |
2014 | |
2015 // '00100000' = 0x20 /32 -- just lock keyboard | |
2016 // '01000000' = 0x40 /64 | |
2017 // '01100000' = 0x60 /96 | |
2018 // '10000000' = 0x80 /128 | |
2019 // '10100000' = 0xA0 /160 | |
2020 // '11000000' = 0xC0 /192 | |
2021 // '11100000' = 0xE0 /224 | |
2022 | |
2023 switch (byte0 & 0xE0) { | |
2024 case 0x40: | |
2025 resetMDT = true; | |
2026 break; | |
2027 | |
2028 case 0x60: | |
2029 resetMDTAll = true; | |
2030 break; | |
2031 | |
2032 case 0x80: | |
2033 nullMDT = true; | |
2034 break; | |
2035 | |
2036 case 0xA0: | |
2037 resetMDT = true; | |
2038 nullAll = true; | |
2039 break; | |
2040 | |
2041 case 0xC0: | |
2042 resetMDT = true; | |
2043 nullMDT = true; | |
2044 break; | |
2045 | |
2046 case 0xE0: | |
2047 resetMDTAll = true; | |
2048 nullAll = true; | |
2049 break; | |
2050 } | |
2051 | |
2052 if (lockKeyboard) { | |
2053 screen52.getOIA().setKeyBoardLocked(true); | |
2054 pendingUnlock = false; | |
2055 } | |
2056 else | |
2057 pendingUnlock = false; | |
2058 | |
2059 if (resetMDT || resetMDTAll || nullMDT || nullAll) { | |
2060 ScreenField sf; | |
2061 int f = screen52.getScreenFields().getSize(); | |
2062 | |
2063 for (int x = 0; x < f; x++) { | |
2064 sf = screen52.getScreenFields().getField(x); | |
2065 | |
2066 if (!sf.isBypassField()) { | |
2067 if ((nullMDT && sf.mdt) || nullAll) { | |
2068 sf.setFieldChar((char) 0x0); | |
2069 screen52.drawField(sf); | |
2070 } | |
2071 } | |
2072 | |
2073 if (resetMDTAll || (resetMDT && !sf.isBypassField())) | |
2074 sf.resetMDT(); | |
2075 } | |
2076 | |
2077 sf = null; | |
2078 } | |
2079 } | |
2080 | |
2081 private void processCC1(byte byte1) { | |
2082 Log.d(TAG, " Control byte1 " + Integer.toBinaryString(byte1 & 0xff)); | |
2083 | |
2084 if ((byte1 & 0x04) == 0x04) { | |
2085 manager.playBeep(); | |
2086 } | |
2087 | |
2088 if ((byte1 & 0x02) == 0x02) { | |
2089 screen52.getOIA().setMessageLightOff(); | |
2090 } | |
2091 | |
2092 if ((byte1 & 0x01) == 0x01) { | |
2093 screen52.getOIA().setMessageLightOn(); | |
2094 } | |
2095 | |
2096 if ((byte1 & 0x01) == 0x01 && (byte1 & 0x02) == 0x02) { | |
2097 screen52.getOIA().setMessageLightOn(); | |
2098 } | |
2099 | |
2100 // reset blinking cursor seems to control whether to set or not set the | |
2101 // the cursor position. No documentation for this just testing and | |
2102 // looking at the bit settings of this field. This was a pain in the | |
2103 // ass! | |
2104 // | |
2105 // if it is off '0' then keep existing cursor positioning information | |
2106 // if it is on '1' then reset the cursor positioning information | |
2107 // *** Note *** unless we receive bit 4 on at the same time | |
2108 // this seems to work so far | |
2109 if ((byte1 & 0x20) == 0x20 && (byte1 & 0x08) == 0x00) { | |
2110 screen52.setPendingInsert(false); | |
2111 Log.d(TAG, " WTD position no move"); | |
2112 } | |
2113 else { | |
2114 screen52.setPendingInsert(true); | |
2115 Log.d(TAG, " WTD position move to home" + screen52.homePos + " row " | |
2116 + screen52.getRow(screen52.homePos) + " col " | |
2117 + screen52.getCol(screen52.homePos)); | |
2118 } | |
2119 | |
2120 // in enhanced mode we sometimes only receive bit 6 turned on which | |
2121 // is reset blinking cursor | |
2122 if ((byte1 & 0x20) == 0x20 && enhanced) { | |
2123 cursorOn = true; | |
2124 } | |
2125 | |
2126 if (!screen52.isStatusErrorCode() && (byte1 & 0x08) == 0x08) { | |
2127 // screen52.setStatus(screen52.STATUS_SYSTEM,screen52.STATUS_VALUE_OFF,null); | |
2128 cursorOn = true; | |
2129 } | |
2130 | |
2131 if ((byte1 & 0x20) == 0x20 && (byte1 & 0x08) == 0x00) { | |
2132 screen52.setPendingInsert(false, 1, 1); | |
2133 } | |
2134 } | |
2135 | |
2136 private boolean isAttribute(int byte0) { | |
2137 int byte1 = byte0 & 0xff; | |
2138 return (byte1 & 0xe0) == 0x20; | |
2139 } | |
2140 | |
2141 //LDC - 12/02/2003 - Function name changed from isData to isDataEBCDIC | |
2142 private boolean isDataEBCDIC(int byte0) { | |
2143 int byte1 = byte0 & 0xff; | |
2144 | |
2145 // here it should always be less than 255 | |
2146 if (byte1 >= 64 && byte1 < 255) | |
2147 return true; | |
2148 else | |
2149 return false; | |
2150 } | |
2151 | |
2152 //LDC - 12/02/2003 - Test if the unicode character is a displayable | |
2153 // character. | |
2154 // The first 32 characters are non displayable characters | |
2155 // This is normally the inverse of isDataEBCDIC (That's why there is a | |
2156 // check on 255 -> 0xFFFF | |
2157 private boolean isDataUnicode(int byte0) { | |
2158 return (((byte0 < 0) || (byte0 >= 32)) && (byte0 != 0xFFFF)); | |
2159 } | |
2160 | |
2161 private void writeStructuredField() { | |
2162 boolean done = false; | |
2163 | |
2164 try { | |
2165 int length = ((bk.getNextByte() & 0xff) << 8 | (bk.getNextByte() & 0xff)); | |
2166 | |
2167 while (bk.hasNext() && !done) { | |
2168 switch (bk.getNextByte()) { | |
2169 case -39: // SOH - Start of Header Order | |
2170 switch (bk.getNextByte()) { | |
2171 case 112: // 5250 Query | |
2172 bk.getNextByte(); // get null required field | |
2173 sendQueryResponse(); | |
2174 break; | |
2175 | |
2176 default: | |
2177 Log.d(TAG, "invalid structured field sub command " | |
2178 + bk.getByteOffset(-1)); | |
2179 break; | |
2180 } | |
2181 | |
2182 break; | |
2183 | |
2184 default: | |
2185 Log.d(TAG, "invalid structured field command " | |
2186 + bk.getByteOffset(-1)); | |
2187 break; | |
2188 } | |
2189 } | |
2190 } | |
2191 catch (Exception e) { | |
2192 } | |
2193 | |
2194 ; | |
2195 } | |
2196 | |
2197 private final void writeErrorCode() throws Exception { | |
2198 screen52.setCursor(screen52.getErrorLine(), 1); // Skip the control byte | |
2199 screen52.setStatus(Screen5250.STATUS_ERROR_CODE, | |
2200 Screen5250.STATUS_VALUE_ON, null); | |
2201 screen52.saveErrorLine(); | |
2202 cursorOn = true; | |
2203 } | |
2204 | |
2205 private final void writeErrorCodeToWindow() throws Exception { | |
2206 int fromCol = bk.getNextByte() & 0xff; // from column | |
2207 int toCol = bk.getNextByte() & 0xff; // to column | |
2208 screen52.setCursor(screen52.getErrorLine(), fromCol); // Skip the control byte | |
2209 screen52.setStatus(Screen5250.STATUS_ERROR_CODE, | |
2210 Screen5250.STATUS_VALUE_ON, null); | |
2211 screen52.saveErrorLine(); | |
2212 cursorOn = true; | |
2213 } | |
2214 | |
2215 /** | |
2216 * Method sendQueryResponse | |
2217 * | |
2218 * The query command is used to obtain information about the capabilities of | |
2219 * the 5250 display. | |
2220 * | |
2221 * The Query command must follow an Escape (0x04) and Write Structured Field | |
2222 * command (0xF3). | |
2223 * | |
2224 * This section is modeled after the rfc1205 - 5250 Telnet Interface section | |
2225 * 5.3 | |
2226 * | |
2227 * @throws IOException | |
2228 */ | |
2229 private final void sendQueryResponse() throws IOException { | |
2230 Log.i(TAG, "sending query response"); | |
2231 byte abyte0[] = new byte[64]; | |
2232 abyte0[0] = 0; // Cursor Row/column (set to zero) | |
2233 abyte0[1] = 0; // "" | |
2234 abyte0[2] = -120; // X'88' inbound write structure Field aid | |
2235 | |
2236 if (enhanced) { | |
2237 abyte0[3] = 0; // 0x003D (61) length of query response | |
2238 abyte0[4] = 64; // "" see note below ????????? | |
2239 } | |
2240 else { | |
2241 abyte0[3] = 0; // 0x003A (58) length of query response | |
2242 abyte0[4] = 58; // "" | |
2243 // the length between 58 and 64 seems to cause | |
2244 // different formatting codes to be sent from | |
2245 // the host ???????????????? why ??????? | |
2246 // Well the why can be found in the manual if | |
2247 // read a little more ;-) | |
2248 } | |
2249 | |
2250 abyte0[5] = -39; // command class 0xD9 | |
2251 abyte0[6] = 112; // Command type query 0x70 | |
2252 abyte0[7] = -128; // 0x80 Flag byte | |
2253 abyte0[8] = 6; // Controller Hardware Class | |
2254 abyte0[9] = 0; // 0x0600 - Other WSF or another 5250 Emulator | |
2255 abyte0[10] = 1; // Controller Code Level | |
2256 abyte0[11] = 1; // Version 1 Rel 1.0 | |
2257 abyte0[12] = 0; // "" | |
2258 abyte0[13] = 0; // 13 - 28 are reserved so set to 0x00 | |
2259 abyte0[14] = 0; // "" | |
2260 abyte0[15] = 0; // "" | |
2261 abyte0[16] = 0; // "" | |
2262 abyte0[17] = 0; // "" | |
2263 abyte0[18] = 0; // "" | |
2264 abyte0[19] = 0; // "" | |
2265 abyte0[20] = 0; // "" | |
2266 abyte0[21] = 0; // "" | |
2267 abyte0[22] = 0; // "" | |
2268 abyte0[23] = 0; // "" | |
2269 abyte0[24] = 0; // "" | |
2270 abyte0[25] = 0; // "" | |
2271 abyte0[26] = 0; // "" | |
2272 abyte0[27] = 0; // "" | |
2273 abyte0[28] = 0; // "" | |
2274 abyte0[29] = 1; // Device type - 0x01 5250 Emulator | |
2275 abyte0[30] = codePage.uni2ebcdic('5'); // Device type character | |
2276 abyte0[31] = codePage.uni2ebcdic('2'); // "" | |
2277 abyte0[32] = codePage.uni2ebcdic('5'); // "" | |
2278 abyte0[33] = codePage.uni2ebcdic('1'); // "" | |
2279 abyte0[34] = codePage.uni2ebcdic('0'); // "" | |
2280 abyte0[35] = codePage.uni2ebcdic('1'); // "" | |
2281 abyte0[36] = codePage.uni2ebcdic('1'); // "" | |
2282 abyte0[37] = 2; // Keyboard Id - 0x02 Standard Keyboard | |
2283 abyte0[38] = 0; // extended keyboard id | |
2284 abyte0[39] = 0; // reserved | |
2285 abyte0[40] = 0; // 40 - 43 Display Serial Number | |
2286 abyte0[41] = 36; // | |
2287 abyte0[42] = 36; // | |
2288 abyte0[43] = 0; // | |
2289 abyte0[44] = 1; // Maximum number of display fields - 256 | |
2290 abyte0[45] = 0; // 0x0100 | |
2291 abyte0[46] = 0; // 46 -48 Reserved set to 0x00 | |
2292 abyte0[47] = 0; | |
2293 abyte0[48] = 0; | |
2294 abyte0[49] = 1; // 49 - 53 Controller Display Capability | |
2295 abyte0[50] = 17; // see rfc - tired of typing :-) | |
2296 abyte0[51] = 0; // "" | |
2297 abyte0[52] = 0; // "" | |
2298 | |
2299 // 53 | |
2300 // Bit 0-2: B'000' - no graphics capability | |
2301 // B'001' - 5292-2 style graphics | |
2302 // Bit 3-7: B '00000' = reserved (it seems for Client access) | |
2303 | |
2304 if (enhanced) { | |
2305 // abyte0[53] = 0x5E; // 0x5E turns on enhanced mode | |
2306 // abyte0[53] = 0x27; // 0x5E turns on enhanced mode | |
2307 abyte0[53] = 0x7; // 0x5E turns on ehnhanced mode | |
2308 Log.i(TAG, "enhanced options"); | |
2309 } | |
2310 else | |
2311 abyte0[53] = 0x0; // 0x0 is normal emulation | |
2312 | |
2313 abyte0[54] = 24; // 54 - 60 Reserved set to 0x00 | |
2314 // 54 - I found out is used for enhanced user | |
2315 // interface level 3. Bit 4 allows headers | |
2316 // and footers for windows | |
2317 abyte0[54] = 8; // 54 - 60 Reserved set to 0x00 | |
2318 // 54 - I found out is used for enhanced user | |
2319 // interface level 3. Bit 4 allows headers | |
2320 // and footers for windows | |
2321 abyte0[55] = 0; | |
2322 abyte0[56] = 0; | |
2323 abyte0[57] = 0; | |
2324 abyte0[58] = 0; | |
2325 abyte0[59] = 0; | |
2326 abyte0[60] = 0; | |
2327 abyte0[61] = 0; // gridlines are not supported | |
2328 abyte0[62] = 0; // gridlines are not supported | |
2329 abyte0[63] = 0; | |
2330 Log.i(TAG, "sendQueryResponse() writeGDS()"); | |
2331 writeGDS(0, 0, abyte0); // now tell them about us | |
2332 abyte0 = null; | |
2333 } | |
2334 | |
2335 protected final boolean negotiate(byte abyte0[]) throws IOException { | |
2336 int i = 0; | |
2337 | |
2338 // from server negotiations | |
2339 if (abyte0[i] == IAC) { // -1 | |
2340 while (i < abyte0.length && abyte0[i++] == -1) | |
2341 | |
2342 // while(i < abyte0.length && (abyte0[i] == -1 || abyte0[i++] == 0x20)) | |
2343 switch (abyte0[i++]) { | |
2344 // we will not worry about what it WONT do | |
2345 case WONT: // -4 | |
2346 default: | |
2347 break; | |
2348 | |
2349 case DO: //-3 | |
2350 | |
2351 // not sure why but since moving to V5R2 we are receiving a | |
2352 // DO with no option when connecting a second session with | |
2353 // device name. Can not find the cause at all. If anybody | |
2354 // is interested please debug this until then this works. | |
2355 if (i < abyte0.length) { | |
2356 switch (abyte0[i]) { | |
2357 case TERMINAL_TYPE: // 24 | |
2358 baosp.write(IAC); | |
2359 baosp.write(WILL); | |
2360 baosp.write(TERMINAL_TYPE); | |
2361 writeByte(baosp.toByteArray()); | |
2362 baosp.reset(); | |
2363 break; | |
2364 | |
2365 case OPT_END_OF_RECORD: // 25 | |
2366 baosp.write(IAC); | |
2367 baosp.write(WILL); | |
2368 baosp.write(OPT_END_OF_RECORD); | |
2369 writeByte(baosp.toByteArray()); | |
2370 baosp.reset(); | |
2371 break; | |
2372 | |
2373 case TRANSMIT_BINARY: // 0 | |
2374 baosp.write(IAC); | |
2375 baosp.write(WILL); | |
2376 baosp.write(TRANSMIT_BINARY); | |
2377 writeByte(baosp.toByteArray()); | |
2378 baosp.reset(); | |
2379 break; | |
2380 | |
2381 case TIMING_MARK: // 6 rfc860 | |
2382 // System.out.println("Timing Mark Received and notifying " + | |
2383 // "the server that we will not do it"); | |
2384 baosp.write(IAC); | |
2385 baosp.write(WONT); | |
2386 baosp.write(TIMING_MARK); | |
2387 writeByte(baosp.toByteArray()); | |
2388 baosp.reset(); | |
2389 break; | |
2390 | |
2391 case NEW_ENVIRONMENT: // 39 rfc1572, rfc4777 | |
2392 // allways send new environment vars ... | |
2393 baosp.write(IAC); | |
2394 baosp.write(WILL); | |
2395 baosp.write(NEW_ENVIRONMENT); | |
2396 writeByte(baosp.toByteArray()); | |
2397 baosp.reset(); | |
2398 break; | |
2399 | |
2400 default: // every thing else we will not do at this time | |
2401 baosp.write(IAC); | |
2402 baosp.write(WONT); | |
2403 baosp.write(abyte0[i]); // either | |
2404 writeByte(baosp.toByteArray()); | |
2405 baosp.reset(); | |
2406 break; | |
2407 } | |
2408 } | |
2409 | |
2410 i++; | |
2411 break; | |
2412 | |
2413 case WILL: | |
2414 switch (abyte0[i]) { | |
2415 case OPT_END_OF_RECORD: // 25 | |
2416 baosp.write(IAC); | |
2417 baosp.write(DO); | |
2418 baosp.write(OPT_END_OF_RECORD); | |
2419 writeByte(baosp.toByteArray()); | |
2420 baosp.reset(); | |
2421 break; | |
2422 | |
2423 case TRANSMIT_BINARY: // '\0' | |
2424 baosp.write(IAC); | |
2425 baosp.write(DO); | |
2426 baosp.write(TRANSMIT_BINARY); | |
2427 writeByte(baosp.toByteArray()); | |
2428 baosp.reset(); | |
2429 break; | |
2430 } | |
2431 | |
2432 i++; | |
2433 break; | |
2434 | |
2435 case SB: // -6 | |
2436 if (abyte0[i] == NEW_ENVIRONMENT && abyte0[i + 1] == 1) { | |
2437 negNewEnvironment(); | |
2438 | |
2439 while (++i < abyte0.length && abyte0[i + 1] != IAC); | |
2440 } | |
2441 | |
2442 if (abyte0[i] == TERMINAL_TYPE && abyte0[i + 1] == 1) { | |
2443 baosp.write(IAC); | |
2444 baosp.write(SB); | |
2445 baosp.write(TERMINAL_TYPE); | |
2446 baosp.write(QUAL_IS); | |
2447 | |
2448 if (!support132) | |
2449 baosp.write("IBM-3179-2".getBytes()); | |
2450 else | |
2451 baosp.write("IBM-3477-FC".getBytes()); | |
2452 | |
2453 baosp.write(IAC); | |
2454 baosp.write(SE); | |
2455 writeByte(baosp.toByteArray()); | |
2456 baosp.reset(); | |
2457 i++; | |
2458 } | |
2459 | |
2460 i++; | |
2461 break; | |
2462 } | |
2463 | |
2464 return true; | |
2465 } | |
2466 else { | |
2467 return false; | |
2468 } | |
2469 } | |
2470 | |
2471 /** | |
2472 * Negotiate new environment string for device name | |
2473 * | |
2474 * @throws IOException | |
2475 */ | |
2476 private void negNewEnvironment() throws IOException { | |
2477 baosp.write(IAC); | |
2478 baosp.write(SB); | |
2479 baosp.write(NEW_ENVIRONMENT); | |
2480 baosp.write(IS); | |
2481 | |
2482 // http://tools.ietf.org/html/rfc4777 | |
2483 | |
2484 if (kbdTypesCodePage != null) { | |
2485 baosp.write(USERVAR); | |
2486 baosp.write("KBDTYPE".getBytes()); | |
2487 baosp.write(VALUE); | |
2488 baosp.write(kbdTypesCodePage.kbdType.getBytes()); | |
2489 baosp.write(USERVAR); | |
2490 baosp.write("CODEPAGE".getBytes()); | |
2491 baosp.write(VALUE); | |
2492 baosp.write(kbdTypesCodePage.codepage.getBytes()); | |
2493 baosp.write(USERVAR); | |
2494 baosp.write("CHARSET".getBytes()); | |
2495 baosp.write(VALUE); | |
2496 baosp.write(kbdTypesCodePage.charset.getBytes()); | |
2497 } | |
2498 | |
2499 if (devName != null) { | |
2500 baosp.write(USERVAR); | |
2501 baosp.write("DEVNAME".getBytes()); | |
2502 baosp.write(VALUE); | |
2503 baosp.write(negDeviceName().getBytes()); | |
2504 } | |
2505 | |
2506 if (user != null) { | |
2507 baosp.write(VAR); | |
2508 baosp.write("USER".getBytes()); | |
2509 baosp.write(VALUE); | |
2510 baosp.write(user.getBytes()); | |
2511 | |
2512 if (password != null) { | |
2513 baosp.write(USERVAR); | |
2514 baosp.write("IBMRSEED".getBytes()); | |
2515 baosp.write(VALUE); | |
2516 baosp.write(NEGOTIATE_ESC); | |
2517 baosp.write(0x0); | |
2518 baosp.write(0x0); | |
2519 baosp.write(0x0); | |
2520 baosp.write(0x0); | |
2521 baosp.write(0x0); | |
2522 baosp.write(0x0); | |
2523 baosp.write(0x0); | |
2524 baosp.write(0x0); | |
2525 baosp.write(USERVAR); | |
2526 baosp.write("IBMSUBSPW".getBytes()); | |
2527 baosp.write(VALUE); | |
2528 baosp.write(password.getBytes()); | |
2529 } | |
2530 | |
2531 if (library != null) { | |
2532 baosp.write(USERVAR); | |
2533 baosp.write("IBMCURLIB".getBytes()); | |
2534 baosp.write(VALUE); | |
2535 baosp.write(library.getBytes()); | |
2536 } | |
2537 | |
2538 if (initialMenu != null) { | |
2539 baosp.write(USERVAR); | |
2540 baosp.write("IBMIMENU".getBytes()); | |
2541 baosp.write(VALUE); | |
2542 baosp.write(initialMenu.getBytes()); | |
2543 } | |
2544 | |
2545 if (program != null) { | |
2546 baosp.write(USERVAR); | |
2547 baosp.write("IBMPROGRAM".getBytes()); | |
2548 baosp.write(VALUE); | |
2549 baosp.write(program.getBytes()); | |
2550 } | |
2551 } | |
2552 | |
2553 baosp.write(IAC); | |
2554 baosp.write(SE); | |
2555 writeByte(baosp.toByteArray()); | |
2556 baosp.reset(); | |
2557 } | |
2558 | |
2559 /** | |
2560 * This will negotiate a device name with controller. if the sequence is | |
2561 * less than zero then it will send the device name as specified. On each | |
2562 * unsuccessful attempt a sequential number is appended until we find one or | |
2563 * the controller says no way. | |
2564 * | |
2565 * @return String | |
2566 */ | |
2567 private String negDeviceName() { | |
2568 if (devSeq++ == -1) { | |
2569 devNameUsed = devName; | |
2570 return devName; | |
2571 } | |
2572 else { | |
2573 StringBuffer sb = new StringBuffer(devName + devSeq); | |
2574 int ei = 1; | |
2575 | |
2576 while (sb.length() > 10) { | |
2577 sb.setLength(0); | |
2578 sb.append(devName.substring(0, devName.length() - ei++)); | |
2579 sb.append(devSeq); | |
2580 } | |
2581 | |
2582 devNameUsed = sb.toString(); | |
2583 return devNameUsed; | |
2584 } | |
2585 } | |
2586 | |
2587 public final void setCodePage(String cp) { | |
2588 codePage = CharMappings.getCodePage(cp); | |
2589 cp = cp.toLowerCase(); | |
2590 | |
2591 for (KbdTypesCodePages kbdtyp : KbdTypesCodePages.values()) { | |
2592 if (("cp" + kbdtyp.codepage).equals(cp) || kbdtyp.ccsid.equals(cp)) { | |
2593 kbdTypesCodePage = kbdtyp; | |
2594 break; | |
2595 } | |
2596 } | |
2597 | |
2598 Log.i(TAG, "Chose keyboard mapping " + kbdTypesCodePage.toString() + " for code page " + cp); | |
2599 } | |
2600 | |
2601 public final ICodePage getCodePage() { | |
2602 return codePage; | |
2603 } | |
2604 | |
2605 public void signalBell() { | |
2606 manager.playBeep(); | |
2607 } | |
2608 | |
2609 } |