1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.mercury.imap;
14
15 import java.io.BufferedInputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.io.PrintStream;
20 import java.io.Reader;
21 import java.io.Writer;
22 import java.net.Socket;
23 import java.util.Properties;
24
25 import javax.mail.Folder;
26 import javax.mail.MessagingException;
27 import javax.mail.Session;
28 import javax.mail.Store;
29 import javax.mail.event.MessageCountEvent;
30 import javax.mail.event.MessageCountListener;
31 import javax.net.ssl.SSLSocket;
32 import javax.net.ssl.SSLSocketFactory;
33 import javax.security.auth.login.LoginContext;
34 import javax.security.auth.login.LoginException;
35
36 import org.abstracthorizon.danube.connection.Connection;
37 import org.abstracthorizon.danube.connection.ConnectionWrapper;
38 import org.abstracthorizon.danube.support.logging.LoggingConnection;
39 import org.abstracthorizon.mercury.common.util.SSLUtil;
40 import org.abstracthorizon.mercury.imap.response.ExistsResponse;
41 import org.abstracthorizon.mercury.imap.response.RecentResponse;
42 import org.abstracthorizon.mercury.imap.util.IMAPScanner;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46
47
48
49
50
51
52 public class IMAPSession extends ConnectionWrapper implements MessageCountListener {
53
54
55 protected static final Logger logger = LoggerFactory.getLogger(IMAPSession.class);
56
57
58 protected IMAPConnectionHandler parent;
59
60
61 protected String tag;
62
63
64 protected String commandLine;
65
66
67 protected boolean authorised = false;
68
69
70 protected Writer writer;
71
72
73 protected Reader reader;
74
75
76 protected IMAPScanner scanner;
77
78
79 protected Store store;
80
81
82 protected Folder selectedFolder = null;
83
84
85 protected Session session;
86
87
88 protected LoginContext lc;
89
90
91 protected boolean secure = false;
92
93
94 protected boolean idling = false;
95
96
97
98
99
100 protected boolean cleanInput = false;
101
102
103 protected Socket socket;
104
105
106 protected long commandStarted;
107
108
109 protected String defaultDomain;
110
111
112
113
114
115
116 public IMAPSession(Connection connection, IMAPConnectionHandler parent) {
117 super(connection);
118 this.parent = parent;
119 InputStream inputStream = (InputStream)connection.adapt(InputStream.class);
120 OutputStream outputStream = (OutputStream)connection.adapt(OutputStream.class);
121 BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
122 scanner = new IMAPScanner(bufferedInputStream, outputStream);
123
124 Properties props = new Properties();
125
126 props.setProperty("mail.mime.address.strict", "false");
127 session = Session.getInstance(props);
128 }
129
130
131
132
133
134 public IMAPConnectionHandler getParent() {
135 return parent;
136 }
137
138
139
140
141
142 public void setKeepLog(boolean keepLog) {
143 LoggingConnection loggingConnection = (LoggingConnection)connection.adapt(LoggingConnection.class);
144 if (loggingConnection != null) {
145 loggingConnection.setTemporaryLog(!keepLog);
146 }
147 }
148
149
150
151
152
153 public boolean getKeepLog() {
154 LoggingConnection loggingConnection = (LoggingConnection)connection.adapt(LoggingConnection.class);
155 if (loggingConnection != null) {
156 return !loggingConnection.isTermporaryLog();
157 } else {
158 return false;
159 }
160 }
161
162
163
164
165
166 public void writeLogMessage(String msg) {
167 LoggingConnection loggingConnection = (LoggingConnection)connection.adapt(LoggingConnection.class);
168 if (loggingConnection != null) {
169 PrintStream out = new PrintStream(loggingConnection.getDebugOutputStream());
170 out.println(msg);
171 out.flush();
172 }
173 }
174
175
176
177
178
179 public OutputStream getDebugStream() {
180 LoggingConnection loggingConnection = (LoggingConnection)connection.adapt(LoggingConnection.class);
181 if (loggingConnection != null) {
182 return loggingConnection.getDebugOutputStream();
183 } else {
184 return null;
185 }
186 }
187
188
189
190
191
192 public boolean isAuthorised() {
193 return authorised;
194 }
195
196
197
198
199
200 public long getCommandLasted() {
201 return System.currentTimeMillis() - commandStarted;
202 }
203
204
205
206
207 public void markCommandStarted() {
208 commandStarted = System.currentTimeMillis();
209 }
210
211
212
213
214
215 public Store getStore() {
216 return store;
217 }
218
219
220
221
222
223 public Folder getSelectedFolder() {
224 return selectedFolder;
225 }
226
227
228
229
230
231 public void setSelectedFolder(Folder folder) {
232 if (folder != null) {
233 logger.debug("Already selected folder "+folder.getName());
234 folder.removeMessageCountListener(this);
235 }
236 selectedFolder = folder;
237 if (folder != null) {
238 selectedFolder.addMessageCountListener(this);
239 }
240 }
241
242
243
244
245
246 public IMAPScanner getScanner() {
247 return scanner;
248 }
249
250
251
252
253
254 public Session getJavaMailSession() {
255 return session;
256 }
257
258
259
260
261
262 public void setJavaMailSession(Session session) {
263 this.session = session;
264 }
265
266
267
268
269
270 public boolean isInsecureAllowed() {
271 return parent.isInsecureAllowed();
272 }
273
274
275
276
277
278 public boolean isSecure() {
279 Socket socket = (Socket)adapt(Socket.class);
280 if (socket != null) {
281 return socket instanceof SSLSocket;
282 } else {
283 return true;
284 }
285 }
286
287
288
289
290
291 public synchronized void setIdling(boolean idling) {
292 this.idling = idling;
293 }
294
295
296
297
298
299 public boolean isIdling() {
300 return idling;
301 }
302
303
304
305
306
307 public boolean isCleanInput() {
308 return cleanInput;
309 }
310
311
312
313
314
315 public void setCleanInput(boolean cleanInput) {
316 this.cleanInput = cleanInput;
317 }
318
319
320
321
322
323 public String getTag() {
324 return tag;
325 }
326
327
328
329
330
331 public void setTag(String tag) {
332 this.tag = tag;
333 }
334
335
336
337
338
339 public String getDefaultDomain() {
340 return defaultDomain;
341 }
342
343
344
345
346
347 public void setDefaultDomain(String domain) {
348 this.defaultDomain = domain;
349 }
350
351
352
353
354
355
356
357
358
359
360 public boolean authorise(String user, String pass) throws MessagingException {
361 String domain;
362 int i = user.indexOf('@');
363 if (i >= 1) {
364 domain = user.substring(i + 1);
365 user = user.substring(0, i);
366 } else if (defaultDomain != null) {
367 domain = defaultDomain;
368 } else {
369 domain = parent.getStorageManager().getMainDomain();
370 }
371
372
373 if (domain != null) {
374 logger.info("AUTHORISE: user " + user + " for domain " + domain);
375 } else {
376 logger.info("AUTHORISE: user " + user + " without domain");
377 }
378
379
380 try {
381 store = parent.getStorageManager().findStore(user, domain, pass.toCharArray());
382 authorised = true;
383 } catch (Exception e) {
384 logger.error("Failed to find a store", e);
385 }
386
387 return authorised;
388 }
389
390
391
392
393 public void unauthorise() {
394 authorised = false;
395 if (lc != null) {
396 try {
397 lc.logout();
398 } catch (LoginException ignore) {
399 }
400 }
401 }
402
403
404
405
406 public void close() {
407 if ((selectedFolder != null) && (selectedFolder.isOpen())) {
408 try {
409 selectedFolder.removeMessageCountListener(this);
410 if (selectedFolder.isOpen()) {
411 selectedFolder.close(false);
412 }
413 } catch (IllegalStateException ignore) {
414 } catch (MessagingException e1) {
415
416 logger.debug("Forced close on folder excetion ", e1);
417 }
418 }
419 super.close();
420 logger.debug("Finished session ");
421 }
422
423
424
425
426
427 public void switchToTLS() throws IOException {
428 char[] passPhrase = parent.getPassPhrase();
429 InputStream keyStoreInputStream = parent.getKeyStoreInputStream();
430 SSLSocketFactory factory = SSLUtil.getSocketFactory(passPhrase, keyStoreInputStream);
431 if (factory == null) {
432 throw new IOException("Cannot obtain SSLSocket Factory");
433 }
434
435
436 socket = factory.createSocket(socket, socket.getInetAddress().getHostName(), socket.getPort(), true);
437 ((SSLSocket)socket).setUseClientMode(false);
438 }
439
440
441
442
443
444 public synchronized void messagesAdded(MessageCountEvent event) {
445 if ((selectedFolder != null) && idling) {
446 parent.getThreadPool().execute(new Runnable(){
447 public void run() {
448 try {
449 new RecentResponse(IMAPSession.this, selectedFolder).submit();
450 new ExistsResponse(IMAPSession.this, selectedFolder).submit();
451 } catch (IOException ignore) {
452 } catch (MessagingException ignore) {
453 }
454 }
455 });
456 }
457 }
458
459
460
461
462
463 public void messagesRemoved(MessageCountEvent event) {
464 messagesAdded(event);
465 }
466 }