Mercurial > 510Connectbot
comparison src/com/five_ten_sg/connectbot/service/TerminalBridge.java @ 79:01d939969b10
merge tn5250 branch into default
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 16 Jun 2014 08:24:00 -0700 |
parents | 1588e359a972 99d5b02ad90c |
children | 33eb63352be5 |
comparison
equal
deleted
inserted
replaced
19:b3d0d806cbe2 | 79:01d939969b10 |
---|---|
93 | 93 |
94 final Paint defaultPaint; | 94 final Paint defaultPaint; |
95 | 95 |
96 private Relay relay; | 96 private Relay relay; |
97 | 97 |
98 private final String emulation; | 98 private String emulation; // aka answerback string, aka terminal type |
99 private final int scrollback; | |
100 | 99 |
101 public Bitmap bitmap = null; | 100 public Bitmap bitmap = null; |
102 public vt320 buffer = null; | 101 public vt320 buffer = null; |
103 | 102 |
104 private TerminalView parent = null; | 103 public TerminalView parent = null; |
105 private final Canvas canvas = new Canvas(); | 104 private final Canvas canvas = new Canvas(); |
106 | 105 |
107 private boolean disconnected = false; | 106 private boolean disconnected = false; |
108 private boolean awaitingClose = false; | 107 private boolean awaitingClose = false; |
109 | 108 |
118 private final SelectionArea selectionArea; | 117 private final SelectionArea selectionArea; |
119 | 118 |
120 // TODO add support for the new clipboard API | 119 // TODO add support for the new clipboard API |
121 private ClipboardManager clipboard; | 120 private ClipboardManager clipboard; |
122 | 121 |
123 public int charWidth = -1; | 122 public int charWidth = -1; |
124 public int charHeight = -1; | 123 public int charHeight = -1; |
125 private int charTop = -1; | 124 private int charTop = -1; |
126 | 125 private float fontSize = -1; |
127 private float fontSize = -1; | |
128 | 126 |
129 private final List<FontSizeChangedListener> fontSizeChangedListeners; | 127 private final List<FontSizeChangedListener> fontSizeChangedListeners; |
130 | 128 |
131 private final List<String> localOutput; | 129 private final List<String> localOutput; |
132 | 130 |
158 }; | 156 }; |
159 emulation = null; | 157 emulation = null; |
160 manager = null; | 158 manager = null; |
161 defaultPaint = new Paint(); | 159 defaultPaint = new Paint(); |
162 selectionArea = new SelectionArea(); | 160 selectionArea = new SelectionArea(); |
163 scrollback = 1; | |
164 localOutput = new LinkedList<String>(); | 161 localOutput = new LinkedList<String>(); |
165 fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>(); | 162 fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>(); |
166 transport = null; | 163 transport = null; |
167 keyListener = new TerminalKeyListener(manager, this, buffer, null); | 164 keyListener = new TerminalKeyListener(manager, this, buffer, null); |
168 monitor = null; | 165 monitor = null; |
169 } | 166 } |
170 | 167 |
171 /** | 168 /** |
172 * Create new terminal bridge with following parameters. We will immediately | 169 * Create new terminal bridge with following parameters. |
173 * launch thread to start SSH connection and handle any hostkey verification | |
174 * and password authentication. | |
175 */ | 170 */ |
176 public TerminalBridge(final TerminalManager manager, final HostBean host) throws IOException { | 171 public TerminalBridge(final TerminalManager manager, final HostBean host) throws IOException { |
177 float hostFontSize; | 172 float hostFontSize; |
178 this.manager = manager; | 173 this.manager = manager; |
179 this.host = host; | 174 this.host = host; |
180 emulation = manager.getEmulation(); | 175 emulation = host.getHostEmulation(); |
181 scrollback = manager.getScrollback(); | 176 if ((emulation == null) || (emulation.length() == 0)) emulation = manager.getEmulation(); |
182 // create prompt helper to relay password and hostkey requests up to gui | 177 // create prompt helper to relay password and hostkey requests up to gui |
183 promptHelper = new PromptHelper(this); | 178 promptHelper = new PromptHelper(this); |
184 // create our default paint | 179 // create our default paint |
185 defaultPaint = new Paint(); | 180 defaultPaint = new Paint(); |
186 defaultPaint.setAntiAlias(true); | 181 defaultPaint.setAntiAlias(true); |
189 localOutput = new LinkedList<String>(); | 184 localOutput = new LinkedList<String>(); |
190 fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>(); | 185 fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>(); |
191 Integer defaultFontSize = Integer.parseInt(manager.prefs.getString(PreferenceConstants.DEFAULT_FONT_SIZE, "-1")); | 186 Integer defaultFontSize = Integer.parseInt(manager.prefs.getString(PreferenceConstants.DEFAULT_FONT_SIZE, "-1")); |
192 Log.i(TAG, "fontSize: " + this.fontSize + ", defaultFontSize: " + defaultFontSize); | 187 Log.i(TAG, "fontSize: " + this.fontSize + ", defaultFontSize: " + defaultFontSize); |
193 | 188 |
194 if (this.fontSize == -1) { | 189 if (fontSize == -1) { |
195 if (defaultFontSize > 0 && host.getFontSize() == -1) | 190 if (defaultFontSize > 0 && host.getFontSize() == -1) |
196 hostFontSize = defaultFontSize; | 191 hostFontSize = defaultFontSize; |
197 else | 192 else |
198 hostFontSize = host.getFontSize(); | 193 hostFontSize = host.getFontSize(); |
199 } | 194 } |
200 else | 195 else |
201 hostFontSize = this.fontSize; | 196 hostFontSize = fontSize; |
202 | 197 |
203 if (hostFontSize <= 0) | 198 if (hostFontSize <= 0) hostFontSize = DEFAULT_FONT_SIZE; |
204 hostFontSize = DEFAULT_FONT_SIZE; | |
205 | 199 |
206 setFontSize(hostFontSize); | 200 setFontSize(hostFontSize); |
207 // create terminal buffer and handle outgoing data | |
208 // this is probably status reply information | |
209 buffer = new vt320() { | |
210 @Override | |
211 public void debug(String s) { | |
212 Log.d(TAG, s); | |
213 } | |
214 @Override | |
215 public void write(byte[] b) { | |
216 try { | |
217 if (b != null && transport != null) { | |
218 if (monitor != null) monitor.hostData(b); | |
219 transport.write(b); | |
220 } | |
221 } | |
222 catch (IOException e) { | |
223 Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); | |
224 } | |
225 } | |
226 @Override | |
227 public void write(int b) { | |
228 try { | |
229 if (transport != null) { | |
230 if (monitor != null) monitor.hostData(b); | |
231 transport.write(b); | |
232 } | |
233 } | |
234 catch (IOException e) { | |
235 Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); | |
236 } | |
237 } | |
238 // We don't use telnet sequences. | |
239 @Override | |
240 public void sendTelnetCommand(byte cmd) { | |
241 } | |
242 // We don't want remote to resize our window. | |
243 @Override | |
244 public void setWindowSize(int c, int r) { | |
245 } | |
246 // test for changed screen contents | |
247 @Override | |
248 public void testChanged() { | |
249 if (monitor != null) monitor.testChanged(); | |
250 } | |
251 // play beep noise | |
252 @Override | |
253 public void beep() { | |
254 if (parent.isShown()) | |
255 manager.playBeep(); | |
256 else | |
257 manager.sendActivityNotification(host); | |
258 } | |
259 // monitor placement of new characters | |
260 @Override | |
261 public void putChar(int c, int l, char ch, int attributes) { | |
262 if (monitor != null) monitor.screenChanged(l, c); | |
263 | |
264 super.putChar(c, l, ch, attributes); | |
265 } | |
266 @Override | |
267 public void insertChar(int c, int l, char ch, int attributes) { | |
268 if (monitor != null) monitor.screenChanged(l, l, c, width - 1); | |
269 | |
270 super.insertChar(c, l, ch, attributes); | |
271 } | |
272 @Override | |
273 public void insertLine(int l, int n, boolean scrollDown) { | |
274 if (monitor != null) { | |
275 if (scrollDown) monitor.screenChanged(l, height - 1, 0, width - 1); | |
276 else monitor.screenChanged(0, l, 0, width - 1); | |
277 } | |
278 | |
279 super.insertLine(l, n, scrollDown); | |
280 } | |
281 @Override | |
282 public void deleteLine(int l) { | |
283 if (monitor != null) monitor.screenChanged(l, height - 1, 0, width - 1); | |
284 | |
285 super.deleteLine(l); | |
286 } | |
287 @Override | |
288 public void deleteChar(int c, int l) { | |
289 if (monitor != null) monitor.screenChanged(l, l, c, width - 1); | |
290 | |
291 super.deleteChar(c, l); | |
292 } | |
293 @Override | |
294 public void setCursorPosition(int c, int l) { | |
295 if (monitor != null) monitor.cursorMove(l, c); | |
296 | |
297 super.setCursorPosition(c, l); | |
298 } | |
299 }; | |
300 | |
301 // Don't keep any scrollback if a session is not being opened. | |
302 if (host.getWantSession()) | |
303 buffer.setBufferSize(scrollback); | |
304 else | |
305 buffer.setBufferSize(0); | |
306 | |
307 resetColors(); | 201 resetColors(); |
308 buffer.setDisplay(this); | |
309 selectionArea = new SelectionArea(); | 202 selectionArea = new SelectionArea(); |
310 keyListener = new TerminalKeyListener(manager, this, buffer, host.getEncoding()); | 203 } |
204 | |
205 public PromptHelper getPromptHelper() { | |
206 return promptHelper; | |
207 } | |
208 | |
209 /** | |
210 * Spawn thread to open connection and start login process. | |
211 */ | |
212 protected void startConnection() { | |
213 transport = TransportFactory.getTransport(host.getProtocol()); | |
214 transport.setLinks(manager, this, host, emulation); | |
215 buffer = transport.getTransportBuffer(); | |
216 keyListener = transport.getTerminalKeyListener(); | |
311 | 217 |
312 String monitor_init = host.getMonitor(); | 218 String monitor_init = host.getMonitor(); |
313 if ((monitor_init != null) && (monitor_init.length() > 0)) { | 219 if ((monitor_init != null) && (monitor_init.length() > 0)) { |
314 monitor = new TerminalMonitor(manager, buffer, keyListener, parent, monitor_init); | 220 monitor = new TerminalMonitor(manager, buffer, keyListener, parent, monitor_init); |
315 } | 221 } |
316 } | 222 |
317 | |
318 public PromptHelper getPromptHelper() { | |
319 return promptHelper; | |
320 } | |
321 | |
322 /** | |
323 * Spawn thread to open connection and start login process. | |
324 */ | |
325 protected void startConnection() { | |
326 transport = TransportFactory.getTransport(host.getProtocol()); | |
327 transport.setBridge(this); | |
328 transport.setManager(manager); | |
329 transport.setHost(host); | |
330 // TODO make this more abstract so we don't litter on AbsTransport | |
331 transport.setCompression(host.getCompression()); | 223 transport.setCompression(host.getCompression()); |
332 transport.setHttpproxy(host.getHttpproxy()); | 224 transport.setHttpproxy(host.getHttpproxy()); |
333 transport.setUseAuthAgent(host.getUseAuthAgent()); | 225 transport.setUseAuthAgent(host.getUseAuthAgent()); |
334 transport.setEmulation(emulation); | |
335 | 226 |
336 if (transport.canForwardPorts()) { | 227 if (transport.canForwardPorts()) { |
337 for (PortForwardBean portForward : manager.hostdb.getPortForwardsForHost(host)) | 228 for (PortForwardBean portForward : manager.hostdb.getPortForwardsForHost(host)) |
338 transport.addPortForward(portForward); | 229 transport.addPortForward(portForward); |
339 } | 230 } |
365 | 256 |
366 /** | 257 /** |
367 * @return charset in use by bridge | 258 * @return charset in use by bridge |
368 */ | 259 */ |
369 public Charset getCharset() { | 260 public Charset getCharset() { |
370 return relay.getCharset(); | 261 if (relay != null) return relay.getCharset(); |
262 return keyListener.getCharset(); | |
371 } | 263 } |
372 | 264 |
373 /** | 265 /** |
374 * Sets the encoding used by the terminal. If the connection is live, | 266 * Sets the encoding used by the terminal. If the connection is live, |
375 * then the character set is changed for the next read. | 267 * then the character set is changed for the next read. |
376 * @param encoding the canonical name of the character encoding | 268 * @param encoding the canonical name of the character encoding |
377 */ | 269 */ |
378 public void setCharset(String encoding) { | 270 public void setCharset(String encoding) { |
379 if (relay != null) | 271 if (relay != null) relay.setCharset(encoding); |
380 relay.setCharset(encoding); | |
381 | |
382 keyListener.setCharset(encoding); | 272 keyListener.setCharset(encoding); |
383 } | 273 } |
384 | 274 |
385 /** | 275 /** |
386 * Convenience method for writing a line into the underlying MUD buffer. | 276 * Convenience method for writing a line into the underlying MUD buffer. |
427 * authentication. If called before authenticated, it will just fail. | 317 * authentication. If called before authenticated, it will just fail. |
428 */ | 318 */ |
429 public void onConnected() { | 319 public void onConnected() { |
430 disconnected = false; | 320 disconnected = false; |
431 buffer.reset(); | 321 buffer.reset(); |
432 // We no longer need our local output. | |
433 localOutput.clear(); | |
434 // previously tried vt100 and xterm for emulation modes | |
435 // "screen" works the best for color and escape codes | |
436 buffer.setAnswerBack(emulation); | 322 buffer.setAnswerBack(emulation); |
323 localOutput.clear(); // We no longer need our local output. | |
437 | 324 |
438 if (HostDatabase.DELKEY_BACKSPACE.equals(host.getDelKey())) | 325 if (HostDatabase.DELKEY_BACKSPACE.equals(host.getDelKey())) |
439 buffer.setBackspace(vt320.DELETE_IS_BACKSPACE); | 326 buffer.setBackspace(vt320.DELETE_IS_BACKSPACE); |
440 else | 327 else |
441 buffer.setBackspace(vt320.DELETE_IS_DEL); | 328 buffer.setBackspace(vt320.DELETE_IS_DEL); |
442 | 329 |
443 // create thread to relay incoming connection data to buffer | 330 // create thread to relay incoming connection data to buffer |
444 relay = new Relay(this, transport, buffer, host.getEncoding()); | 331 // only if needed by the transport |
445 Thread relayThread = new Thread(relay); | 332 if (transport.needsRelay()) { |
446 relayThread.setDaemon(true); | 333 relay = new Relay(this, transport, buffer, host.getEncoding()); |
447 relayThread.setName("Relay"); | 334 Thread relayThread = new Thread(relay); |
448 relayThread.start(); | 335 relayThread.setDaemon(true); |
336 relayThread.setName("Relay"); | |
337 relayThread.start(); | |
338 } | |
339 | |
449 // force font-size to make sure we resizePTY as needed | 340 // force font-size to make sure we resizePTY as needed |
450 setFontSize(fontSize); | 341 setFontSize(fontSize); |
451 // finally send any post-login string, if requested | 342 // finally send any post-login string, if requested |
452 injectString(host.getPostLogin()); | 343 injectString(host.getPostLogin()); |
453 } | 344 } |
561 defaultPaint.getTextWidths("X", widths); | 452 defaultPaint.getTextWidths("X", widths); |
562 charWidth = (int)FloatMath.ceil(widths[0]); | 453 charWidth = (int)FloatMath.ceil(widths[0]); |
563 charHeight = (int)FloatMath.ceil(fm.descent - fm.top); | 454 charHeight = (int)FloatMath.ceil(fm.descent - fm.top); |
564 | 455 |
565 // refresh any bitmap with new font size | 456 // refresh any bitmap with new font size |
566 if (parent != null) | 457 if (parent != null) parentChanged(parent); |
567 parentChanged(parent); | |
568 | 458 |
569 for (FontSizeChangedListener ofscl : fontSizeChangedListeners) | 459 for (FontSizeChangedListener ofscl : fontSizeChangedListeners) |
570 ofscl.onFontSizeChanged(size); | 460 ofscl.onFontSizeChanged(size); |
571 | 461 |
572 host.setFontSize((int) fontSize); | 462 host.setFontSize((int) fontSize); |
662 canvas.drawLine(0, borderY, borderX + 1, borderY, defaultPaint); | 552 canvas.drawLine(0, borderY, borderX + 1, borderY, defaultPaint); |
663 } | 553 } |
664 | 554 |
665 try { | 555 try { |
666 // request a terminal pty resize | 556 // request a terminal pty resize |
667 synchronized (buffer) { | 557 if (buffer != null) { |
668 buffer.setScreenSize(columns, rows, true); | 558 synchronized (buffer) { |
559 buffer.setScreenSize(columns, rows, true); | |
560 } | |
669 } | 561 } |
670 | 562 |
671 if (transport != null) | 563 if (transport != null) |
672 transport.setDimensions(columns, rows, width, height); | 564 transport.setDimensions(columns, rows, width, height); |
673 } | 565 } |
674 catch (Exception e) { | 566 catch (Exception e) { |
675 Log.e(TAG, "Problem while trying to resize screen or PTY", e); | 567 Log.e(TAG, "Problem while trying to resize screen or PTY", e); |
676 } | 568 } |
677 | 569 |
678 // redraw local output if we don't have a sesson to receive our resize request | 570 // redraw local output if we don't have a session to receive our resize request |
679 if (transport == null) { | 571 if (transport == null) { |
680 synchronized (localOutput) { | 572 synchronized (localOutput) { |
681 buffer.reset(); | 573 buffer.reset(); |
682 | 574 |
683 for (String line : localOutput) | 575 for (String line : localOutput) |
1244 buffer.keyPressed(vt320.KEY_RIGHT, ' ', 0); | 1136 buffer.keyPressed(vt320.KEY_RIGHT, ' ', 0); |
1245 else if (result.equals("↑")) | 1137 else if (result.equals("↑")) |
1246 buffer.keyPressed(vt320.KEY_UP, ' ', 0); | 1138 buffer.keyPressed(vt320.KEY_UP, ' ', 0); |
1247 else if (result.equals("↓")) | 1139 else if (result.equals("↓")) |
1248 buffer.keyPressed(vt320.KEY_DOWN, ' ', 0); | 1140 buffer.keyPressed(vt320.KEY_DOWN, ' ', 0); |
1141 else if (result.equals("T")) | |
1142 buffer.keyPressed(vt320.KEY_TAB, ' ', 0); | |
1249 else if (result.equals("I")) | 1143 else if (result.equals("I")) |
1250 buffer.keyPressed(vt320.KEY_INSERT, ' ', 0); | 1144 buffer.keyPressed(vt320.KEY_INSERT, ' ', 0); |
1251 else if (result.equals("D")) | 1145 else if (result.equals("D")) |
1252 buffer.keyPressed(vt320.KEY_DELETE, ' ', 0); | 1146 buffer.keyPressed(vt320.KEY_DELETE, ' ', 0); |
1253 else if (result.equals("E")) | 1147 else if (result.equals("E")) |
1254 buffer.keyTyped(vt320.KEY_ENTER, ' ', 0); | 1148 buffer.keyPressed(vt320.KEY_ENTER, ' ', 0); |
1255 else if (result.equals("T")) { | |
1256 try { | |
1257 transport.write(0x09); | |
1258 } | |
1259 catch (IOException e) { | |
1260 Log.e(TAG, "Problem with the arrowsDialog", e); | |
1261 } | |
1262 } | |
1263 } | 1149 } |
1264 @Override | 1150 @Override |
1265 public void onItemClick(AdapterView p, View v, int pos, long id) { | 1151 public void onItemClick(AdapterView p, View v, int pos, long id) { |
1266 final String result = String.valueOf(pickerString.charAt(pos)); | 1152 final String result = String.valueOf(pickerString.charAt(pos)); |
1267 buttonPressed(result); | 1153 buttonPressed(result); |
1398 else if (result.equals("9")) | 1284 else if (result.equals("9")) |
1399 key = vt320.KEY_F9; | 1285 key = vt320.KEY_F9; |
1400 else if (result.equals("0")) | 1286 else if (result.equals("0")) |
1401 key = vt320.KEY_F10; | 1287 key = vt320.KEY_F10; |
1402 | 1288 |
1403 if (key != 0) | 1289 if (key != 0) buffer.keyPressed(key, ' ', 0); |
1404 buffer.keyPressed(key, ' ', 0); | |
1405 | 1290 |
1406 dismiss(); | 1291 dismiss(); |
1407 } | 1292 } |
1408 @Override | 1293 @Override |
1409 public void onItemClick(AdapterView p, View v, int pos, long id) { | 1294 public void onItemClick(AdapterView p, View v, int pos, long id) { |
1494 if (keyListener.isSymKey(keyCode) || | 1379 if (keyListener.isSymKey(keyCode) || |
1495 keyCode == KeyEvent.KEYCODE_BACK) { | 1380 keyCode == KeyEvent.KEYCODE_BACK) { |
1496 dismiss(); | 1381 dismiss(); |
1497 return true; | 1382 return true; |
1498 } | 1383 } |
1499 | 1384 } |
1500 // return keyListener.onKey(parent, event.getKeyCode(), event); | |
1501 } | |
1502 | |
1503 return super.dispatchKeyEvent(event); | 1385 return super.dispatchKeyEvent(event); |
1504 } | 1386 } |
1505 }; | 1387 }; |
1506 cpd.show(); | 1388 cpd.show(); |
1507 return true; | 1389 return true; |