001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * -----------------------------------------------------------------------------
005: * ivata groupware may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * -----------------------------------------------------------------------------
030: * $Log: JavaMailServer.java,v $
031: * Revision 1.8 2005/10/14 14:39:59 colinmacleod
032: * Changed checkPassword to return boolean rather than throwing an
033: * exception.
034: *
035: * Revision 1.7 2005/10/11 18:56:03 colinmacleod
036: * Fixed some checkstyle and javadoc issues.
037: *
038: * Revision 1.6 2005/10/02 14:08:59 colinmacleod
039: * Added/improved log4j logging.
040: *
041: * Revision 1.5 2005/09/29 14:17:04 colinmacleod
042: * Split UserGroupDO off from GroupDO.
043: * Moved UserGroupDO, Right classes to security subproject (from
044: * addressbook).
045: * Centralized user right handling into Rights and RightsImpl.
046: *
047: * Revision 1.4 2005/09/14 16:16:52 colinmacleod
048: * Removed unused local and class variables.
049: * Added serialVersionUID.
050: *
051: * Revision 1.3 2005/04/10 19:30:11 colinmacleod
052: * Fixed exception message when login fails
053: * (added missing quote).
054: *
055: * Revision 1.2 2005/04/09 17:20:01 colinmacleod
056: * Changed copyright text to GPL v2 explicitly.
057: *
058: * Revision 1.1.1.1 2005/03/10 17:51:22 colinmacleod
059: * Restructured ivata op around Hibernate/PicoContainer.
060: * Renamed ivata groupware.
061: *
062: * -----------------------------------------------------------------------------
063: */
064: package com.ivata.groupware.business.mail.server;
065:
066: import java.util.Properties;
067:
068: import javax.mail.AuthenticationFailedException;
069: import javax.mail.Folder;
070: import javax.mail.MessagingException;
071: import javax.mail.NoSuchProviderException;
072: import javax.mail.Session;
073: import javax.mail.Store;
074:
075: import org.apache.log4j.Logger;
076: import org.picocontainer.MutablePicoContainer;
077: import org.picocontainer.PicoContainer;
078: import org.picocontainer.defaults.DefaultPicoContainer;
079:
080: import com.ivata.groupware.admin.security.server.PlainTextSecuritySession;
081: import com.ivata.groupware.admin.security.server.SecuritySession;
082: import com.ivata.groupware.admin.security.user.UserConstants;
083: import com.ivata.groupware.admin.security.user.UserDO;
084: import com.ivata.groupware.admin.setting.Settings;
085: import com.ivata.groupware.business.addressbook.AddressBook;
086: import com.ivata.groupware.business.addressbook.person.PersonDO;
087: import com.ivata.groupware.business.mail.session.MailSession;
088: import com.ivata.groupware.container.PicoContainerFactory;
089: import com.ivata.mask.util.SystemException;
090:
091: /**
092: * <p>
093: * Uses <strong>JavaMail</strong> methods to actually log into the mail server.
094: * </p>
095: *
096: * @since ivata groupware 0.10 (2005-02-21)
097: * @author Colin MacLeod
098: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
099: * @version $Revision: 1.8 $
100: */
101: public abstract class JavaMailServer implements MailServer {
102: /**
103: * Logger for this class.
104: */
105: private static final Logger logger = Logger
106: .getLogger(JavaMailServer.class);
107: /**
108: * <copyDoc>Refer to {@link #JavaMailServer(AddressBook, Settings)}.
109: * </copyDoc>
110: */
111: private AddressBook addressBook;
112: /**
113: * <copyDoc>Refer to {@link #JavaMailServer(AddressBook, Settings)}.
114: * </copyDoc>
115: */
116: private Settings settings;
117:
118: /**
119: * Constructor. Normally called by <code>PicoContainer</code>.
120: *
121: * @param addressBookParam Used to look-up the people associated with site
122: * users.
123: * @param settingsParam Used to access email settings such as the site
124: * host, and folder names.
125: */
126: public JavaMailServer(final AddressBook addressBookParam,
127: final Settings settingsParam) {
128: this .addressBook = addressBookParam;
129: this .settings = settingsParam;
130: }
131:
132: /**
133: * {@inheritDoc}
134: *
135: * @param securitySession {@inheritDoc}
136: * @param userName {@inheritDoc}
137: * @param password {@inheritDoc}
138: * @throws SystemException {@inheritDoc}
139: * @return {@inheritDoc}
140: */
141: public boolean checkPassword(final SecuritySession securitySession,
142: final String userName, final String password)
143: throws SystemException {
144: if (logger.isDebugEnabled()) {
145: logger
146: .debug("checkPassword(SecuritySession securitySession = "
147: + securitySession
148: + ", String userName = "
149: + userName
150: + ", String password = "
151: + password + ") - start");
152: }
153:
154: PicoContainer globalContainer = PicoContainerFactory
155: .getInstance().getGlobalContainer();
156: MutablePicoContainer sessionContainer = new DefaultPicoContainer(
157: globalContainer);
158: SecuritySession guestSession = loginGuest();
159: PersonDO person = addressBook.findPersonByUserName(
160: guestSession, userName);
161: UserDO user = person.getUser();
162: MailSession mailSession = new MailSession(sessionContainer,
163: user);
164: user.setName(user.getName().toLowerCase());
165:
166: Properties mailProperties = new Properties();
167: try {
168: mailProperties.setProperty("mail.host", (settings
169: .getStringSetting(mailSession, "emailHost", null)));
170: mailProperties.setProperty("mail.smtp.host", settings
171: .getStringSetting(mailSession, "emailHostSmtp",
172: null));
173: } catch (Exception e) {
174: logger
175: .error(
176: "checkPassword(SecuritySession, String, String)",
177: e);
178:
179: throw new SystemException(
180: "ERROR: Exception in ScriptMailServer", e);
181: }
182: mailProperties.setProperty("mail.user", getSystemUserName(
183: securitySession, user.getName()));
184:
185: if (user.getName().equals("emergency")) {
186: mailProperties.setProperty("mail.from",
187: "emergency@ivata.com");
188: } else {
189: mailProperties.setProperty("mail.from", person
190: .getEmailAddress());
191: }
192:
193: try {
194: mailSession.login(password, mailProperties);
195: } catch (AuthenticationFailedException e) {
196: if (logger.isDebugEnabled()) {
197: logger.debug(
198: "checkPassword - authentication failed - end - "
199: + "return value = " + false, e);
200: }
201: return false;
202: } catch (NoSuchProviderException e) {
203: logger
204: .error(
205: "checkPassword(SecuritySession, String, String)",
206: e);
207:
208: throw new SystemException("ERROR: "
209: + e.getClass().getName()
210: + " connecting using imap to "
211: + mailProperties.getProperty("mail.host"), e);
212: } catch (MessagingException e) {
213: logger
214: .error(
215: "checkPassword(SecuritySession, String, String)",
216: e);
217:
218: throw new SystemException("ERROR: "
219: + e.getClass().getName()
220: + " connecting using imap to "
221: + mailProperties.getProperty("mail.host"), e);
222: } catch (Exception e) {
223: logger
224: .error(
225: "checkPassword(SecuritySession, String, String)",
226: e);
227:
228: throw new SystemException("ERROR: "
229: + e.getClass().getName()
230: + " connecting using imap to "
231: + mailProperties.getProperty("mail.host"), e);
232: }
233:
234: if (logger.isDebugEnabled()) {
235: logger
236: .debug("checkPassword() - end - return value = " + true);
237: }
238: return true;
239: }
240:
241: /**
242: * <p>Helper. Get the store from the mail session and connect it.</p>
243: *
244: * @param mailSession Used to access <em>JavaMail</em> store.
245: * @return A valid, connected <em>JavaMail</em> store.
246: * @throws SystemException If we cannot connect for any reason.
247: */
248: public Store connectStore(final MailSession mailSession)
249: throws SystemException {
250: if (logger.isDebugEnabled()) {
251: logger.debug("connectStore(MailSession mailSession = "
252: + mailSession + ") - start");
253: }
254:
255: try {
256: Session javaMailSession;
257: try {
258: javaMailSession = mailSession.getJavaMailSession();
259: } catch (java.security.NoSuchProviderException e1) {
260: logger.error("connectStore(MailSession)", e1);
261:
262: throw new SystemException(e1);
263: }
264: Store store = javaMailSession.getStore("imap");
265: if (store == null) {
266: throw new SystemException(
267: "ERROR in MailBean: could not access the mail store");
268: }
269: if (!store.isConnected()) {
270: store.connect();
271: }
272:
273: if (logger.isDebugEnabled()) {
274: logger.debug("connectStore - end - return value = "
275: + store);
276: }
277: return store;
278: } catch (MessagingException e) {
279: logger.error("connectStore(MailSession)", e);
280:
281: throw new SystemException(e);
282: }
283: }
284:
285: /**
286: * Wrapper for <code>Store.getFolder</code> to get around the fact that
287: * courier/cyrus imap prefixes all "personal namespace" folder names with
288: * "INBOX".
289: *
290: * @param securitySession used to access the settings.
291: * @param store valid, connected store.
292: * @param name name of the folder you want to open.
293: * @return folder for the name you passed.
294: * @throws SystemException if the settings cannot be accessed, or there is
295: * any exception accessing the store.
296: */
297: public Folder getFolder(final SecuritySession securitySession,
298: final Store store, final String name)
299: throws SystemException {
300: if (logger.isDebugEnabled()) {
301: logger.debug("getFolder(SecuritySession securitySession = "
302: + securitySession + ", Store store = " + store
303: + ", String name = " + name + ") - start");
304: }
305:
306: assert (securitySession != null);
307: assert (store != null);
308: assert (store.isConnected());
309: assert (name != null);
310: String prefix;
311: if ("inbox".equalsIgnoreCase(name)) {
312: prefix = "";
313: } else {
314: prefix = settings.getStringSetting(securitySession,
315: "emailFolderNamespace", securitySession.getUser());
316: }
317: String fullFolderName = prefix + name;
318: try {
319: Folder returnFolder = store.getFolder(fullFolderName);
320: if (logger.isDebugEnabled()) {
321: logger.debug("getFolder - end - return value = "
322: + returnFolder);
323: }
324: return returnFolder;
325: } catch (MessagingException e) {
326: logger
327: .error("getFolder(SecuritySession, Store, String)",
328: e);
329:
330: throw new SystemException(e);
331: }
332: }
333:
334: /**
335: * {@inheritDoc}
336: *
337: * @param securitySession {@inheritDoc}
338: * @param userName {@inheritDoc}
339: * @param folderName {@inheritDoc}
340: * @return {@inheritDoc}
341: * @throws SystemException {@inheritDoc}
342: */
343: public boolean hasNewMessages(
344: final SecuritySession securitySession,
345: final String userName, final String folderName)
346: throws SystemException {
347: if (logger.isDebugEnabled()) {
348: logger
349: .debug("hasNewMessages(SecuritySession securitySession = "
350: + securitySession
351: + ", String userName = "
352: + userName
353: + ", String folderName = "
354: + folderName + ") - start");
355: }
356:
357: assert (securitySession instanceof MailSession);
358: MailSession mailSession = (MailSession) securitySession;
359:
360: Store store = connectStore(mailSession);
361: try {
362: Folder folder = getFolder(mailSession, store, folderName);
363: boolean returnboolean = folder.hasNewMessages();
364: if (logger.isDebugEnabled()) {
365: logger.debug("hasNewMessages - end - return value = "
366: + returnboolean);
367: }
368: return returnboolean;
369: } catch (MessagingException e) {
370: logger.error(
371: "hasNewMessages(SecuritySession, String, String)",
372: e);
373:
374: throw new SystemException(e);
375: } finally {
376: try {
377: store.close();
378: } catch (MessagingException e) {
379: logger.error("Closing store.", e);
380: }
381: }
382: }
383:
384: /**
385: * {@inheritDoc}
386: *
387: * @param user {@inheritDoc}
388: * @param password {@inheritDoc}
389: * @return {@inheritDoc}
390: * @throws SystemException {@inheritDoc}
391: */
392: public SecuritySession login(final UserDO user,
393: final String password) throws SystemException {
394: if (logger.isDebugEnabled()) {
395: logger.debug("login(UserDO user = " + user
396: + ", String password = " + password + ") - start");
397: }
398:
399: PicoContainer globalContainer = PicoContainerFactory
400: .getInstance().getGlobalContainer();
401: MutablePicoContainer sessionContainer = new DefaultPicoContainer(
402: globalContainer);
403: MailSession mailSession = new MailSession(sessionContainer,
404: user);
405: sessionContainer.registerComponentInstance(
406: SecuritySession.class, mailSession);
407:
408: // all user names are lower case
409: if (user == null) {
410: throw new SystemException(
411: "ERROR in ScriptMailServer: user is null");
412: }
413: if (user.getName() == null) {
414: throw new SystemException(
415: "ERROR in ScriptMailServer: user name is null");
416: }
417: user.setName(user.getName().toLowerCase());
418:
419: Properties mailProperties = new Properties();
420: String hostName;
421:
422: try {
423: hostName = settings.getStringSetting(mailSession,
424: "emailHost", null);
425: mailProperties.setProperty("mail.host", hostName);
426: mailProperties.setProperty("mail.smtp.host", settings
427: .getStringSetting(mailSession, "emailHostSmtp",
428: null));
429: } catch (Exception e) {
430: logger.error("login(UserDO, String)", e);
431:
432: throw new SystemException(
433: "ERROR: Exception in ScriptMailServer", e);
434: }
435: mailProperties.setProperty("mail.user", getSystemUserName(
436: mailSession, user.getName()));
437:
438: if (user.getName().equals("emergency")) {
439: mailProperties.setProperty("mail.from",
440: "emergency@ivata.com");
441: } else {
442: // now check out this user's name and email address
443: PersonDO person = addressBook.findPersonByUserName(
444: mailSession, user.getName());
445: mailProperties.setProperty("mail.from", person
446: .getEmailAddress());
447: }
448:
449: try {
450: try {
451: mailSession.login(password, mailProperties);
452: } catch (AuthenticationFailedException e) {
453: logger.error("login(UserDO, String)", e);
454:
455: String logPassword = "**********";
456: Boolean showPassword = settings.getBooleanSetting(
457: mailSession, "siteLoginDebugPassword", null);
458: if ((showPassword != null)
459: && showPassword.booleanValue()) {
460: logPassword = password;
461: }
462: throw new SystemException(
463: "Warning: could not connect user '"
464: + mailProperties
465: .getProperty("mail.user")
466: + ", password '" + logPassword
467: + "' to server '" + hostName + "'", e);
468: }
469: } catch (NoSuchProviderException e) {
470: logger.error("login(UserDO, String)", e);
471:
472: throw new SystemException("ERROR: "
473: + e.getClass().getName()
474: + " connecting using imap to "
475: + mailProperties.getProperty("mail.host"), e);
476: } catch (MessagingException e) {
477: logger.error("login(UserDO, String)", e);
478:
479: throw new SystemException("ERROR: "
480: + e.getClass().getName()
481: + " connecting using imap to "
482: + mailProperties.getProperty("mail.host"), e);
483: } catch (Exception e) {
484: logger.error("login(UserDO, String)", e);
485:
486: throw new SystemException("ERROR: "
487: + e.getClass().getName()
488: + " connecting using imap to "
489: + mailProperties.getProperty("mail.host"), e);
490: }
491: mailSession.setPassword(password);
492:
493: if (logger.isDebugEnabled()) {
494: logger
495: .debug("login(UserDO, String) - end - return value = "
496: + mailSession);
497: }
498: return mailSession;
499: }
500:
501: /**
502: * {@inheritDoc}
503: *
504: * @return {@inheritDoc}
505: * @throws SystemException {@inheritDoc}
506: */
507: public SecuritySession loginGuest() throws SystemException {
508: if (logger.isDebugEnabled()) {
509: logger.debug("loginGuest() - start");
510: }
511:
512: PicoContainer globalContainer = PicoContainerFactory
513: .getInstance().getGlobalContainer();
514: UserDO guestUser = new UserDO();
515: guestUser.setId(UserConstants.GUEST);
516: guestUser.setDeleted(false);
517: guestUser.setEnabled(true);
518: guestUser.setName("guest");
519: MutablePicoContainer sessionContainer = new DefaultPicoContainer(
520: globalContainer);
521: SecuritySession session = new PlainTextSecuritySession(
522: sessionContainer, guestUser);
523: sessionContainer.registerComponentInstance(
524: SecuritySession.class, session);
525:
526: if (logger.isDebugEnabled()) {
527: logger.debug("loginGuest() - end - return value = "
528: + session);
529: }
530: return session;
531: }
532: }
|