Index: mailtool/project.xml =================================================================== --- mailtool/project.xml (revision 33562) +++ mailtool/project.xml (working copy) @@ -259,7 +259,15 @@ - src/java + src/java + src/test + + + + **/*Test.java + + + ${basedir}/src/bundle Index: mailtool/src/test/org/sakaiproject/tool/mailtool/MailtoolEmailListValidationTest.java =================================================================== --- mailtool/src/test/org/sakaiproject/tool/mailtool/MailtoolEmailListValidationTest.java (revision 0) +++ mailtool/src/test/org/sakaiproject/tool/mailtool/MailtoolEmailListValidationTest.java (revision 0) @@ -0,0 +1,149 @@ +package org.sakaiproject.tool.mailtool; + +import junit.framework.TestCase; + +public class MailtoolEmailListValidationTest extends TestCase { + + private Mailtool mailtool; + + protected void setUp() throws Exception { + // some hacks b/c of env assumptions in the Mailtool constructor + mailtool = new Mailtool() { + + protected String getSiteID() { + return "THIS_IS_A_STUB_SITE_ID"; + } + + protected String getSiteTitle() { + return "THIS_IS_A_STUB_SITE_TITLE"; + } + + protected String getSiteRealmID() { + return "/site/" + getSiteID(); + } + + public String getGroupAwareRole() { + return groupAwareRoleDefault; + } + + protected String getConfigParam(String parameter) { + return ""; + } + + public int readMaxNumAttachment() { + return 10000; + } + + protected String getSiteType() { + return ""; + } + + public void getRecipientSelectors() { + // do nothing + } + + public void checkifGroupAwareRoleExist() { + // do nothing + } + + public boolean isEmailArchiveAddedToSite() { + return false; + } + + }; + + super.setUp(); + } + + + public void testIsValidEmailList_AcceptsSimpleAddress() { + String toMatch = "someone@domain.com"; + assertTrue("Should have validated a simple address [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsAddressWithFourthLevelDomain() { + String toMatch = "someone@subber.sub.domain.com"; + assertTrue("Should have validated an address with a third-level domain [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_RejectsAddressWithEmptyDomainSegment() { + String toMatch = "someone@sub..com"; + assertFalse("Should have rejected an address with empty domain segment [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_RejectsAddressWithUnqualifiedDomain() { + String toMatch = "someone@domain"; + assertFalse("Should have rejected an address with invalid domain [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_RejectsAddressWithOnlyOneToken() { + String toMatch = "garbage"; + assertFalse("Should have rejected an address with invalid domain [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmaiList_AcceptsAddressWithMixedCaseDomain() { + String toMatch = "someone@sUb.doMain.CoM"; + assertTrue("Should have validated an address with a mixed-case domain [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsCommaDelimitedListOfValidAddresses() { + String toMatch = "someone@domain.com,someone@domain.com"; + assertTrue("Should have validated multiple simple addresses [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsCommaDelimitedListOfValidAddressesWithWhitespace() { + String toMatch = "someone@domain.com, someoneelse@domain.com"; + assertTrue("Should have validated multiple simple addresses with comma and space delims [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsSemiColonDelimitedListOfValidAddresses() { + String toMatch = "someone@domain.com;someoneelse@domain.com"; + assertTrue("Should have validated multiple simple addresses with semicolon delim [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsSemiColonDelimitedListOfValidAddressesWithWhitespace() { + String toMatch = "someone@domain.com; someoneelse@domain.com"; + assertTrue("Should have validated multiple simple addresses with semicolon and space delims [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsLongListOfValidAddresseWithMixedDelimiters() { + String toMatch = "someone@domain.com, someoneelse@domain.com; someoneelseentirely@domain.com,someonenew@domain.com"; + assertTrue("Should have validated a large number of simple addresses with mixed delims [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_RejectsListOfAddressesWithGarbageInFirstElement() { + String toMatch = "garbage, someone@domain.com, someoneelseentirely@domain.com"; + assertFalse("Should have rejected a list of addresses with garbage in the first element [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_RejectsListOfAddressesWithGarbageInInnerElement() { + String toMatch = "someone@domain.com, garbage, someoneelseentirely@domain.com"; + assertFalse("Should have rejected a list of addresses with garbage in an inner element [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_RejectsListOfAddressesWithGarbageInLastElement() { + String toMatch = "someone@domain.com, someoneelseentirely@domain.com, garbage"; + assertFalse("Should have rejected a list of addresses with garbage in the last element [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + + public void testIsValidEmailList_AcceptsAddressAtLocalhost() { + String toMatch = "someone@localhost"; + assertTrue("Should have validated an address at localhost [" + toMatch + "]", + mailtool.isValidEmailList(toMatch)); + } + +} Index: mailtool/src/java/org/sakaiproject/tool/mailtool/Mailtool.java =================================================================== --- mailtool/src/java/org/sakaiproject/tool/mailtool/Mailtool.java (revision 33562) +++ mailtool/src/java/org/sakaiproject/tool/mailtool/Mailtool.java (working copy) @@ -28,65 +28,63 @@ // import java.lang.Thread; import java.io.File; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.TreeSet; import java.util.Iterator; import java.util.List; +import java.util.Properties; import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; import java.util.Vector; import java.util.regex.Pattern; -import java.util.regex.Matcher; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.faces.application.FacesMessage; +import javax.faces.component.UIComponent; +import javax.faces.component.UIInput; +import javax.faces.context.FacesContext; +import javax.faces.event.AbortProcessingException; +import javax.faces.event.ValueChangeEvent; +import javax.faces.validator.ValidatorException; +import javax.mail.BodyPart; +import javax.mail.Message; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + import org.apache.commons.fileupload.FileItem; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.commons.io.FilenameUtils; -import org.sakaiproject.tool.api.ToolSession; -import org.sakaiproject.tool.cover.SessionManager; -import org.sakaiproject.tool.cover.ToolManager; -// import org.sakaiproject.email.cover.EmailService; -import org.sakaiproject.event.cover.NotificationService; import org.sakaiproject.authz.api.AuthzGroup; +import org.sakaiproject.authz.api.Role; import org.sakaiproject.authz.cover.AuthzGroupService; -import org.sakaiproject.authz.api.Role; import org.sakaiproject.component.cover.ServerConfigurationService; +import org.sakaiproject.event.cover.NotificationService; +import org.sakaiproject.mailarchive.api.MailArchiveChannel; +import org.sakaiproject.mailarchive.api.MailArchiveMessageEdit; +import org.sakaiproject.mailarchive.api.MailArchiveMessageHeaderEdit; +import org.sakaiproject.mailarchive.cover.MailArchiveService; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.ToolConfiguration; +import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.time.cover.TimeService; +import org.sakaiproject.tool.api.ToolSession; +import org.sakaiproject.tool.cover.SessionManager; +import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.cover.UserDirectoryService; -import org.sakaiproject.mailarchive.api.MailArchiveChannel; -import org.sakaiproject.mailarchive.api.MailArchiveMessageEdit; -import org.sakaiproject.mailarchive.api.MailArchiveMessageHeaderEdit; -import org.sakaiproject.mailarchive.cover.MailArchiveService; -import org.sakaiproject.site.cover.SiteService; -// import org.sakaiproject.site.api.SitePage; -// import org.sakaiproject.tool.api.ToolSession; -// import org.sakaiproject.tool.cover.SessionManager; -import javax.faces.context.FacesContext; -import javax.faces.application.FacesMessage; -import javax.faces.event.PhaseId; -import javax.faces.event.ValueChangeEvent; -// import javax.faces.event.ActionEvent; -import javax.faces.event.AbortProcessingException; -import javax.faces.validator.ValidatorException; -import javax.faces.component.UIComponent; -import javax.faces.component.UIInput; -import java.util.Properties; -import javax.mail.BodyPart; -import javax.mail.Message; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import javax.mail.internet.InternetAddress; -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.activation.FileDataSource; +import org.sakaiproject.util.StringUtil; /** * Mailtool bean for compose (expanded by kimsooil@bu.edu) @@ -95,6 +93,56 @@ * */ public class Mailtool { + + /** + * Name of the {@link javax.mail.Session} property that enables + * debugging in that package. At this time, std out is the only + * supported output PrintStream for this logging. This is a standard + * Java Mail value. + */ + public static final String JAVAX_MAIL_DEBUG_PROP_NAME = "mail.debug"; + + /** + * Default name of the {@link javax.mail.Session} property with which clients + * specify the target mail server. This name is actually dynamic, being + * composed of mail.protocol.host. At this time, all we support + * is STMP, hence the current value of this constant. + */ + public static final String DEFAULT_JAVAX_MAIL_HOST_PROP_NAME = "mail.smtp.host"; + + /** + * Name of the Sakai property which defines the target mail host. At this + * writing, we piggy-back on the EmailService configuration, + * but do not actually have a dependency on that API. + */ + public static final String DEFAULT_SAKAI_MAIL_HOST_PROP_NAME = + "smtp@org.sakaiproject.email.api.EmailService"; + + /** + * Name of the Sakai property which controls {@link javax.mail.Session} + * debugging. At this writing, this name corresponds to the standard + * javax.mail property name. + */ + public static final String DEFAULT_SAKAI_MAIL_DEBUG_PROP_NAME = + JAVAX_MAIL_DEBUG_PROP_NAME; + + /** + * Default pattern for verifying a single email address's syntax. Is quite + * relaxed w/r/t allowable accountID and domain characters. Coded to + * require all domains other than "localhost" to terminate with a 2 - 6 + * char TLD. The TLD is not actually verified against an official enumeration. + * Anchored by beginning- and end-of-input markers. + */ + public static final String DEFAULT_EMAIL_ADDR_PATTERN = + "^(.+?@(?:localhost)|(?:[^.]+\\.)+[a-zA-Z]{2,6})+$"; + + /** + * The account ID used when constructing no-reply "from" email addresses. + * Currently private with no accessors since this is not yet a generally + * configurable feature. + */ + private static final String NO_REPLY_ACCOUNT_ID = "noreply"; + private final Log log = LogFactory.getLog(this.getClass()); protected FacesContext facesContext = FacesContext.getCurrentInstance(); @@ -204,6 +252,15 @@ private SiteService siteService; protected ToolConfiguration m_toolConfig = null; + + private String javaxMailHostPropertyName = DEFAULT_JAVAX_MAIL_HOST_PROP_NAME; + + private String sakaiMailHostPropertyName = DEFAULT_SAKAI_MAIL_HOST_PROP_NAME; + + private String sakaiMailDebugPropertyName = DEFAULT_SAKAI_MAIL_DEBUG_PROP_NAME; + + // TODO: configurable pattern + private Pattern emailAddrPattern = Pattern.compile(DEFAULT_EMAIL_ADDR_PATTERN); protected Site currentSite = null; @@ -428,7 +485,7 @@ return (ToolManager.getCurrentPlacement().getContext()); } - private String getSiteRealmID() { + protected String getSiteRealmID() { return ("/site/" + ToolManager.getCurrentPlacement().getContext()); } @@ -740,14 +797,6 @@ EmailUser curUser = getCurrentUser(); - String fromEmail = ""; - String fromDisplay = ""; - if (curUser != null) { - fromEmail = curUser.getEmail(); - fromDisplay = curUser.getDisplayname(); - } - String fromString = fromDisplay + " <" + fromEmail + ">"; - m_results = "Message sent to:
"; String subject = m_subject; @@ -766,7 +815,7 @@ + a.getFilename() + "(" + a.getSize() + " Bytes)"; i++; } - this.appendToArchive(emailarchive, fromString, subject, m_body + this.appendToArchive(emailarchive, curUser.getNiceEmail(), subject, m_body + attachment_info); } List headers = new ArrayList(); @@ -775,27 +824,20 @@ else headers.add("content-type: text/plain"); - String smtp_server = ServerConfigurationService - .getString("smtp@org.sakaiproject.email.api.EmailService"); - // String smtp_port = ServerConfigurationService.getString("smtp.port"); try { - Properties props = new Properties(); - props.put("mail.smtp.host", smtp_server); - // props.put("mail.smtp.port", smtp_port); - Session s = Session.getInstance(props, null); + + Session s = createMailSession(); MimeMessage message = new MimeMessage(s); - InternetAddress from = new InternetAddress(fromString); + InternetAddress from = curUser.getInternetAddress(); message.setFrom(from); String reply = getReplyToSelected().trim().toLowerCase(); if (reply.equals("yes")) { // "reply to sender" is default. So do nothing } else if (reply.equals("no")) { - String noreply = getSiteTitle() + " "; - InternetAddress noreplyemail = new InternetAddress(noreply); - message.setFrom(noreplyemail); + InternetAddress noReplyAddr = createNoReplyInternetAddress(); + message.setFrom(noReplyAddr); } else if (reply.equals("otheremail") && getReplyToOtherEmail().equals("") != true) { // need input(email) validation @@ -868,7 +910,7 @@ // Transport.send(message, to); } if (m_sendmecopy) { - message.addRecipients(Message.RecipientType.CC, fromEmail); + message.addRecipients(Message.RecipientType.CC, curUser.getEmail()); // trying to solve SAK-7410 // recipientsString+=fromEmail; // InternetAddress to[] = {new InternetAddress(fromEmail) }; @@ -880,8 +922,17 @@ Transport.send(message); } catch (Exception e) { - log.debug("Mailtool Exception while trying to send the email: " - + e.getMessage()); + if ( log.isWarnEnabled() ) { + log.warn("Mailtool Exception while trying to send the email: ", e); + } + + FacesMessage message = new FacesMessage(); + message.setDetail("Failed to send email. Error message: " + e.getMessage()); + message.setSummary("Failed to send email. Error message: " + e.getMessage()); + message.setSeverity(FacesMessage.SEVERITY_ERROR); + FacesContext.getCurrentInstance().addMessage("", message); + return ""; + } // Clear the Subject and Body of the Message @@ -926,7 +977,112 @@ } return "results"; } + + /** + * Instantiate and configure a new {@link javax.mail.Session}. + * + * @see #createMailSessionProperties() + * @return a new {@link javax.mail.Session} + */ + protected Session createMailSession() { + Properties sessionProps = createMailSessionProperties(); + Session s = Session.getInstance(sessionProps, null); + return s; + } + + /** + * Collect a {@link Properties} instance representing the + * standard configuration for a new Mailtool {@link javax.mail.Session} + * instance. As implemented, simply configures a single mail host + * and a debugging flag. + * + * @see #getMailHost() + * @see #getMailDebug() + * @return {@link javax.mail.Session} configuration + */ + protected Properties createMailSessionProperties() { + + Properties props = new Properties(); + + // we assume only one mail host + String mailHost = StringUtil.trimToNull(getMailHost()); + if ( mailHost == null ) { + if ( log.isWarnEnabled() ) { + log.warn("No javax.mail host configured."); + } + } else { + if ( log.isDebugEnabled() ) { + log.debug("Setting javax.mail.Session property [name = " + javaxMailHostPropertyName + + "][value = " + mailHost + "]"); + } + props.put(javaxMailHostPropertyName, mailHost); + } + + String debugJavaxMail = getMailDebug(); + if ( log.isDebugEnabled() ) { + log.debug("Setting javax.mail.Session property [name = " + JAVAX_MAIL_DEBUG_PROP_NAME + + "][value = " + debugJavaxMail + "]"); + } + props.put(JAVAX_MAIL_DEBUG_PROP_NAME, debugJavaxMail); + + return props; + + } + + /** + * Constructs an {@link InternetAddress} for use as a "no-reply" from address. + * Follows the historical convention of using the configured mail host + * as the address domain. The account ID is not currently configurable. + * + * @see #getMailHost() + * @return a new {@link InternetAddress} + * @throws UnsupportedEncodingException + */ + protected InternetAddress createNoReplyInternetAddress() + throws UnsupportedEncodingException { + String siteTitle = getSiteTitle(); + String noReplyEmailAddrStr = NO_REPLY_ACCOUNT_ID + "@" + getMailHost(); + if ( log.isDebugEnabled() ) { + log.debug("Constructing a no-reply email addr [personal name = " + siteTitle + + "][address = " + noReplyEmailAddrStr + "]"); + } + InternetAddress internetAddr = new InternetAddress(noReplyEmailAddrStr, siteTitle); + return internetAddr; + } + + /** + * Access the name of the target mail host. Currently implemented + * to retrieve this value from the Sakai {@link ServerConfigurationService} + * using a configurable key. + * + * @see #getSakaiMailHostPropertyName() + * @see ServerConfigurationService#getString(String) + * @return name of the mail host used by this tool + */ + public String getMailHost() { + String hostName = + ServerConfigurationService.getString(sakaiMailHostPropertyName); + return hostName; + } + + /** + * Access the current {@link javax.mail.Session} debugging flag (String-encoded + * boolean). Will not return null; defaults to "false". + * Currently implemented to retrieve this value from the Sakai + * {@link ServerConfigurationService} using a configurable key. + * + * @see #getSakaiMailDebugPropertyName() + * @see ServerConfigurationService#getString(String) + * @return + */ + public String getMailDebug() { + String debug = + StringUtil.trimToNull(ServerConfigurationService.getString(sakaiMailDebugPropertyName)); + return debug == null ? "false" : "true"; + } + + public RecipientSelector getRecipientSelector() { getRecipientSelectors(); @@ -1965,24 +2121,43 @@ */ public void validateEmail(FacesContext context, UIComponent toValidate, Object value) throws ValidatorException { - String enteredEmail = (String) value; - Pattern p = Pattern.compile("(.+@.+\\.[a-z]+)"); // Set the email - // pattern string + boolean matchFound = isValidEmailList((String)value); - // Match the given string with the pattern - Matcher m = p.matcher(enteredEmail); - - // Check whether match is found - boolean matchFound = m.matches(); - if (!matchFound) { FacesMessage message = new FacesMessage(); - message.setDetail("Email not valid"); - message.setSummary("Email not valid"); + message.setDetail("Email not valid in Other Recipients field"); + message.setSummary("Email not valid in Other Recipients field"); message.setSeverity(FacesMessage.SEVERITY_ERROR); throw new ValidatorException(message); } } + + /** + * Tests if a string contains one or more valid email addresses and no invalid + * addresses. Test is purely syntactical. Default pattern is defined by + * {@link #DEFAULT_EMAIL_ADDR_PATTERN}. + * + * @param emailAddresses a String, possibly representing a comma- or semi-colon- + * delimited list of email addresses + * @return true unless any of the tokens in the given string + * are syntactically invalid email addresses. + */ + protected boolean isValidEmailList(String emailAddresses) { + // TODO configurable delims? + StringTokenizer tokenizer = new StringTokenizer(emailAddresses, ",;"); + for ( String token = null; tokenizer.hasMoreTokens(); ) { + token = tokenizer.nextToken().trim(); + if (!(emailAddrPattern.matcher(token).matches())) { + if ( log.isDebugEnabled() ) { + log.debug("Email failed syntax validation test [email addr = " + token + + "][pattern = " + emailAddrPattern.pattern() + "]"); + } + return false; + } + } + return true; + } + public void validateSubject(FacesContext context, UIComponent toValidate, Object value) throws ValidatorException { String enteredSubject = (String) value; @@ -2049,4 +2224,74 @@ public void setSitename(String sitename) { this.sitename = sitename; } + + /** + * Access the name of the {@link javax.mail.Session} property + * to use when assigning the target host name. + * + * @return a {@link javax.mail.Session} property name + */ + public String getJavaxMailHostPropertyName() { + return javaxMailHostPropertyName; + } + + /** + * Set the name of the {@link javax.mail.Session} property + * to use when assigning the target host name. This is technically + * a dynamic value, being composed of mail.protocol.host. + * Defaults to {@link #DEFAULT_JAVAX_MAIL_HOST_PROP_NAME}. + * + * @param javaxMailHostPropertyName + */ + public void setJavaxMailHostPropertyName(String javaxMailHostPropertyName) { + this.javaxMailHostPropertyName = javaxMailHostPropertyName; + } + + /** + * Access the name of the Sakai property which defines the target mail host. + * (Not the actual mail host name itself). + * + * @see #getMailHost() + * @see ServerConfigurationService#getString(String) + * @return a Sakai property name + */ + public String getSakaiMailHostPropertyName() { + return sakaiMailHostPropertyName; + } + + /** + * Set the name of the Sakai property which defines the target mail host. + * (Not the actual mail host name itself). Defaults to + * {@link #DEFAULT_SAKAI_MAIL_HOST_PROP_NAME}. + * + * @see ServerConfigurationService#getString(String) + * @param sakaiMailHostPropertyName a Sakai property name + */ + public void setSakaiMailHostPropertyName(String sakaiMailHostPropertyName) { + this.sakaiMailHostPropertyName = sakaiMailHostPropertyName; + } + + /** + * Access the name of the Sakai property which controls {@link javax.mail.Session} + * debugging. (Not the actual boolean setting itself). + * + * @see #getMailDebug() + * @see ServerConfigurationService#getString(String) + * @return a Sakai property name + */ + public String getSakaiMailDebugPropertyName() { + return sakaiMailDebugPropertyName; + } + + /** + * Assign the name of the Sakai property which controls {@link javax.mail.Session} + * debugging. (Not the actual boolean setting itself). Defaults to + * {@link #DEFAULT_SAKAI_MAIL_DEBUG_PROP_NAME} + * + * @see ServerConfigurationService#getString(String) + * @param sakaiMailDebugPropertyName a Sakai property name + */ + public void setSakaiMailDebugPropertyName(String sakaiMailDebugPropertyName) { + this.sakaiMailDebugPropertyName = sakaiMailDebugPropertyName; + } } Index: mailtool/src/java/org/sakaiproject/tool/mailtool/EmailUser.java =================================================================== --- mailtool/src/java/org/sakaiproject/tool/mailtool/EmailUser.java (revision 33562) +++ mailtool/src/java/org/sakaiproject/tool/mailtool/EmailUser.java (working copy) @@ -21,7 +21,14 @@ package org.sakaiproject.tool.mailtool; +import java.io.UnsupportedEncodingException; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; + +import org.sakaiproject.util.StringUtil; + + /** * EmailUser contains user id, full name, first/last names, etc. (commented by kimsooil@bu.edu) * @@ -107,6 +114,35 @@ return nicestring; } + /** + * Constructs an {@link InternetAddress} based on this user's current + * state. If the user has not been assigned an email address String, will + * return an "empty" {@link InternetAddress}. If no display name + * has been assigned, will return an instance initialized by + * {@link InternetAddress#InternetAddress(String)}. If both a display + * name and an email address String have been assigned, will return + * an instance initialized by {@link InternetAddress#InternetAddress(String, String)} + * + * @return a new {@link InternetAddress} derived from this user's state + * @throws AddressException if the proposed address fails {@link InternetAddress} + * parsing rules + * @throws UnsupportedEncodingException + */ + public InternetAddress getInternetAddress() throws AddressException, + UnsupportedEncodingException { + + if ( StringUtil.trimToNull(m_email) == null ) { + return new InternetAddress(); + } + + if ( StringUtil.trimToNull(m_displayname) == null ) { + return new InternetAddress(m_email); + } + + return new InternetAddress(m_email, m_displayname); + + } + public int compareTo(Object anotherEmailUser) throws ClassCastException { if (!(anotherEmailUser instanceof EmailUser)) Index: .classpath =================================================================== --- .classpath (revision 33562) +++ .classpath (working copy) @@ -1,3 +1,4 @@ + @@ -2,2 +3,3 @@ + @@ -30,4 +32,6 @@ + +