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

Last change on this file since 409 was 409, checked in by ra33, 16 years ago

Fixed bug causing SIMPLE program run from an overlay to backup to that frame instead of the frame that was the current
Synchronized messageBay class...

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