source: trunk/src/org/expeditee/agents/mail/MailSession.java@ 290

Last change on this file since 290 was 290, checked in by ra33, 16 years ago
File size: 17.4 KB
Line 
1package org.expeditee.agents.mail;
2
3import java.awt.Color;
4import java.awt.Point;
5import java.io.BufferedReader;
6import java.io.InputStream;
7import java.io.InputStreamReader;
8import java.util.Collection;
9import java.util.Date;
10import java.util.LinkedList;
11import java.util.Properties;
12
13import javax.mail.Address;
14import javax.mail.Authenticator;
15import javax.mail.Folder;
16import javax.mail.Message;
17import javax.mail.MessagingException;
18import javax.mail.Multipart;
19import javax.mail.Part;
20import javax.mail.PasswordAuthentication;
21import javax.mail.Session;
22import javax.mail.Store;
23import javax.mail.Transport;
24import javax.mail.Flags.Flag;
25import javax.mail.Message.RecipientType;
26import javax.mail.event.MessageCountAdapter;
27import javax.mail.event.MessageCountEvent;
28import javax.mail.internet.InternetAddress;
29import javax.mail.internet.MimeMessage;
30
31import org.expeditee.gui.AttributeValuePair;
32import org.expeditee.gui.Frame;
33import org.expeditee.gui.FrameCreator;
34import org.expeditee.gui.MessageBay;
35import org.expeditee.importer.FrameDNDTransferHandler;
36import org.expeditee.items.Item;
37import org.expeditee.items.Text;
38
39public class MailSession {
40 public static boolean _autoConnect = false;
41
42 private static MailSession _theMailSession = null;
43
44 private Session _session;
45
46 private Transport _transport;
47
48 private Store _store;
49
50 private Folder _folder;
51
52 private String _address;
53
54 private String _username;
55
56 private String _password;
57
58 private String _mailServer;
59
60 private String _serverType;
61
62 private Boolean _bConnecting;
63
64 private MailSession(Frame settingsFrame) {
65 _bConnecting = false;
66
67 Properties props = System.getProperties();
68
69 _username = null;
70 _password = "";
71 _mailServer = null;
72 _serverType = null;
73
74 // Set the settings
75 for (Text item : settingsFrame.getBodyTextItems(false)) {
76 if (item.getText().toLowerCase().trim().equals("autoconnect")) {
77 _autoConnect = true;
78 continue;
79 }
80 AttributeValuePair avp = new AttributeValuePair(item.getText());
81 if (!avp.hasPair())
82 continue;
83 String attributeFullCase = avp.getAttribute();
84 String attribute = attributeFullCase.toLowerCase();
85
86 if (attribute.equals("user")) {
87 _username = avp.getValue();
88 props.setProperty("mail.user", _username);
89 } else if (attribute.equals("password")) {
90 _password = avp.getValue();
91 props.setProperty("mail.password", _password);
92 } else if (attribute.equals("address")) {
93 _address = avp.getValue();
94 } else if (attribute.equals("smtpserver")) {
95 props.setProperty("mail.transport.protocol", "smtp");
96 props.setProperty("mail.host", avp.getValue());
97 props.setProperty("mail.smtp.starttls.enable", "true");
98 props.setProperty("mail.smtp.host", avp.getValue());
99 props.setProperty("mail.smtp.auth", "true");
100 } else if (attribute.equals("popserver")) {
101 _mailServer = avp.getValue();
102 _serverType = "pop3s";
103 props.setProperty("mail.pop3.host", _mailServer);
104 } else if (attribute.equals("imapserver")) {
105 _mailServer = avp.getValue();
106 _serverType = "imaps";
107 props.setProperty("mail.imap.host", _mailServer);
108 }
109 }
110
111 // Create the authenticator
112 Authenticator auth = null;
113 if (_username != null) {
114 auth = new SMTPAuthenticator(_username, _password);
115 }
116 java.security.Security
117 .addProvider(new com.sun.net.ssl.internal.ssl.Provider());
118
119 // -- Attaching to default Session, or we could start a new one --
120 _session = Session.getDefaultInstance(props, auth);
121 try {
122 // Set up the mail receiver
123 _store = _session.getStore(_serverType);
124
125 // Connect the mail sender
126 _transport = _session.getTransport();
127 if (_autoConnect) {
128 connectThreaded();
129 }
130 } catch (Exception e) {
131 MessageBay.errorMessage("Error in ExpMail setup");
132 }
133 }
134
135 /**
136 * Attempts to connect the mail transporter to the mail server.
137 *
138 */
139 public static void connect() {
140 if (_theMailSession._bConnecting) {
141 MessageBay.errorMessage("Already connecting to mail server");
142 return;
143 } else if (_theMailSession != null) {
144 _theMailSession.connectThreaded();
145 }
146 }
147
148 private void connectThreaded() {
149 Thread t = new ConnectThread(this);
150 t.start();
151 }
152
153 public synchronized void connectServers() {
154 try {
155 if (!_transport.isConnected()) {
156 Text message = MessageBay.displayMessage("Connecting to SMTP server...");
157 _bConnecting = true;
158 _transport.connect();
159 message.setAttributeValue("SMTP server connected");
160 message.setColor(Color.green);
161 } else {
162 MessageBay.warningMessage("SMTP server already connected");
163 }
164 } catch (MessagingException e) {
165 MessageBay.errorMessage("Error connecting to SMTP server");
166 }
167
168 if (_mailServer != null && !_store.isConnected()) {
169 try {
170 Text message = MessageBay.displayMessage("Connecting to " + _mailServer
171 + "...");
172 _store.connect(_mailServer, _username, _password);
173
174 // -- Try to get hold of the default folder --
175 _folder = _store.getDefaultFolder();
176 if (_folder == null)
177 throw new Exception("No default folder");
178 // -- ...and its INBOX --
179 _folder = _folder.getFolder("INBOX");
180 if (_folder == null)
181 throw new Exception("No INBOX");
182 // -- Open the folder for read only --
183 _folder.open(Folder.READ_WRITE);
184 _folder.addMessageCountListener(new MessageCountAdapter() {
185 @Override
186 public void messagesAdded(MessageCountEvent e) {
187 MessageBay.displayMessage("New mail message!",
188 Color.green);
189 displayUnreadMailCount();
190 }
191 });
192
193 new Thread() {
194 public void run() {
195 for (;;) {
196 try {
197 Thread.sleep(1000);
198 /*
199 * sleep for freq milliseconds. This is to force
200 * the IMAP server to send us EXISTS
201 * notifications
202 */
203 // TODO: Is synchronisation needed?
204 _folder.getMessageCount();
205 _folder.exists();
206 //_folder.getUnreadMessageCount();
207 } catch (Exception e) {
208 e.printStackTrace();
209 }
210 }
211 }
212 }.start();
213
214 message.setAttributeValue("Connection complete");
215 message.setColor(Color.GREEN);
216
217 displayUnreadMailCount();
218
219 } catch (Exception e) {
220 // e.printStackTrace();
221 MessageBay.errorMessage("Error connecting to " + _mailServer);
222 }
223 }
224 _bConnecting = false;
225 }
226
227 private void displayUnreadMailCount() {
228 int unreadCount = getUnreadCount();
229 Text text = new Text(-1, unreadCount + " unread message"
230 + (unreadCount == 1 ? "" : "s"), Color.BLUE, null);
231 text.addAction("getRecentMail " + unreadCount);
232 MessageBay.displayMessage(text);
233 }
234
235 public static boolean sendTextMessage(String to, String cc, String bcc,
236 String subject, String body, Object attachments) {
237
238 if (_theMailSession == null) {
239 MessageBay.errorMessage("Add mail settings to profile frame");
240 return false;
241 }
242
243 if (_theMailSession._bConnecting) {
244 MessageBay.errorMessage("Busy connecting to mail server...");
245 return false;
246 }
247
248 return _theMailSession
249 .sendText(to, cc, bcc, subject, body, attachments);
250 }
251
252 private synchronized boolean sendText(String to, String cc, String bcc,
253 String subject, String body, Object attachments) {
254 if (!_transport.isConnected()) {
255 MessageBay
256 .warningMessage("Not connected to server, attempting to reconnect...");
257 try {
258 _bConnecting = true;
259 _transport.connect();
260 _bConnecting = false;
261 } catch (Exception e) {
262 MessageBay.errorMessage("Could not connect to mail server");
263 _bConnecting = false;
264 return false;
265 }
266 }
267
268 if (to == null) {
269 MessageBay.errorMessage("Add tag @to:<sendToEmailAddress>");
270 return false;
271 }
272
273 try {
274 // -- Create a new message --
275 Message msg = new MimeMessage(_session);
276
277 // -- Set the FROM and TO fields --
278 msg.setFrom(new InternetAddress(_address));
279 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(
280 to, false));
281
282 // -- We could include CC recipients too --
283 if (cc != null) {
284 msg.setRecipients(Message.RecipientType.CC, InternetAddress
285 .parse(cc, false));
286 }
287
288 if (bcc != null) {
289 msg.setRecipients(Message.RecipientType.BCC, InternetAddress
290 .parse(bcc, false));
291 }
292
293 // -- Set the subject and body text --
294 msg.setSubject(subject);
295 msg.setContent(body.toString(), "text/plain");
296
297 // -- Set some other header information --
298 msg.setHeader("ExpMail", "Expeditee");
299 msg.setSentDate(new Date());
300
301 Transport.send(msg, msg.getRecipients(Message.RecipientType.TO));
302 } catch (Exception e) {
303 MessageBay.errorMessage("Error sending mail: " + e.getMessage());
304 return false;
305 }
306 MessageBay.displayMessage("Message sent OK.");
307 return true;
308 }
309
310 public static void init(Frame settingsFrame) {
311
312 if (settingsFrame == null)
313 return;
314
315 if (_theMailSession == null)
316 _theMailSession = new MailSession(settingsFrame);
317 }
318
319 private class SMTPAuthenticator extends javax.mail.Authenticator {
320 private String _username;
321
322 private String _password;
323
324 public SMTPAuthenticator(String username, String password) {
325 _username = username;
326 _password = password;
327 }
328
329 @Override
330 public PasswordAuthentication getPasswordAuthentication() {
331 return new PasswordAuthentication(_username, _password);
332 }
333 }
334
335 public static MailSession getInstance() {
336 return _theMailSession;
337 }
338
339 /**
340 * Closes the mail folders.
341 * @return true if the folders needed to be closed.
342 */
343 public synchronized boolean finalise() {
344 boolean result = false;
345 try {
346 if (_transport != null && _transport.isConnected()) {
347 _transport.close();
348 result = true;
349 }
350
351 if (_folder != null && _folder.isOpen()) {
352 _folder.close(false);
353 result = true;
354 }
355
356 if (_store != null && _store.isConnected()) {
357 _store.close();
358 result = true;
359 }
360 } catch (Exception e) {
361
362 }
363 return result;
364 }
365
366 public int getUnreadCount() {
367 try {
368 return _folder.getUnreadMessageCount();
369 } catch (MessagingException e) {
370 // TODO Auto-generated catch block
371 e.printStackTrace();
372 }
373 return 0;
374 }
375
376 /**
377 * Gets mail and puts a list of mail items with links to the messages
378 * content. TODO: Put reply and forward button on the frame...
379 *
380 * @param flag
381 * @param isPresent
382 * @param frame
383 * @param point
384 * @return
385 */
386 public String getMailString(Flag flag, Boolean isPresent) {
387 StringBuffer sb = new StringBuffer();
388 // -- Get the message wrappers and process them --
389 Message[] msgs;
390 try {
391 msgs = _folder.getMessages();
392 for (int msgNum = 0; msgNum < msgs.length; msgNum++) {
393
394 if (flag == null
395 || msgs[msgNum].getFlags().contains(flag) == isPresent) {
396 if (sb.length() > 0) {
397 sb.append('\n').append('\n').append(
398 "-----------------------------").append('\n')
399 .append('\n');
400 }
401 // Only get messages that have not been read
402 sb.append(getTextMessage(msgs[msgNum]));
403 }
404 }
405 } catch (MessagingException e) {
406 e.printStackTrace();
407 }
408 return sb.toString();
409 }
410
411 /**
412 * Gets mail and puts a list of mail items with links to the messages
413 * content. TODO: Put reply and forward button on the frame...
414 *
415 * @param flag
416 * @param isPresent
417 * @param frame
418 * @param point
419 * @return
420 */
421 public Collection<Text> getMail(Flag flag, Boolean isPresent, Frame frame,
422 Point point, int numberOfMessages) {
423 if (_folder == null)
424 return null;
425
426 Collection<Text> mailItems = new LinkedList<Text>();
427 // -- Get the message wrappers and process them --
428 Message[] msgs;
429 try {
430 msgs = _folder.getMessages();
431
432 int start = Math.max(msgs.length - numberOfMessages, 0);
433
434 for (int msgNum = start; msgNum < msgs.length; msgNum++) {
435 if (flag == null
436 || msgs[msgNum].getFlags().contains(flag) == isPresent) {
437 Text newItem = readMessage(msgs[msgNum], msgNum + 1, frame,
438 point);
439 if (newItem != null) {
440 mailItems.add(newItem);
441 point.y += newItem.getBoundsHeight();
442 }
443 }
444
445 }
446 } catch (MessagingException e) {
447 e.printStackTrace();
448 }
449
450 return mailItems;
451 }
452
453 private Text readMessage(final Message message, final int messageNo,
454 final Frame frame, final Point point) {
455
456 final Text source = FrameDNDTransferHandler.importString(
457 "Reading message " + messageNo + "...", point);
458
459 new Thread() {
460 public void run() {
461 try {
462 String subject = message.getSubject();
463 source.setText(messageNo + ". " + subject);
464 // Create a frameCreator
465 final FrameCreator frames = new FrameCreator(frame
466 .getFramesetName(), frame.path, subject, false);
467
468 frames.addText("@date: " + message.getSentDate(), null,
469 null, null, false);
470
471 // Get the header information
472 String from = ((InternetAddress) message.getFrom()[0])
473 .toString();
474 Text fromAddressItem = frames.addText("@from: " + from,
475 null, null, null, false);
476
477 addRecipients(message, frames, _address, RecipientType.TO,
478 "@to: ");
479 addRecipients(message, frames, null, RecipientType.CC,
480 "@cc: ");
481
482 // Read reply to addresses
483 Text reply = addAddresses(message, frames, from, message
484 .getReplyTo(), "@replyTo: ");
485 /*
486 * If the only person to reply to is the person who sent the
487 * mail add a tag that just says reply
488 */
489 if (reply == null) {
490 reply = frames.addText("@reply", null, null, null,
491 false);
492 reply.setPosition(10 + fromAddressItem.getX()
493 + fromAddressItem.getBoundsWidth(),
494 fromAddressItem.getY());
495 }
496 reply.addAction("reply");
497 // frames.addSpace(15);
498
499 // -- Get the message part (i.e. the message itself) --
500 Part messagePart = message;
501 Object content = messagePart.getContent();
502 // -- or its first body part if it is a multipart
503 // message --
504 if (content instanceof Multipart) {
505 messagePart = ((Multipart) content).getBodyPart(0);
506 // System.out.println("[ Multipart Message ]");
507 }
508 // -- Get the content type --
509 String contentType = messagePart.getContentType()
510 .toLowerCase();
511 // -- If the content is plain text, we can print it --
512 // System.out.println("CONTENT:" + contentType);
513 if (contentType.startsWith("text/plain")
514 || contentType.startsWith("text/html")) {
515 InputStream is = messagePart.getInputStream();
516 BufferedReader reader = new BufferedReader(
517 new InputStreamReader(is));
518 String thisLine = reader.readLine();
519 while (thisLine != null) {
520 frames.addText(thisLine, null, null, null, false);
521 thisLine = reader.readLine();
522 }
523 }
524 message.setFlag(Flag.SEEN, true);
525
526 frames.save();
527 source.setLink(frames.getName());
528 } catch (MessagingException e) {
529 MessageBay.errorMessage("GetMail error: " + e.getMessage());
530 } catch (Exception e) {
531 MessageBay.errorMessage("Error reading mail: "
532 + e.getMessage());
533 e.printStackTrace();
534 }
535 }
536 }.start();
537 return source;
538 }
539
540 /**
541 * "getTextMessage()" method to print a message.
542 */
543 public String getTextMessage(Message message) {
544 StringBuffer sb = new StringBuffer();
545
546 try {
547 // Get the header information
548 String from = ((InternetAddress) message.getFrom()[0])
549 .getPersonal();
550 if (from == null)
551 from = ((InternetAddress) message.getFrom()[0]).getAddress();
552 sb.append("FROM: " + from).append('\n');
553 String subject = message.getSubject();
554 sb.append("SUBJECT: " + subject).append('\n').append('\n');
555 // -- Get the message part (i.e. the message itself) --
556 Part messagePart = message;
557 Object content = messagePart.getContent();
558 // -- or its first body part if it is a multipart message --
559 if (content instanceof Multipart) {
560 messagePart = ((Multipart) content).getBodyPart(0);
561 System.out.println("[ Multipart Message ]");
562 }
563 // -- Get the content type --
564 String contentType = messagePart.getContentType();
565 // -- If the content is plain text, we can print it --
566 // System.out.println("CONTENT:" + contentType);
567 if (contentType.startsWith("text/plain")
568 || contentType.startsWith("text/html")) {
569 InputStream is = messagePart.getInputStream();
570 BufferedReader reader = new BufferedReader(
571 new InputStreamReader(is));
572 String thisLine = reader.readLine();
573 while (thisLine != null) {
574 sb.append(thisLine).append('\n');
575 thisLine = reader.readLine();
576 }
577 }
578 message.setFlag(Flag.SEEN, true);
579 } catch (Exception ex) {
580 ex.printStackTrace();
581 }
582 sb.deleteCharAt(sb.length() - 1);
583 return sb.toString();
584 }
585
586 public Folder getFolder() {
587 return _folder;
588 }
589
590 /**
591 * @param message
592 * @param frames
593 * @param type
594 * @throws MessagingException
595 */
596 private Text addAddresses(final Message message, final FrameCreator frames,
597 final String excludeAddress, final Address[] addresses,
598 String typeTag) throws MessagingException {
599 if (addresses == null)
600 return null;
601
602 StringBuffer sb = new StringBuffer();
603 boolean foundOtherRecipients = false;
604 for (Address addy : addresses) {
605 // Only show the to flag if this message was sent to
606 // other people
607 if (excludeAddress == null
608 || !addy.toString().toLowerCase().contains(
609 excludeAddress.toLowerCase())) {
610 foundOtherRecipients = true;
611 }
612 if (sb.length() > 0) {
613 sb.append(", ");
614 }
615 sb.append(addy.toString());
616 }
617 Text reply = null;
618 if (foundOtherRecipients) {
619 reply = frames.addText(typeTag + sb.toString(), null, null, null,
620 false);
621 }
622 return reply;
623 }
624
625 private Text addRecipients(final Message message,
626 final FrameCreator frames, String excludeAddress,
627 RecipientType type, String typeTag) throws MessagingException {
628 // Read and display all the recipients of the message
629 Address[] toRecipients = message.getRecipients(type);
630 return addAddresses(message, frames, excludeAddress, toRecipients,
631 typeTag);
632 }
633}
Note: See TracBrowser for help on using the repository browser.