1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package davmail;
20
21 import davmail.exception.DavMailException;
22 import davmail.exchange.ExchangeSession;
23 import davmail.ui.tray.DavGatewayTray;
24 import org.apache.log4j.Logger;
25
26 import java.io.*;
27 import java.net.Socket;
28 import java.nio.charset.StandardCharsets;
29
30
31
32
33
34 public abstract class AbstractConnection extends Thread implements Closeable {
35
36 protected enum State {
37 INITIAL, LOGIN, USER, PASSWORD, AUTHENTICATED, STARTMAIL, RECIPIENT, MAILDATA
38 }
39
40 protected static class LineReaderInputStream extends PushbackInputStream {
41 final String encoding;
42
43 protected LineReaderInputStream(InputStream in, String encoding) {
44 super(in);
45 if (encoding == null) {
46 this.encoding = "ASCII";
47 } else {
48 this.encoding = encoding;
49 }
50 }
51
52 public String readLine() throws IOException {
53 ByteArrayOutputStream baos = null;
54 int b;
55 while ((b = read()) > -1) {
56 if (b == '\r') {
57 int next = read();
58 if (next != '\n') {
59 unread(next);
60 }
61 break;
62 } else if (b == '\n') {
63 break;
64 }
65 if (baos == null) {
66 baos = new ByteArrayOutputStream();
67 }
68 baos.write(b);
69 }
70 if (baos != null) {
71 return baos.toString(encoding);
72 } else {
73 return null;
74 }
75 }
76
77
78
79
80
81
82
83
84 public String readContentAsString(int byteSize) throws IOException {
85 return new String(readContent(byteSize), encoding);
86 }
87
88
89
90
91
92
93
94
95 public byte[] readContent(int byteSize) throws IOException {
96 byte[] buffer = new byte[byteSize];
97 int startIndex = 0;
98 int count = 0;
99 while (count >= 0 && startIndex < byteSize) {
100 count = read(buffer, startIndex, byteSize - startIndex);
101 startIndex += count;
102 }
103 if (startIndex < byteSize) {
104 throw new DavMailException("EXCEPTION_END_OF_STREAM");
105 }
106
107 return buffer;
108 }
109 }
110
111 protected final Socket client;
112
113 protected LineReaderInputStream in;
114 protected OutputStream os;
115
116 protected String userName;
117 protected String password;
118
119 protected State state = State.INITIAL;
120
121 protected ExchangeSession session;
122
123
124
125
126
127
128
129 public AbstractConnection(String name, Socket clientSocket) {
130 super(name + '-' + clientSocket.getPort());
131 this.client = clientSocket;
132 setDaemon(true);
133 }
134
135
136
137
138
139
140
141
142 public AbstractConnection(String name, Socket clientSocket, String encoding) {
143 super(name + '-' + clientSocket.getPort());
144 this.client = clientSocket;
145 logConnection("CONNECT", "");
146 try {
147 in = new LineReaderInputStream(client.getInputStream(), encoding);
148 os = new BufferedOutputStream(client.getOutputStream());
149 } catch (IOException e) {
150 close();
151 DavGatewayTray.error(new BundleMessage("LOG_EXCEPTION_GETTING_SOCKET_STREAMS"), e);
152 }
153 }
154
155 public void logConnection(String action, String userName) {
156 Logger.getLogger("davmail.connection").info(action+" - "+client.getInetAddress().getHostAddress()+":"+client.getPort()+" " + userName);
157 }
158
159
160
161
162
163
164
165 public void sendClient(String message) throws IOException {
166 sendClient(null, message);
167 }
168
169
170
171
172
173
174
175
176 public void sendClient(String prefix, String message) throws IOException {
177 if (prefix != null) {
178 os.write(prefix.getBytes(StandardCharsets.UTF_8));
179 DavGatewayTray.debug(new BundleMessage("LOG_SEND_CLIENT_PREFIX_MESSAGE", prefix, message));
180 } else {
181 DavGatewayTray.debug(new BundleMessage("LOG_SEND_CLIENT_MESSAGE", message));
182 }
183 os.write(message.getBytes(StandardCharsets.UTF_8));
184 os.write((char) 13);
185 os.write((char) 10);
186 os.flush();
187 }
188
189
190
191
192
193
194
195 public void sendClient(byte[] messageBytes) throws IOException {
196 sendClient(messageBytes, 0, messageBytes.length);
197 }
198
199
200
201
202
203
204
205
206
207 public void sendClient(byte[] messageBytes, int offset, int length) throws IOException {
208
209
210
211 os.write(messageBytes, offset, length);
212 os.flush();
213 }
214
215
216
217
218
219
220
221
222 public String readClient() throws IOException {
223 String line = in.readLine();
224 if (line != null) {
225 if (line.startsWith("PASS")) {
226 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_PASS"));
227
228 } else if (line.startsWith("AUTH LOGIN ")) {
229 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTH_LOGIN"));
230
231 } else if (state == State.INITIAL && line.indexOf(' ') >= 0 &&
232 line.substring(line.indexOf(' ') + 1).toUpperCase().startsWith("LOGIN")) {
233 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_LOGIN"));
234 } else if (state == State.PASSWORD) {
235 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_PASSWORD"));
236
237 } else if (line.startsWith("Authorization:")) {
238 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTHORIZATION"));
239 } else if (line.startsWith("AUTH PLAIN")) {
240 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTH_PLAIN"));
241 } else {
242 DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_LINE", line));
243 }
244 }
245 DavGatewayTray.switchIcon();
246 return line;
247 }
248
249
250
251
252 public void close() {
253 logConnection("DISCONNECT", "");
254 if (in != null) {
255 try {
256 in.close();
257 } catch (IOException e2) {
258
259 }
260 }
261 if (os != null) {
262 try {
263 os.close();
264 } catch (IOException e2) {
265
266 }
267 }
268 try {
269 client.close();
270 } catch (IOException e2) {
271 DavGatewayTray.debug(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_SOCKET"), e2);
272 }
273 }
274 }