001: package org.claros.commons.mail.protocols;
002:
003: import java.util.ArrayList;
004: import java.util.Collections;
005: import java.util.HashMap;
006: import java.util.Map;
007: import java.util.Properties;
008:
009: import javax.mail.AuthenticationFailedException;
010: import javax.mail.FetchProfile;
011: import javax.mail.Flags;
012: import javax.mail.Folder;
013: import javax.mail.Message;
014: import javax.mail.MessagingException;
015: import javax.mail.NoSuchProviderException;
016: import javax.mail.Session;
017: import javax.mail.Store;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.claros.commons.auth.models.AuthProfile;
022: import org.claros.commons.exception.SystemException;
023: import org.claros.commons.mail.exception.ConnectionException;
024: import org.claros.commons.mail.exception.MailboxActionException;
025: import org.claros.commons.mail.exception.ServerDownException;
026: import org.claros.commons.mail.models.ConnectionMetaHandler;
027: import org.claros.commons.mail.models.ConnectionProfile;
028: import org.claros.commons.mail.models.EmailHeader;
029: import org.claros.commons.mail.utility.Constants;
030: import org.claros.commons.mail.utility.Utility;
031: import org.claros.commons.utility.Formatter;
032:
033: /**
034: * @author Umut Gokbayrak
035: */
036: public class Pop3ProtocolImpl implements Protocol {
037: private static Log log = LogFactory.getLog(Pop3ProtocolImpl.class);
038: private ConnectionProfile profile;
039: private AuthProfile auth;
040: private ConnectionMetaHandler handler;
041: private static Map pop3Folders = Collections
042: .synchronizedMap(new HashMap());
043:
044: /**
045: *
046: * @param profile
047: * @param auth
048: * @param handler
049: */
050: Pop3ProtocolImpl(ConnectionProfile profile, AuthProfile auth,
051: ConnectionMetaHandler handler) {
052: this .profile = profile;
053: this .auth = auth;
054: this .handler = handler;
055: }
056:
057: /* (non-Javadoc)
058: * @see org.claros.commons.mail.protocols.FetchProtocol#connect(int)
059: */
060: public ConnectionMetaHandler connect(int connectType)
061: throws SystemException, ConnectionException,
062: ServerDownException {
063: try {
064: try {
065: disconnect();
066: try {
067: Thread.sleep(2000);
068: } catch (Exception k) {
069: }
070: } catch (Exception k) {
071: }
072:
073: if (handler == null || !handler.getStore().isConnected()) {
074: Properties props = new Properties();
075: Session session = Session.getDefaultInstance(props);
076: log.debug("session instance initiated");
077: handler = new ConnectionMetaHandler();
078: handler.setStore(session
079: .getStore(profile.getProtocol()));
080: log.debug("session store set");
081: handler.getStore().connect(profile.getFetchServer(),
082: profile.getIFetchPort(), auth.getUsername(),
083: auth.getPassword());
084: log.debug("Store has been connected... Successful");
085: handler.setMbox(handler.getStore().getDefaultFolder());
086: handler.setMbox(handler.getMbox().getFolder(
087: Constants.FOLDER_INBOX(profile)));
088: log.debug("Got mailbox");
089: handler.getMbox().open(connectType);
090: log.debug("Mailbox open");
091:
092: // storing the folder in map
093: pop3Folders.put(auth.getUsername(), handler.getMbox());
094:
095: handler.setTotalMessagesCount(handler.getMbox()
096: .getMessageCount());
097: log.debug("Message Count:"
098: + handler.getTotalMessagesCount());
099: }
100: } catch (AuthenticationFailedException e) {
101: log
102: .debug(
103: "Pop3 Mailbox was busy with another session and there is a read write lock. A few minutes later when the lock is released everything will be fine.",
104: e);
105: } catch (NoSuchProviderException e) {
106: log.fatal(profile.getProtocol()
107: + " provider could not be found.");
108: throw new SystemException(e);
109: } catch (MessagingException e) {
110: log.error("Connection could not be established.");
111: throw new ConnectionException(e);
112: } catch (Exception e) {
113: e.printStackTrace();
114: }
115: return handler;
116: }
117:
118: /* (non-Javadoc)
119: * @see org.claros.commons.mail.protocols.FetchProtocol#deleteMessages(int[])
120: */
121: public ConnectionMetaHandler deleteMessages(int[] messageIds)
122: throws MailboxActionException, SystemException,
123: ConnectionException {
124: Folder fold = null;
125: try {
126: fold = getFolder();
127: if (messageIds != null && messageIds.length > 0) {
128: for (int i = 0; i < messageIds.length; i++) {
129: Message msg = fold.getMessage(messageIds[i]);
130: msg.setFlag(Flags.Flag.DELETED, true);
131: }
132: }
133: fold.expunge();
134: connect(Constants.CONNECTION_READ_WRITE);
135: return handler;
136: } catch (Exception e) {
137: pop3Folders.put(auth.getUsername(), null);
138: log.error("Could not delete message ids: " + messageIds, e);
139: throw new MailboxActionException(e);
140: }
141: }
142:
143: /**
144: * Fetches all e-mail headers from the server, with appropriate
145: * fields already set.
146: * @param handler
147: * @return ArrayList of MessageHeaders
148: * @throws ConnectionException
149: */
150: public ArrayList fetchAllHeaders() throws SystemException,
151: ConnectionException {
152: ArrayList headers = null;
153: Folder fold = null;
154: try {
155: fold = getFolder();
156: closeFolder(fold);
157: fold = getFolder();
158:
159: headers = new ArrayList();
160: EmailHeader header = null;
161:
162: Message[] msgs = fold.getMessages();
163: FetchProfile fp = new FetchProfile();
164: fp.add(FetchProfile.Item.ENVELOPE);
165: fp.add(FetchProfile.Item.FLAGS);
166: fp.add(FetchProfile.Item.CONTENT_INFO);
167: fp.add("Size");
168: fp.add("Date");
169: fold.fetch(msgs, fp);
170:
171: Message msg = null;
172: for (int i = 0; i < msgs.length; i++) {
173: try {
174: header = new EmailHeader();
175: msg = msgs[i];
176:
177: header
178: .setMultipart((msg
179: .isMimeType("multipart/*")) ? true
180: : false);
181: header.setMessageId(i + 1);
182: header.setFrom(msg.getFrom());
183: header.setTo(msg
184: .getRecipients(Message.RecipientType.TO));
185: header.setCc(msg
186: .getRecipients(Message.RecipientType.CC));
187: header.setBcc(msg
188: .getRecipients(Message.RecipientType.BCC));
189: header.setDate(msg.getSentDate());
190: header.setReplyTo(msg.getReplyTo());
191: header.setSize(msg.getSize());
192: header.setSubject(msg.getSubject());
193:
194: // now set the human readables.
195: header.setDateShown(Formatter.formatDate(header
196: .getDate(), "dd.MM.yyyy HH:mm"));
197: header.setFromShown(Utility
198: .addressArrToString(header.getFrom()));
199: header.setToShown(Utility.addressArrToString(header
200: .getTo()));
201: header.setCcShown(Utility.addressArrToString(header
202: .getCc()));
203: header.setSizeShown(Utility
204: .sizeToHumanReadable(header.getSize()));
205:
206: // it is time to add it to the arraylist
207: headers.add(header);
208: } catch (MessagingException e1) {
209: log
210: .debug(
211: "Could not parse headers of e-mail. Message might be defuncted or illegal formatted.",
212: e1);
213: }
214: }
215: } catch (Exception e) {
216: log
217: .error(
218: "Could not fetch message headers. Is mbox connection still alive???",
219: e);
220: throw new ConnectionException(e);
221: }
222: return headers;
223: }
224:
225: /**
226: * Fetches and returns message headers as message objects.
227: * @return
228: * @throws SystemException
229: * @throws ConnectionException
230: */
231: public ArrayList fetchAllHeadersAsMessages()
232: throws SystemException, ConnectionException {
233: ArrayList headers = null;
234: Folder fold = null;
235: try {
236: fold = getFolder();
237: closeFolder(fold);
238: fold = getFolder();
239: headers = new ArrayList();
240:
241: Message[] msgs = fold.getMessages();
242: FetchProfile fp = new FetchProfile();
243: fp.add(FetchProfile.Item.ENVELOPE);
244: fp.add(FetchProfile.Item.FLAGS);
245: fp.add(FetchProfile.Item.CONTENT_INFO);
246: fp.add("Size");
247: fp.add("Date");
248: fold.fetch(msgs, fp);
249:
250: Message msg = null;
251: for (int i = 0; i < msgs.length; i++) {
252: msg = msgs[i];
253: headers.add(msg);
254: }
255: } catch (Exception e) {
256: log
257: .error(
258: "Could not fetch message headers. Is mbox connection still alive???",
259: e);
260: throw new ConnectionException(e);
261: }
262: return headers;
263: }
264:
265: public Message getMessage(int messageId)
266: throws MailboxActionException, SystemException,
267: ConnectionException, Exception {
268: Message msg = null;
269: Folder fold = null;
270: try {
271: try {
272: fold = getFolder();
273: msg = fold.getMessage(messageId);
274: } catch (Exception e) {
275: log
276: .error(
277: "Could not fetch message body from remote server.",
278: e);
279: throw new MailboxActionException(e);
280: }
281: } catch (Exception e) {
282: throw e;
283: }
284: return msg;
285: }
286:
287: /**
288: * Disconnects the previously opened data connection if
289: * the connection is still alive.
290: * @param handler
291: */
292: public void disconnect() {
293: try {
294: Folder fold = (Folder) pop3Folders.get(auth.getUsername());
295: if (fold != null) {
296: fold.close(true);
297: }
298: try {
299: if (handler.getMbox() != null) {
300: handler.getMbox().close(true);
301: }
302: } catch (Exception e) {
303: }
304:
305: try {
306: if (handler.getStore() != null) {
307: handler.getStore().close();
308: }
309: } catch (Exception e) {
310: }
311: } catch (Exception e) {
312: }
313: pop3Folders.put(auth.getUsername(), null);
314: }
315:
316: public void emptyFolder() throws Exception {
317: Folder f = getFolder();
318:
319: try {
320: Message msgs[] = f.getMessages();
321: FetchProfile fp = new FetchProfile();
322: fp.add(FetchProfile.Item.ENVELOPE);
323: f.fetch(msgs, fp);
324:
325: int ids[] = new int[msgs.length];
326: for (int i = 0; i < msgs.length; i++) {
327: ids[i] = msgs[i].getMessageNumber();
328: }
329: if (ids.length > 0) {
330: deleteMessages(ids);
331: }
332: } catch (Exception e) {
333: log.warn("Could not delete all messages");
334: }
335: }
336:
337: /**
338: *
339: * @return
340: * @throws Exception
341: */
342: public synchronized Folder getFolder() throws Exception {
343: String folder = Constants.FOLDER_INBOX(profile);
344:
345: Folder fold = (Folder) pop3Folders.get(auth.getUsername());
346: if (fold != null && fold.isOpen()) {
347: return fold;
348: } else {
349: if (folder != null && handler != null) {
350: Store store = handler.getStore();
351: if (store == null || !store.isConnected()) {
352: log.debug("Connection is closed. Restoring it...");
353: handler = connect(Constants.CONNECTION_READ_WRITE);
354: log.debug("Connection re-established");
355: }
356: fold = handler.getStore().getFolder(folder);
357: if (!fold.isOpen()) {
358: log.debug("Folder :" + folder
359: + " is closed. Opening again.");
360: fold.open(Constants.CONNECTION_READ_WRITE);
361: log.debug("Folder is open again.");
362:
363: pop3Folders.put(auth.getUsername(), fold);
364: }
365: }
366: }
367: return fold;
368: }
369:
370: /**
371: *
372: * @throws Exception
373: */
374: /*
375: public void connectIfNeeded() throws Exception {
376: Folder myFold = null;
377: String folder = Constants.FOLDER_INBOX(profile);
378:
379: if (folder != null && handler != null) {
380: Store store = handler.getStore();
381: if (store == null || !store.isConnected()) {
382: log.debug("Connection is closed. Restoring it...");
383: handler = connect(Constants.CONNECTION_READ_WRITE);
384: log.debug("Connection re-established");
385: }
386: myFold = handler.getStore().getFolder(folder);
387: if (!myFold.isOpen() && myFold.exists()) {
388: try {
389: myFold.close(true);
390: } catch (Exception z) {}
391:
392: try {
393: log.debug("Folder :" + folder + " is closed. Opening again.");
394: myFold.open(Constants.CONNECTION_READ_WRITE);
395: log.debug("Folder is open again.");
396: } catch (Exception m) {
397: m.printStackTrace();
398: }
399: }
400: }
401: }
402: */
403:
404: /**
405: *
406: * @param f
407: */
408: public void closeFolder(Folder f) {
409: if (f != null) {
410: try {
411: if (f.isOpen()) {
412: f.close(true);
413: log.info("Folder: " + f.getName()
414: + " was open and now closed.");
415: } else {
416: log.info("Folder: " + f.getName()
417: + " was already closed.");
418: }
419: } catch (MessagingException e) {
420: log.info("Error while closing folder: " + f.getName(),
421: e);
422: }
423: }
424: pop3Folders.put(auth.getUsername(), null);
425: }
426:
427: /**
428: * @return
429: */
430: public int getUnreadMessageCount() throws Exception {
431: Folder f = getFolder();
432:
433: if (f.exists()) {
434: return f.getUnreadMessageCount();
435: }
436: return 0;
437: }
438:
439: /**
440: * @return
441: */
442: public int getTotalMessageCount() throws Exception {
443: Folder f = getFolder();
444: if (f.exists()) {
445: return f.getMessageCount();
446: }
447: return 0;
448: }
449:
450: public void flagAsDeleted(int[] ids) throws Exception {
451: deleteMessages(ids);
452: }
453: }
|