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

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

Added Spell Checker
Added word count stats
Fixed some mail stuff

File size: 19.1 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 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() == "") {
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
600 frames.addText(nextText.substring(0, nextText.length() - 1),
601 null, null, null, false);
602 }
603 }.start();
604 return source;
605 }
606
607 /**
608 * "getTextMessage()" method to print a message.
609 */
610 public String getTextMessage(Message message) {
611 StringBuffer sb = new StringBuffer();
612
613 try {
614 // Get the header information
615 String from = ((InternetAddress) message.getFrom()[0])
616 .getPersonal();
617 if (from == null)
618 from = ((InternetAddress) message.getFrom()[0]).getAddress();
619 sb.append("FROM: " + from).append('\n');
620 String subject = message.getSubject();
621 sb.append("SUBJECT: " + subject).append('\n').append('\n');
622 // -- Get the message part (i.e. the message itself) --
623 Part messagePart = message;
624 Object content = messagePart.getContent();
625 // -- or its first body part if it is a multipart message --
626 if (content instanceof Multipart) {
627 messagePart = ((Multipart) content).getBodyPart(0);
628 System.out.println("[ Multipart Message ]");
629 }
630 // -- Get the content type --
631 String contentType = messagePart.getContentType();
632 // -- If the content is plain text, we can print it --
633 // System.out.println("CONTENT:" + contentType);
634 if (contentType.startsWith("text/plain")
635 || contentType.startsWith("text/html")) {
636 InputStream is = messagePart.getInputStream();
637 BufferedReader reader = new BufferedReader(
638 new InputStreamReader(is));
639 String thisLine = reader.readLine();
640 while (thisLine != null) {
641 sb.append(thisLine).append('\n');
642 thisLine = reader.readLine();
643 }
644 }
645 message.setFlag(Flag.SEEN, true);
646 } catch (Exception ex) {
647 ex.printStackTrace();
648 }
649 sb.deleteCharAt(sb.length() - 1);
650 return sb.toString();
651 }
652
653 public Folder getFolder() {
654 return _folder;
655 }
656
657 /**
658 * @param message
659 * @param frames
660 * @param type
661 * @throws MessagingException
662 */
663 private Text addAddresses(final Message message, final FrameCreator frames,
664 final String excludeAddress, final Address[] addresses,
665 String typeTag) throws MessagingException {
666 if (addresses == null)
667 return null;
668
669 StringBuffer sb = new StringBuffer();
670 boolean foundOtherRecipients = false;
671 for (Address addy : addresses) {
672 // Only show the to flag if this message was sent to
673 // other people
674 if (excludeAddress == null
675 || !addy.toString().toLowerCase().contains(
676 excludeAddress.toLowerCase())) {
677 foundOtherRecipients = true;
678 }
679 if (sb.length() > 0) {
680 sb.append(", ");
681 }
682 sb.append(addy.toString());
683 }
684 Text reply = null;
685 if (foundOtherRecipients) {
686 reply = frames.addText(typeTag + sb.toString(), null, null, null,
687 false);
688 }
689 return reply;
690 }
691
692 private Text addRecipients(final Message message,
693 final FrameCreator frames, String excludeAddress,
694 RecipientType type, String typeTag) throws MessagingException {
695 // Read and display all the recipients of the message
696 Address[] toRecipients = message.getRecipients(type);
697 return addAddresses(message, frames, excludeAddress, toRecipients,
698 typeTag);
699 }
700}
Note: See TracBrowser for help on using the repository browser.