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