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

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

fixed getmail so it splits text items

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