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

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

Added some HELP actions
More mail stuff... and networking stuff
Can now save frames and send messages to peers
Also version control prevent versions from being lost

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