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;