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

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

Adding networking stuff for peer to peer sharing of frames

File size: 17.6 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 MessageBay.errorMessage("Mail connection unavailable");
210 finalise();
211 break;
212 }
213 }
214 }
215 }.start();
216
217 message.setAttributeValue("Connection complete");
218 message.setColor(Color.GREEN);
219
220 displayUnreadMailCount();
221
222 } catch (Exception e) {
223 // e.printStackTrace();
224 MessageBay.errorMessage("Error connecting to " + _mailServer);
225 }
226 }
227 _bConnecting = false;
228 }
229
230 private void displayUnreadMailCount() {
231 int unreadCount = getUnreadCount();
232 Text text = new Text(-1, unreadCount + " unread message"
233 + (unreadCount == 1 ? "" : "s"), Color.BLUE, null);
234 text.addAction("getRecentMail " + unreadCount);
235 MessageBay.displayMessage(text);
236 }
237
238 public static boolean sendTextMessage(String to, String cc, String bcc,
239 String subject, String body, Object attachments) {
240
241 if (_theMailSession == null) {
242 MessageBay.errorMessage("Add mail settings to profile frame");
243 return false;
244 }
245
246 if (_theMailSession._bConnecting) {
247 MessageBay.errorMessage("Busy connecting to mail server...");
248 return false;
249 }
250
251 return _theMailSession
252 .sendText(to, cc, bcc, subject, body, attachments);
253 }
254
255 private synchronized boolean sendText(String to, String cc, String bcc,
256 String subject, String body, Object attachments) {
257 if (!_transport.isConnected()) {
258 MessageBay
259 .warningMessage("Not connected to server, attempting to reconnect...");
260 try {
261 _bConnecting = true;
262 _transport.connect();
263 _bConnecting = false;
264 } catch (Exception e) {
265 MessageBay.errorMessage("Could not connect to mail server");
266 _bConnecting = false;
267 return false;
268 }
269 }
270
271 if (to == null) {
272 MessageBay.errorMessage("Add tag @to:<sendToEmailAddress>");
273 return false;
274 }
275
276 try {
277 // -- Create a new message --
278 Message msg = new MimeMessage(_session);
279
280 // -- Set the FROM and TO fields --
281 msg.setFrom(new InternetAddress(_address));
282 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(
283 to, false));
284
285 // -- We could include CC recipients too --
286 if (cc != null) {
287 msg.setRecipients(Message.RecipientType.CC, InternetAddress
288 .parse(cc, false));
289 }
290
291 if (bcc != null) {
292 msg.setRecipients(Message.RecipientType.BCC, InternetAddress
293 .parse(bcc, false));
294 }
295
296 // -- Set the subject and body text --
297 msg.setSubject(subject);
298 msg.setContent(body.toString(), "text/plain");
299
300 // -- Set some other header information --
301 msg.setHeader("ExpMail", "Expeditee");
302 msg.setSentDate(new Date());
303
304 Transport.send(msg, msg.getRecipients(Message.RecipientType.TO));
305 } catch (Exception e) {
306 MessageBay.errorMessage("Error sending mail: " + e.getMessage());
307 return false;
308 }
309 MessageBay.displayMessage("Message sent OK.");
310 return true;
311 }
312
313 public static void init(Frame settingsFrame) {
314
315 if (settingsFrame == null)
316 return;
317
318 if (_theMailSession == null)
319 _theMailSession = new MailSession(settingsFrame);
320 }
321
322 private class SMTPAuthenticator extends javax.mail.Authenticator {
323 private String _username;
324
325 private String _password;
326
327 public SMTPAuthenticator(String username, String password) {
328 _username = username;
329 _password = password;
330 }
331
332 @Override
333 public PasswordAuthentication getPasswordAuthentication() {
334 return new PasswordAuthentication(_username, _password);
335 }
336 }
337
338 public static MailSession getInstance() {
339 return _theMailSession;
340 }
341
342 /**
343 * Closes the mail folders.
344 * @return true if the folders needed to be closed.
345 */
346 public synchronized boolean finalise() {
347 boolean result = false;
348 try {
349 if (_transport != null && _transport.isConnected()) {
350 _transport.close();
351 result = true;
352 }
353
354 if (_folder != null && _folder.isOpen()) {
355 _folder.close(false);
356 result = true;
357 }
358
359 if (_store != null && _store.isConnected()) {
360 _store.close();
361 result = true;
362 }
363 } catch (Exception e) {
364
365 }
366 return result;
367 }
368
369 public int getUnreadCount() {
370 try {
371 return _folder.getUnreadMessageCount();
372 } catch (MessagingException e) {
373 // TODO Auto-generated catch block
374 e.printStackTrace();
375 }
376 return 0;
377 }
378
379 /**
380 * Gets mail and puts a list of mail items with links to the messages
381 * content. TODO: Put reply and forward button on the frame...
382 *
383 * @param flag
384 * @param isPresent
385 * @param frame
386 * @param point
387 * @return
388 */
389 public String getMailString(Flag flag, Boolean isPresent) {
390 StringBuffer sb = new StringBuffer();
391 // -- Get the message wrappers and process them --
392 Message[] msgs;
393 try {
394 msgs = _folder.getMessages();
395 for (int msgNum = 0; msgNum < msgs.length; msgNum++) {
396
397 if (flag == null
398 || msgs[msgNum].getFlags().contains(flag) == isPresent) {
399 if (sb.length() > 0) {
400 sb.append('\n').append('\n').append(
401 "-----------------------------").append('\n')
402 .append('\n');
403 }
404 // Only get messages that have not been read
405 sb.append(getTextMessage(msgs[msgNum]));
406 }
407 }
408 } catch (MessagingException e) {
409 e.printStackTrace();
410 }
411 return sb.toString();
412 }
413
414 /**
415 * Gets mail and puts a list of mail items with links to the messages
416 * content. TODO: Put reply and forward button on the frame...
417 *
418 * @param flag
419 * @param isPresent
420 * @param frame
421 * @param point
422 * @return
423 */
424 public Collection<Text> getMail(Flag flag, Boolean isPresent, Frame frame,
425 Point point, int numberOfMessages) {
426 if (_folder == null)
427 return null;
428
429 Collection<Text> mailItems = new LinkedList<Text>();
430 // -- Get the message wrappers and process them --
431 Message[] msgs;
432 try {
433 msgs = _folder.getMessages();
434
435 int start = Math.max(msgs.length - numberOfMessages, 0);
436
437 for (int msgNum = start; msgNum < msgs.length; msgNum++) {
438 if (flag == null
439 || msgs[msgNum].getFlags().contains(flag) == isPresent) {
440 Text newItem = readMessage(msgs[msgNum], msgNum + 1, frame,
441 point);
442 if (newItem != null) {
443 mailItems.add(newItem);
444 point.y += newItem.getBoundsHeight();
445 }
446 }
447
448 }
449 } catch (MessagingException e) {
450 e.printStackTrace();
451 }
452
453 return mailItems;
454 }
455
456 private Text readMessage(final Message message, final int messageNo,
457 final Frame frame, final Point point) {
458
459 final Text source = FrameDNDTransferHandler.importString(
460 "Reading message " + messageNo + "...", point);
461
462 new Thread() {
463 public void run() {
464 try {
465 String subject = message.getSubject();
466 source.setText(messageNo + ". " + subject);
467 // Create a frameCreator
468 final FrameCreator frames = new FrameCreator(frame
469 .getFramesetName(), frame.getPath(), subject, false, false);
470
471 frames.addText("@date: " + message.getSentDate(), null,
472 null, null, false);
473
474 // Get the header information
475 String from = ((InternetAddress) message.getFrom()[0])
476 .toString();
477 Text fromAddressItem = frames.addText("@from: " + from,
478 null, null, null, false);
479
480 addRecipients(message, frames, _address, RecipientType.TO,
481 "@to: ");
482 addRecipients(message, frames, null, RecipientType.CC,
483 "@cc: ");
484
485 // Read reply to addresses
486 Text reply = addAddresses(message, frames, from, message
487 .getReplyTo(), "@replyTo: ");
488 /*
489 * If the only person to reply to is the person who sent the
490 * mail add a tag that just says reply
491 */
492 if (reply == null) {
493 reply = frames.addText("@reply", null, null, null,
494 false);
495 reply.setPosition(10 + fromAddressItem.getX()
496 + fromAddressItem.getBoundsWidth(),
497 fromAddressItem.getY());
498 }
499 reply.addAction("reply");
500 // frames.addSpace(15);
501
502 // -- Get the message part (i.e. the message itself) --
503 Part messagePart = message;
504 Object content = messagePart.getContent();
505 // -- or its first body part if it is a multipart
506 // message --
507 if (content instanceof Multipart) {
508 messagePart = ((Multipart) content).getBodyPart(0);
509 // System.out.println("[ Multipart Message ]");
510 }
511 // -- Get the content type --
512 String contentType = messagePart.getContentType()
513 .toLowerCase();
514 // -- If the content is plain text, we can print it --
515 // System.out.println("CONTENT:" + contentType);
516 if (contentType.startsWith("text/plain")
517 || contentType.startsWith("text/html")) {
518 InputStream is = messagePart.getInputStream();
519 BufferedReader reader = new BufferedReader(
520 new InputStreamReader(is));
521 String thisLine = reader.readLine();
522 while (thisLine != null) {
523 frames.addText(thisLine, null, null, null, false);
524 thisLine = reader.readLine();
525 }
526 }
527 message.setFlag(Flag.SEEN, true);
528
529 frames.save();
530 source.setLink(frames.getName());
531 } catch (MessagingException e) {
532 MessageBay.errorMessage("GetMail error: " + e.getMessage());
533 } catch (Exception e) {
534 MessageBay.errorMessage("Error reading mail: "
535 + e.getMessage());
536 e.printStackTrace();
537 }
538 }
539 }.start();
540 return source;
541 }
542
543 /**
544 * "getTextMessage()" method to print a message.
545 */
546 public String getTextMessage(Message message) {
547 StringBuffer sb = new StringBuffer();
548
549 try {
550 // Get the header information
551 String from = ((InternetAddress) message.getFrom()[0])
552 .getPersonal();
553 if (from == null)
554 from = ((InternetAddress) message.getFrom()[0]).getAddress();
555 sb.append("FROM: " + from).append('\n');
556 String subject = message.getSubject();
557 sb.append("SUBJECT: " + subject).append('\n').append('\n');
558 // -- Get the message part (i.e. the message itself) --
559 Part messagePart = message;
560 Object content = messagePart.getContent();
561 // -- or its first body part if it is a multipart message --
562 if (content instanceof Multipart) {
563 messagePart = ((Multipart) content).getBodyPart(0);
564 System.out.println("[ Multipart Message ]");
565 }
566 // -- Get the content type --
567 String contentType = messagePart.getContentType();
568 // -- If the content is plain text, we can print it --
569 // System.out.println("CONTENT:" + contentType);
570 if (contentType.startsWith("text/plain")
571 || contentType.startsWith("text/html")) {
572 InputStream is = messagePart.getInputStream();
573 BufferedReader reader = new BufferedReader(
574 new InputStreamReader(is));
575 String thisLine = reader.readLine();
576 while (thisLine != null) {
577 sb.append(thisLine).append('\n');
578 thisLine = reader.readLine();
579 }
580 }
581 message.setFlag(Flag.SEEN, true);
582 } catch (Exception ex) {
583 ex.printStackTrace();
584 }
585 sb.deleteCharAt(sb.length() - 1);
586 return sb.toString();
587 }
588
589 public Folder getFolder() {
590 return _folder;
591 }
592
593 /**
594 * @param message
595 * @param frames
596 * @param type
597 * @throws MessagingException
598 */
599 private Text addAddresses(final Message message, final FrameCreator frames,
600 final String excludeAddress, final Address[] addresses,
601 String typeTag) throws MessagingException {
602 if (addresses == null)
603 return null;
604
605 StringBuffer sb = new StringBuffer();
606 boolean foundOtherRecipients = false;
607 for (Address addy : addresses) {
608 // Only show the to flag if this message was sent to
609 // other people
610 if (excludeAddress == null
611 || !addy.toString().toLowerCase().contains(
612 excludeAddress.toLowerCase())) {
613 foundOtherRecipients = true;
614 }
615 if (sb.length() > 0) {
616 sb.append(", ");
617 }
618 sb.append(addy.toString());
619 }
620 Text reply = null;
621 if (foundOtherRecipients) {
622 reply = frames.addText(typeTag + sb.toString(), null, null, null,
623 false);
624 }
625 return reply;
626 }
627
628 private Text addRecipients(final Message message,
629 final FrameCreator frames, String excludeAddress,
630 RecipientType type, String typeTag) throws MessagingException {
631 // Read and display all the recipients of the message
632 Address[] toRecipients = message.getRecipients(type);
633 return addAddresses(message, frames, excludeAddress, toRecipients,
634 typeTag);
635 }
636}
Note: See TracBrowser for help on using the repository browser.