0
|
1 /*
|
|
2 * ConnectBot: simple, powerful, open-source SSH client for Android
|
|
3 * Copyright 2007 Kenny Root, Jeffrey Sharkey
|
|
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.service;
|
|
19
|
|
20 import java.io.IOException;
|
|
21 import java.nio.ByteBuffer;
|
|
22 import java.nio.CharBuffer;
|
|
23 import java.nio.charset.Charset;
|
|
24 import java.nio.charset.CharsetDecoder;
|
|
25 import java.nio.charset.CoderResult;
|
|
26 import java.nio.charset.CodingErrorAction;
|
227
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
27 import java.util.Timer;
|
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
28 import java.util.TimerTask;
|
0
|
29
|
|
30 import org.apache.harmony.niochar.charset.additional.IBM437;
|
|
31
|
|
32 import com.five_ten_sg.connectbot.transport.AbsTransport;
|
|
33 import android.graphics.Paint;
|
|
34 import android.text.AndroidCharacter;
|
|
35 import android.util.Log;
|
|
36 import de.mud.terminal.vt320;
|
|
37
|
|
38 /**
|
|
39 * @author Kenny Root
|
|
40 */
|
|
41 public class Relay implements Runnable {
|
|
42 private static final String TAG = "ConnectBot.Relay";
|
|
43
|
|
44 private static final int BUFFER_SIZE = 4096;
|
|
45
|
|
46 private TerminalBridge bridge;
|
|
47
|
|
48 private Charset currentCharset;
|
|
49 private CharsetDecoder decoder;
|
|
50
|
|
51 private AbsTransport transport;
|
|
52
|
|
53 private vt320 buffer;
|
|
54
|
|
55 private ByteBuffer byteBuffer;
|
|
56 private CharBuffer charBuffer;
|
|
57
|
|
58 private byte[] byteArray;
|
|
59 private char[] charArray;
|
|
60
|
|
61 private void eastAsianWidthMeasure(char[] charArray, int start, int end,
|
|
62 byte[] wideAttribute, Paint paint, int charWidth) {
|
|
63 AndroidCharacter.getEastAsianWidths(charArray, start, end - start, wideAttribute);
|
|
64 }
|
|
65
|
|
66 public Relay(TerminalBridge bridge, AbsTransport transport, vt320 buffer, String encoding) {
|
|
67 setCharset(encoding);
|
|
68 this.bridge = bridge;
|
|
69 this.transport = transport;
|
|
70 this.buffer = buffer;
|
|
71 }
|
|
72
|
|
73 public void setCharset(String encoding) {
|
|
74 Log.d("ConnectBot.Relay", "changing charset to " + encoding);
|
|
75 Charset charset;
|
|
76
|
|
77 if (encoding.equals("CP437"))
|
|
78 charset = new IBM437("IBM437",
|
|
79 new String[] { "IBM437", "CP437" });
|
|
80 else
|
|
81 charset = Charset.forName(encoding);
|
|
82
|
|
83 if (charset == currentCharset || charset == null)
|
|
84 return;
|
|
85
|
|
86 CharsetDecoder newCd = charset.newDecoder();
|
|
87 newCd.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
|
88 newCd.onMalformedInput(CodingErrorAction.REPLACE);
|
|
89 currentCharset = charset;
|
|
90
|
|
91 synchronized (this) {
|
|
92 decoder = newCd;
|
|
93 }
|
|
94 }
|
|
95
|
|
96 public Charset getCharset() {
|
|
97 return currentCharset;
|
|
98 }
|
|
99
|
|
100 public void run() {
|
|
101 byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
|
|
102 charBuffer = CharBuffer.allocate(BUFFER_SIZE);
|
|
103 /* for East Asian character widths */
|
|
104 byte[] wideAttribute = new byte[BUFFER_SIZE];
|
|
105 byteArray = byteBuffer.array();
|
|
106 charArray = charBuffer.array();
|
|
107 CoderResult result;
|
|
108 int bytesRead = 0;
|
|
109 byteBuffer.limit(0);
|
|
110 int bytesToRead;
|
|
111 int offset;
|
|
112 int charWidth;
|
227
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
113 Timer timer = new Timer("relay.blocker", true);
|
234
|
114 TimerTask task = null;
|
0
|
115
|
|
116 try {
|
|
117 while (true) {
|
|
118 charWidth = bridge.charWidth;
|
|
119 bytesToRead = byteBuffer.capacity() - byteBuffer.limit();
|
|
120 offset = byteBuffer.arrayOffset() + byteBuffer.limit();
|
112
|
121
|
227
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
122 if (transport.willBlock()) {
|
234
|
123 task = new TimerTask() {
|
|
124 public void run() {
|
|
125 buffer.testChanged();
|
|
126 }
|
|
127 };
|
227
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
128 timer.schedule(task, 10); // 10 ms delay
|
228
|
129 }
|
112
|
130
|
0
|
131 bytesRead = transport.read(byteArray, offset, bytesToRead);
|
234
|
132
|
|
133 if (task != null) {
|
|
134 task.cancel();
|
|
135 task = null;
|
|
136 }
|
227
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
137
|
0
|
138 if (bytesRead > 0) {
|
|
139 byteBuffer.limit(byteBuffer.limit() + bytesRead);
|
|
140
|
|
141 synchronized (this) {
|
|
142 result = decoder.decode(byteBuffer, charBuffer, false);
|
|
143 }
|
|
144
|
|
145 if (result.isUnderflow() &&
|
|
146 byteBuffer.limit() == byteBuffer.capacity()) {
|
|
147 byteBuffer.compact();
|
|
148 byteBuffer.limit(byteBuffer.position());
|
|
149 byteBuffer.position(0);
|
|
150 }
|
|
151
|
|
152 offset = charBuffer.position();
|
|
153 eastAsianWidthMeasure(charArray, 0, offset, wideAttribute, bridge.defaultPaint, charWidth);
|
|
154 buffer.putString(charArray, wideAttribute, 0, charBuffer.position());
|
|
155 bridge.propagateConsoleText(charArray, charBuffer.position());
|
|
156 charBuffer.clear();
|
|
157 bridge.redraw();
|
|
158 }
|
|
159 }
|
|
160 }
|
|
161 catch (IOException e) {
|
|
162 Log.e(TAG, "Problem while handling incoming data in relay thread", e);
|
|
163 }
|
227
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
164
|
2dd627df4dfb
delay testChanged() by 10ms for async transports; sendScreen resets watch area to the entire screen
Carl Byington <carl@five-ten-sg.com>
diff
changeset
|
165 timer.cancel();
|
0
|
166 }
|
|
167 }
|