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

Last change on this file since 286 was 286, checked in by ra33, 16 years ago
File size: 17.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.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 public synchronized void finalise() {
340 try {
341 if (_transport != null && _transport.isConnected()) {
342 _transport.close();
343 }
344
345 if (_folder != null && _folder.isOpen()) {
346 _folder.close(false);
347 }
348
349 if (_store != null && _store.isConnected()) {
350 _store.close();
351 }
352 } catch (Exception e) {
353
354 }
355 }
356
357 public int getUnreadCount() {
358 try {
359 return _folder.getUnreadMessageCount();
360 } catch (MessagingException e) {
361 // TODO Auto-generated catch block
362 e.printStackTrace();
363 }
364 return 0;
365 }
366
367 /**
368 * Gets mail and puts a list of mail items with links to the messages
369 * content. TODO: Put reply and forward button on the frame...
370 *
371 * @param flag
372 * @param isPresent
373 * @param frame
374 * @param point
375 * @return
376 */
377 public String getMailString(Flag flag, Boolean isPresent) {
378 StringBuffer sb = new StringBuffer();
379 // -- Get the message wrappers and process them --
380 Message[] msgs;
381 try {
382 msgs = _folder.getMessages();
383 for (int msgNum = 0; msgNum < msgs.length; msgNum++) {
384
385 if (flag == null
386 || msgs[msgNum].getFlags().contains(flag) == isPresent) {
387 if (sb.length() > 0) {
388 sb.append('\n').append('\n').append(
389 "-----------------------------").append('\n')
390 .append('\n');
391 }
392 // Only get messages that have not been read
393 sb.append(getTextMessage(msgs[msgNum]));
394 }
395 }
396 } catch (MessagingException e) {
397 e.printStackTrace();
398 }
399 return sb.toString();
400 }
401
402 /**
403 * Gets mail and puts a list of mail items with links to the messages
404 * content. TODO: Put reply and forward button on the frame...
405 *
406 * @param flag
407 * @param isPresent
408 * @param frame
409 * @param point
410 * @return
411 */
412 public Collection<Text> getMail(Flag flag, Boolean isPresent, Frame frame,
413 Point point, int numberOfMessages) {
414 if (_folder == null)
415 return null;
416
417 Collection<Text> mailItems = new LinkedList<Text>();
418 // -- Get the message wrappers and process them --
419 Message[] msgs;
420 try {
421 msgs = _folder.getMessages();
422
423 int start = Math.max(msgs.length - numberOfMessages, 0);
424
425 for (int msgNum = start; msgNum < msgs.length; msgNum++) {
426 if (flag == null
427 || msgs[msgNum].getFlags().contains(flag) == isPresent) {
428 Text newItem = readMessage(msgs[msgNum], msgNum + 1, frame,
429 point);
430 if (newItem != null) {
431 mailItems.add(newItem);
432 point.y += newItem.getBoundsHeight();
433 }
434 }
435
436 }
437 } catch (MessagingException e) {
438 e.printStackTrace();
439 }
440
441 return mailItems;
442 }
443
444 private Text readMessage(final Message message, final int messageNo,
445 final Frame frame, final Point point) {
446
447 final Text source = FrameDNDTransferHandler.importString(
448 "Reading message " + messageNo + "...", point);
449
450 new Thread() {
451 public void run() {
452 try {
453 String subject = message.getSubject();
454 source.setText(messageNo + ". " + subject);
455 // Create a frameCreator
456 final FrameCreator frames = new FrameCreator(frame
457 .getFramesetName(), frame.path, subject, false);
458
459 frames.addText("@date: " + message.getSentDate(), null,
460 null, null, false);
461
462 // Get the header information
463 String from = ((InternetAddress) message.getFrom()[0])
464 .toString();
465 Text fromAddressItem = frames.addText("@from: " + from,
466 null, null, null, false);
467
468 addRecipients(message, frames, _address, RecipientType.TO,
469 "@to: ");
470 addRecipients(message, frames, null, RecipientType.CC,
471 "@cc: ");
472
473 // Read reply to addresses
474 Text reply = addAddresses(message, frames, from, message
475 .getReplyTo(), "@replyTo: ");
476 /*
477 * If the only person to reply to is the person who sent the
478 * mail add a tag that just says reply
479 */
480 if (reply == null) {
481 reply = frames.addText("@reply", null, null, null,
482 false);
483 reply.setPosition(10 + fromAddressItem.getX()
484 + fromAddressItem.getBoundsWidth(),
485 fromAddressItem.getY());
486 }
487 reply.addAction("reply");
488 // frames.addSpace(15);
489
490 // -- Get the message part (i.e. the message itself) --
491 Part messagePart = message;
492 Object content = messagePart.getContent();
493 // -- or its first body part if it is a multipart
494 // message --
495 if (content instanceof Multipart) {
496 messagePart = ((Multipart) content).getBodyPart(0);
497 // System.out.println("[ Multipart Message ]");
498 }
499 // -- Get the content type --
500 String contentType = messagePart.getContentType()
501 .toLowerCase();
502 // -- If the content is plain text, we can print it --
503 // System.out.println("CONTENT:" + contentType);
504 if (contentType.startsWith("text/plain")
505 || contentType.startsWith("text/html")) {
506 InputStream is = messagePart.getInputStream();
507 BufferedReader reader = new BufferedReader(
508 new InputStreamReader(is));
509 String thisLine = reader.readLine();
510 while (thisLine != null) {
511 frames.addText(thisLine, null, null, null, false);
512 thisLine = reader.readLine();
513 }
514 }
515 message.setFlag(Flag.SEEN, true);
516
517 frames.save();
518 source.setLink(frames.getName());
519 } catch (MessagingException e) {
520 MessageBay.errorMessage("GetMail error: " + e.getMessage());
521 } catch (Exception e) {
522 MessageBay.errorMessage("Error reading mail: "
523 + e.getMessage());
524 e.printStackTrace();
525 }
526 }
527 }.start();
528 return source;
529 }
530
531 /**
532 * "getTextMessage()" method to print a message.
533 */
534 public String getTextMessage(Message message) {
535 StringBuffer sb = new StringBuffer();
536
537 try {
538 // Get the header information
539 String from = ((InternetAddress) message.getFrom()[0])
540 .getPersonal();
541 if (from == null)
542 from = ((InternetAddress) message.getFrom()[0]).getAddress();
543 sb.append("FROM: " + from).append('\n');
544 String subject = message.getSubject();
545 sb.append("SUBJECT: " + subject).append('\n').append('\n');
546 // -- Get the message part (i.e. the message itself) --
547 Part messagePart = message;
548 Object content = messagePart.getContent();
549 // -- or its first body part if it is a multipart 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 // -- 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 while (thisLine != null) {
565 sb.append(thisLine).append('\n');
566 thisLine = reader.readLine();
567 }
568 }
569 message.setFlag(Flag.SEEN, true);
570 } catch (Exception ex) {
571 ex.printStackTrace();
572 }
573 sb.deleteCharAt(sb.length() - 1);
574 return sb.toString();
575 }
576
577 public Folder getFolder() {
578 return _folder;
579 }
580
581 /**
582 * @param message
583 * @param frames
584 * @param type
585 * @throws MessagingException
586 */
587 private Text addAddresses(final Message message, final FrameCreator frames,
588 final String excludeAddress, final Address[] addresses,
589 String typeTag) throws MessagingException {
590 if (addresses == null)
591 return null;
592
593 StringBuffer sb = new StringBuffer();
594 boolean foundOtherRecipients = false;
595 for (Address addy : addresses) {
596 // Only show the to flag if this message was sent to
597 // other people
598 if (excludeAddress == null
599 || !addy.toString().toLowerCase().contains(
600 excludeAddress.toLowerCase())) {
601 foundOtherRecipients = true;
602 }
603 if (sb.length() > 0) {
604 sb.append(", ");
605 }
606 sb.append(addy.toString());
607 }
608 Text reply = null;
609 if (foundOtherRecipients) {
610 reply = frames.addText(typeTag + sb.toString(), null, null, null,
611 false);
612 }
613 return reply;
614 }
615
616 private Text addRecipients(final Message message,
617 final FrameCreator frames, String excludeAddress,
618 RecipientType type, String typeTag) throws MessagingException {
619 // Read and display all the recipients of the message
620 Address[] toRecipients = message.getRecipients(type);
621 return addAddresses(message, frames, excludeAddress, toRecipients,
622 typeTag);
623 }
624}
Note: See TracBrowser for help on using the repository browser.