Mercurial > 510Connectbot
comparison src/com/five_ten_sg/connectbot/transport/TN5250.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 | 7ae9b0c382ec |
children | 8f23b05a51f7 |
comparison
equal
deleted
inserted
replaced
19:b3d0d806cbe2 | 79:01d939969b10 |
---|---|
1 /* | |
2 * 510ConnectBot | |
3 * Copyright 2014 Carl Byington | |
4 * | |
5 * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 * you may not use this file except in compliance with the License. | |
7 * You may obtain a copy of the License at | |
8 * | |
9 * http://www.apache.org/licenses/LICENSE-2.0 | |
10 * | |
11 * Unless required by applicable law or agreed to in writing, software | |
12 * distributed under the License is distributed on an "AS IS" BASIS, | |
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 * See the License for the specific language governing permissions and | |
15 * limitations under the License. | |
16 */ | |
17 | |
18 package com.five_ten_sg.connectbot.transport; | |
19 | |
20 import java.io.IOException; | |
21 import java.io.InputStream; | |
22 import java.io.OutputStream; | |
23 import java.net.Socket; | |
24 import java.net.SocketException; | |
25 import java.net.UnknownHostException; | |
26 import java.util.HashMap; | |
27 import java.util.List; | |
28 import java.util.Map; | |
29 import java.util.regex.Matcher; | |
30 import java.util.regex.Pattern; | |
31 | |
32 import org.tn5250j.framework.tn5250.Screen5250; | |
33 import org.tn5250j.framework.tn5250.tnvt; | |
34 | |
35 import com.five_ten_sg.connectbot.R; | |
36 import com.five_ten_sg.connectbot.bean.HostBean; | |
37 import com.five_ten_sg.connectbot.bean.PortForwardBean; | |
38 import com.five_ten_sg.connectbot.service.TerminalBridge; | |
39 import com.five_ten_sg.connectbot.service.TerminalKeyListener; | |
40 import com.five_ten_sg.connectbot.service.TerminalManager; | |
41 import com.five_ten_sg.connectbot.util.HostDatabase; | |
42 import com.five_ten_sg.connectbot.util.PreferenceConstants; | |
43 import android.content.Context; | |
44 import android.net.Uri; | |
45 import android.util.Log; | |
46 import android.view.KeyCharacterMap; | |
47 import android.view.KeyEvent; | |
48 import android.view.View; | |
49 import de.mud.terminal.vt320; | |
50 | |
51 | |
52 /** | |
53 * @author Carl Byington | |
54 * | |
55 */ | |
56 public class TN5250 extends AbsTransport { | |
57 private static final String PROTOCOL = "tn5250"; | |
58 private static final String TAG = "ConnectBot.tn5250"; | |
59 private static final int DEFAULT_PORT = 23; | |
60 | |
61 private Screen5250 screen52; | |
62 private tnvt handler = null; | |
63 private Socket socket; | |
64 private boolean connected = false; | |
65 | |
66 static final Pattern hostmask; | |
67 static { | |
68 hostmask = Pattern.compile("^([0-9a-z.-]+)(:(\\d+))?$", Pattern.CASE_INSENSITIVE); | |
69 } | |
70 | |
71 | |
72 class vt320x5250 extends vt320 { | |
73 private HashMap<Integer, String> mnemonics; | |
74 | |
75 public vt320x5250() { | |
76 this(80,24); | |
77 } | |
78 | |
79 public vt320x5250(int width, int height) { | |
80 super(width, height); | |
81 mnemonics = new HashMap<Integer, String>(); | |
82 mnemonics.put(KEY_PAUSE , "[attn]"); | |
83 mnemonics.put(KEY_F1 , "[pf1]"); | |
84 mnemonics.put(KEY_F2 , "[pf2]"); | |
85 mnemonics.put(KEY_F3 , "[pf3]"); | |
86 mnemonics.put(KEY_F4 , "[pf4]"); | |
87 mnemonics.put(KEY_F5 , "[pf5]"); | |
88 mnemonics.put(KEY_F6 , "[pf6]"); | |
89 mnemonics.put(KEY_F7 , "[pf7]"); | |
90 mnemonics.put(KEY_F8 , "[pf8]"); | |
91 mnemonics.put(KEY_F9 , "[pf9]"); | |
92 mnemonics.put(KEY_F10 , "[pf10]"); | |
93 mnemonics.put(KEY_F11 , "[pf11]"); | |
94 mnemonics.put(KEY_F12 , "[pf12]"); | |
95 mnemonics.put(KEY_UP , "[up]"); | |
96 mnemonics.put(KEY_DOWN , "[down]"); | |
97 mnemonics.put(KEY_LEFT , "[left]"); | |
98 mnemonics.put(KEY_RIGHT , "[right]"); | |
99 mnemonics.put(KEY_PAGE_DOWN , "[pgdown]"); | |
100 mnemonics.put(KEY_PAGE_UP , "[pgup]"); | |
101 mnemonics.put(KEY_INSERT , "[insert]"); | |
102 mnemonics.put(KEY_DELETE , "[delete]"); | |
103 mnemonics.put(KEY_BACK_SPACE , "[backspace]"); | |
104 mnemonics.put(KEY_HOME , "[home]"); | |
105 mnemonics.put(KEY_END , "[end]"); | |
106 mnemonics.put(KEY_NUM_LOCK , ""); | |
107 mnemonics.put(KEY_CAPS_LOCK , ""); | |
108 mnemonics.put(KEY_SHIFT , ""); | |
109 mnemonics.put(KEY_CONTROL , ""); | |
110 mnemonics.put(KEY_ALT , ""); | |
111 mnemonics.put(KEY_ENTER , "[enter]"); | |
112 mnemonics.put(KEY_NUMPAD0 , "0"); | |
113 mnemonics.put(KEY_NUMPAD1 , "1"); | |
114 mnemonics.put(KEY_NUMPAD2 , "2"); | |
115 mnemonics.put(KEY_NUMPAD3 , "3"); | |
116 mnemonics.put(KEY_NUMPAD4 , "4"); | |
117 mnemonics.put(KEY_NUMPAD5 , "5"); | |
118 mnemonics.put(KEY_NUMPAD6 , "6"); | |
119 mnemonics.put(KEY_NUMPAD7 , "7"); | |
120 mnemonics.put(KEY_NUMPAD8 , "8"); | |
121 mnemonics.put(KEY_NUMPAD9 , "9"); | |
122 mnemonics.put(KEY_DECIMAL , "."); | |
123 mnemonics.put(KEY_ADD , "+"); | |
124 mnemonics.put(KEY_ESCAPE , ""); | |
125 mnemonics.put(KEY_TAB , "[tab]"); | |
126 } | |
127 | |
128 @Override | |
129 public void debug(String s) { | |
130 Log.d(TAG, s); | |
131 } | |
132 | |
133 // monitor injecting a field | |
134 @Override | |
135 public void setField(int l, int c, char [] d) { | |
136 screen52.setField(l, c, d); | |
137 } | |
138 | |
139 // terminal key listener sending to local screen | |
140 @Override | |
141 public void write(byte[] b) { | |
142 if (bridge.monitor != null) bridge.monitor.hostData(b); | |
143 screen52.sendKeys(new String(b)); | |
144 } | |
145 @Override | |
146 public void write(int b) { | |
147 if (bridge.monitor != null) bridge.monitor.hostData(b); | |
148 screen52.sendKeys(new String(new byte[] {(byte)b})); | |
149 } | |
150 @Override | |
151 public void keyPressed(int keyCode, char keyChar, int modifiers) { | |
152 if (mnemonics.containsKey(keyCode)) { | |
153 String s = mnemonics.get(keyCode); | |
154 if (s != "") { | |
155 if (bridge.monitor != null) bridge.monitor.hostData(s.getBytes()); | |
156 screen52.sendKeys(s); | |
157 } | |
158 } | |
159 } | |
160 // 5250 writing to the screen | |
161 // test for changed screen contents | |
162 @Override | |
163 public void testChanged() { | |
164 if (bridge.monitor != null) bridge.monitor.testChanged(); | |
165 } | |
166 @Override | |
167 public void putChar(int c, int l, char ch, int attributes) { | |
168 if (bridge.monitor != null) bridge.monitor.screenChanged(l, c); | |
169 super.putChar(c, l, ch, attributes); | |
170 } | |
171 @Override | |
172 public void setCursorPosition(int c, int l) { | |
173 if (bridge.monitor != null) bridge.monitor.cursorMove(l, c); | |
174 super.setCursorPosition(c, l); | |
175 } | |
176 }; | |
177 | |
178 | |
179 public TN5250() { | |
180 super(); | |
181 } | |
182 | |
183 | |
184 /** | |
185 * @return protocol part of the URI | |
186 */ | |
187 public static String getProtocolName() { | |
188 return PROTOCOL; | |
189 } | |
190 | |
191 | |
192 /** | |
193 * Encode the current transport into a URI that can be passed via intent calls. | |
194 * @return URI to host | |
195 */ | |
196 public Uri getUri(String input) { | |
197 Matcher matcher = hostmask.matcher(input); | |
198 | |
199 if (!matcher.matches()) | |
200 return null; | |
201 | |
202 StringBuilder sb = new StringBuilder(); | |
203 sb.append(PROTOCOL) | |
204 .append("://") | |
205 .append(matcher.group(1)); | |
206 String portString = matcher.group(3); | |
207 int port = DEFAULT_PORT; | |
208 | |
209 if (portString != null) { | |
210 try { | |
211 port = Integer.parseInt(portString); | |
212 | |
213 if (port < 1 || port > 65535) { | |
214 port = DEFAULT_PORT; | |
215 } | |
216 } | |
217 catch (NumberFormatException nfe) { | |
218 // Keep the default port | |
219 } | |
220 } | |
221 | |
222 if (port != DEFAULT_PORT) { | |
223 sb.append(':'); | |
224 sb.append(port); | |
225 } | |
226 | |
227 sb.append("/#") | |
228 .append(Uri.encode(input)); | |
229 Uri uri = Uri.parse(sb.toString()); | |
230 return uri; | |
231 } | |
232 | |
233 | |
234 /** | |
235 * Causes transport to connect to the target host. After connecting but before a | |
236 * session is started, must call back to {@link TerminalBridge#onConnected()}. | |
237 * After that call a session may be opened. | |
238 */ | |
239 @Override | |
240 public void connect() { | |
241 screen52 = new Screen5250(); | |
242 handler = new tnvt(screen52, true, false, bridge, manager); | |
243 String encryption = host.getEncryption5250(); | |
244 if ((encryption == null) || (encryption.length() == 0)) encryption = "NONE"; | |
245 handler.setSSLType(encryption); | |
246 screen52.setVT(handler); | |
247 screen52.setBuffer(buffer); | |
248 connected = handler.connect(host.getHostname(), host.getPort(), buffer); | |
249 if (connected) bridge.onConnected(); | |
250 } | |
251 | |
252 | |
253 /** | |
254 * Checks if read() will block. If there are no bytes remaining in | |
255 * the underlying transport, return true. | |
256 */ | |
257 @Override | |
258 public boolean willBlock() { | |
259 // we don't use a relay thread between the transport and the vt320 buffer | |
260 return true; | |
261 } | |
262 | |
263 | |
264 /** | |
265 * Reads from the transport. Transport must support reading into a byte array | |
266 * <code>buffer</code> at the start of <code>offset</code> and a maximum of | |
267 * <code>length</code> bytes. If the remote host disconnects, throw an | |
268 * {@link IOException}. | |
269 * @param buffer byte buffer to store read bytes into | |
270 * @param offset where to start writing in the buffer | |
271 * @param length maximum number of bytes to read | |
272 * @return number of bytes read | |
273 * @throws IOException when remote host disconnects | |
274 */ | |
275 public int read(byte[] buffer, int offset, int length) throws IOException { | |
276 // we don't use a relay thread between the transport and the vt320 buffer | |
277 return 0; | |
278 } | |
279 | |
280 | |
281 /** | |
282 * Writes to the transport. If the host is not yet connected, simply return without | |
283 * doing anything. An {@link IOException} should be thrown if there is an error after | |
284 * connection. | |
285 * @param buffer bytes to write to transport | |
286 * @throws IOException when there is a problem writing after connection | |
287 */ | |
288 public void write(byte[] buffer) throws IOException { | |
289 } | |
290 | |
291 | |
292 /** | |
293 * Writes to the transport. See {@link #write(byte[])} for behavior details. | |
294 * @param c character to write to the transport | |
295 * @throws IOException when there is a problem writing after connection | |
296 */ | |
297 public void write(int c) throws IOException { | |
298 } | |
299 | |
300 | |
301 /** | |
302 * Flushes the write commands to the transport. | |
303 * @throws IOException when there is a problem writing after connection | |
304 */ | |
305 public void flush() throws IOException { | |
306 } | |
307 | |
308 | |
309 /** | |
310 * Closes the connection to the terminal. | |
311 */ | |
312 public void close() { | |
313 handler.disconnect(); | |
314 connected = false; | |
315 bridge.dispatchDisconnect(false); | |
316 } | |
317 | |
318 | |
319 /** | |
320 * Tells the transport what dimensions the display is currently | |
321 * @param columns columns of text | |
322 * @param rows rows of text | |
323 * @param width width in pixels | |
324 * @param height height in pixels | |
325 */ | |
326 @Override | |
327 public void setDimensions(int columns, int rows, int width, int height) { | |
328 // do nothing | |
329 } | |
330 | |
331 | |
332 @Override | |
333 public vt320 getTransportBuffer() { | |
334 buffer = new vt320x5250(); | |
335 return setupTransportBuffer(); | |
336 } | |
337 | |
338 | |
339 @Override | |
340 public int getDefaultPort() { | |
341 return DEFAULT_PORT; | |
342 } | |
343 | |
344 | |
345 @Override | |
346 public boolean isConnected() { | |
347 return connected; | |
348 } | |
349 | |
350 | |
351 @Override | |
352 public boolean isSessionOpen() { | |
353 return connected; | |
354 } | |
355 | |
356 | |
357 @Override | |
358 public boolean isAuthenticated() { | |
359 return connected; | |
360 } | |
361 | |
362 | |
363 @Override | |
364 public String getDefaultNickname(String username, String hostname, int port) { | |
365 if (port == DEFAULT_PORT) { | |
366 return String.format("%s", hostname); | |
367 } | |
368 else { | |
369 return String.format("%s:%d", hostname, port); | |
370 } | |
371 } | |
372 | |
373 | |
374 @Override | |
375 public void getSelectionArgs(Uri uri, Map<String, String> selection) { | |
376 selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); | |
377 selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); | |
378 selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); | |
379 int port = uri.getPort(); | |
380 | |
381 if (port < 0) | |
382 port = DEFAULT_PORT; | |
383 | |
384 selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); | |
385 } | |
386 | |
387 | |
388 @Override | |
389 public HostBean createHost(Uri uri) { | |
390 HostBean host = new HostBean(); | |
391 host.setProtocol(PROTOCOL); | |
392 host.setHostname(uri.getHost()); | |
393 int port = uri.getPort(); | |
394 | |
395 if (port < 0) | |
396 port = DEFAULT_PORT; | |
397 | |
398 host.setPort(port); | |
399 String nickname = uri.getFragment(); | |
400 | |
401 if (nickname == null || nickname.length() == 0) { | |
402 host.setNickname(getDefaultNickname(host.getUsername(), | |
403 host.getHostname(), host.getPort())); | |
404 } | |
405 else { | |
406 host.setNickname(uri.getFragment()); | |
407 } | |
408 | |
409 return host; | |
410 } | |
411 | |
412 | |
413 public String getFormatHint(Context context) { | |
414 return String.format("%s:%s", | |
415 context.getString(R.string.format_hostname), | |
416 context.getString(R.string.format_port)); | |
417 } | |
418 | |
419 | |
420 @Override | |
421 public boolean usesNetwork() { | |
422 return true; | |
423 } | |
424 | |
425 | |
426 @Override | |
427 public boolean needsRelay() { | |
428 // we don't use a relay thread between the transport and the vt320 buffer | |
429 return false; | |
430 } | |
431 | |
432 public TerminalKeyListener getTerminalKeyListener() { | |
433 return new TerminalKeyListener(manager, bridge, buffer, host.getEncoding()); | |
434 } | |
435 | |
436 } |