001 package org.crsh.term.spi.net;
002
003 import org.crsh.term.CodeType;
004 import org.crsh.term.spi.TermIO;
005 import org.crsh.util.AbstractSocketServer;
006 import org.crsh.util.Safe;
007
008 import java.io.IOException;
009 import java.io.InputStream;
010 import java.io.OutputStream;
011 import java.net.InetSocketAddress;
012 import java.net.ServerSocket;
013 import java.net.Socket;
014 import java.nio.charset.Charset;
015
016 /**
017 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
018 */
019 public class TermIOServer extends AbstractSocketServer {
020
021 /** . */
022 private static final Charset UTF_8 = Charset.forName("UTF-8");
023
024 /** . */
025 private final TermIO delegate;
026
027 /** . */
028 private InputStream in;
029
030 /** . */
031 private OutputStream out;
032
033 public TermIOServer(TermIO delegate, int bindingPort) {
034 super(bindingPort);
035
036 //
037 this.delegate = delegate;
038 }
039
040 @Override
041 protected void handle(InputStream in, OutputStream out) throws IOException {
042 this.in = in;
043 this.out = out;
044 }
045
046 private byte read() throws IOException, Done {
047 int b = in.read();
048 if (b == -1) {
049 throw new Done();
050 }
051 return (byte)b;
052 }
053
054 private int read(byte[] buffer, int off, int len) throws IOException, Done {
055 int b = in.read(buffer, off, len);
056 if (b == -1) {
057 throw new Done();
058 }
059 return b;
060 }
061
062 private void write(byte b) throws IOException, Done {
063 out.write(b);
064 }
065
066 private void write(byte[] bytes) throws IOException, Done {
067 out.write(bytes);
068 }
069
070 private void flush() throws IOException, Done {
071 out.flush();
072 }
073
074 public boolean execute() throws IOException, IllegalStateException {
075 if (in == null) {
076 throw new IllegalStateException("No connection");
077 }
078 try {
079 iterate();
080 return true;
081 } catch (Done ignore) {
082 in = null;
083 out = null;
084 close();
085 return false;
086 }
087 }
088
089 private void iterate() throws IOException, Done {
090 byte b = read();
091 if (b == 0) {
092 int code = delegate.read();
093 CodeType codeType = delegate.decode(code);
094 byte ordinal = (byte) codeType.ordinal();
095 if (codeType == CodeType.CHAR) {
096 write(new byte[]{ordinal, (byte)((code & 0xFF00) >> 8), (byte)((code & 0xFF))});
097 } else {
098 write(ordinal);
099 }
100 flush();
101 } else if (b == 1) {
102 int b1 = in.read();
103 int b2 = in.read();
104 char c = (char)((b1 << 8) + b2);
105 delegate.write(c);
106 } else if (b == 2) {
107 b = read();
108 int remaining = (b + 2) * 2;
109 int offset = 0;
110 byte[] buffer = new byte[remaining];
111 while (remaining > 0) {
112 int r = read(buffer, offset, remaining);
113 offset += r;
114 remaining -= r;
115 }
116 char[] chars = new char[buffer.length / 2];
117 int index = 0;
118 for (int i = 0;i < chars.length;i++) {
119 int high = buffer[index++];
120 int low = buffer[index++];
121 chars[i] = (char)((high << 8) + low);
122 }
123 String s = new String(chars);
124 delegate.write(s);
125 } else if (b == 3) {
126 delegate.writeDel();
127 } else if (b == 4) {
128 delegate.writeCRLF();
129 } else if (b == 5) {
130 int b1 = in.read();
131 int b2 = in.read();
132 char c = (char)((b1 << 8) + b2);
133 delegate.moveRight(c);
134 } else if (b == 6) {
135 delegate.moveLeft();
136 } else if (b == 7) {
137 delegate.flush();
138 } else if (b == 8) {
139 int len = read() + 1;
140 byte[] bytes = new byte[len];
141 read(bytes, 0, len);
142 String propertyName = new String(bytes, UTF_8);
143 String propertyValue;
144 if ("width".equals(propertyName)) {
145 propertyValue = Integer.toString(delegate.getWidth());
146 } else {
147 propertyValue = delegate.getProperty(propertyName);
148 }
149 if (propertyValue == null) {
150 write((byte)0);
151 } else if (propertyValue.length() == 0) {
152 write((byte)1);
153 } else {
154 bytes = propertyValue.getBytes(UTF_8);
155 len = bytes.length;
156 if (len > 254) {
157 // We don't process that for now
158 // so we say it's null
159 write((byte)0);
160 } else {
161 write((byte)(len + 1));
162 write(bytes);
163 }
164 flush();
165 }
166 } else {
167 throw new UnsupportedOperationException("cannot handle " + b);
168 }
169 }
170 }