mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
28.00.2007 16e9aa11e63515dbd5ee373ffe32863abddcc82a
Add an SMTP account status notification handler, which can be configured to
send e-mail messages whenever an account status notification is generated. The
message can be sent to the end user impacted by the notification (based on an
attribute in the user's entry) and/or a fixed set of recipients.

The messages that will be generated are created from template files, which can
include tokens that will be replced with things like:

- The name of the notification type
- The notification message
- The DN of the target user's entry
- Attribute values from the target user's entry
- Values of account status notification properties, which may vary based on the
type of notification

This change also includes a fix for a problem that could allow password
expiration warning messages to be sent to a client even if the bind was not
successful.


OpenDS Issue Number: 581
21 files added
5 files modified
1671 ■■■■■ changed files
opends/resource/config/config.ldif 35 ●●●●● patch | view | raw | blame | history
opends/resource/messages/account-disabled.template 4 ●●●● patch | view | raw | blame | history
opends/resource/messages/account-enabled.template 4 ●●●● patch | view | raw | blame | history
opends/resource/messages/account-expired.template 4 ●●●● patch | view | raw | blame | history
opends/resource/messages/account-idle-locked.template 5 ●●●●● patch | view | raw | blame | history
opends/resource/messages/account-permanently-locked.template 5 ●●●●● patch | view | raw | blame | history
opends/resource/messages/account-reset-locked.template 5 ●●●●● patch | view | raw | blame | history
opends/resource/messages/account-temporarily-locked.template 6 ●●●●● patch | view | raw | blame | history
opends/resource/messages/account-unlocked.template 3 ●●●●● patch | view | raw | blame | history
opends/resource/messages/password-changed.template 5 ●●●●● patch | view | raw | blame | history
opends/resource/messages/password-expired.template 3 ●●●●● patch | view | raw | blame | history
opends/resource/messages/password-expiring.template 7 ●●●●● patch | view | raw | blame | history
opends/resource/messages/password-reset.template 3 ●●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif 22 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/SMTPAccountStatusNotificationHandlerConfiguration.xml 209 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/extension.properties 45 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/NotificationMessageNotificationMessageTemplateElement.java 62 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/NotificationMessageTemplateElement.java 54 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/NotificationPropertyNotificationMessageTemplateElement.java 78 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/NotificationTypeNotificationMessageTemplateElement.java 62 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java 792 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/TextNotificationMessageTemplateElement.java 70 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java 90 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/UserDNNotificationMessageTemplateElement.java 62 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/AccountStatusNotification.java 22 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java 14 ●●●● patch | view | raw | blame | history
opends/resource/config/config.ldif
@@ -101,6 +101,41 @@
ds-cfg-account-status-notification-type: password-reset
ds-cfg-account-status-notification-type: password-changed
dn: cn=SMTP Handler,cn=Account Status Notification Handlers,cn=config
objectClass: top
objectClass: ds-cfg-account-status-notification-handler
objectClass: ds-cfg-smtp-account-status-notification-handler
cn: SMTP Handler
ds-cfg-account-status-notification-handler-class: org.opends.server.extensions.SMTPAccountStatusNotificationHandler
ds-cfg-account-status-notification-handler-enabled: false
ds-cfg-sender-address: opends-notifications@example.com
ds-cfg-email-address-attribute-type: mail
ds-cfg-send-notification-without-end-user-address: false
ds-cfg-message-template-file: account-temporarily-locked:config/messages/account-temporarily-locked.template
ds-cfg-message-template-file: account-permanently-locked:config/messages/account-permanently-locked.template
ds-cfg-message-template-file: account-unlocked:config/messages/account-unlocked.template
ds-cfg-message-template-file: account-idle-locked:config/messages/account-idle-locked.template
ds-cfg-message-template-file: account-reset-locked:config/messages/account-reset-locked.template
ds-cfg-message-template-file: account-disabled:config/messages/account-disabled.template
ds-cfg-message-template-file: account-enabled:config/messages/account-enabled.template
ds-cfg-message-template-file: account-expired:config/messages/account-expired.template
ds-cfg-message-template-file: password-expired:config/messages/password-expired.template
ds-cfg-message-template-file: password-expiring:config/messages/password-expiring.template
ds-cfg-message-template-file: password-reset:config/messages/password-reset.template
ds-cfg-message-template-file: password-changed:config/messages/password-changed.template
ds-cfg-message-subject: account-temporarily-locked:Your directory account has been locked
ds-cfg-message-subject: account-permanently-locked:Your directory account has been locked
ds-cfg-message-subject: account-unlocked:Your directory account has been unlocked
ds-cfg-message-subject: account-idle-locked:Your directory account has been locked
ds-cfg-message-subject: account-reset-locked:Your directory account has been locked
ds-cfg-message-subject: account-disabled:Your directory account has been disabled
ds-cfg-message-subject: account-enabled:Your directory account has been re-enabled
ds-cfg-message-subject: account-expired:Your directory account has expired
ds-cfg-message-subject: password-expired:Your directory password has expired
ds-cfg-message-subject: password-expiring:Your directory password is going to expire
ds-cfg-message-subject: password-reset:Your directory password has been reset
ds-cfg-message-subject: password-changed:Your directory password has been changed
dn: cn=Alert Handlers,cn=config
objectClass: top
objectClass: ds-cfg-branch
opends/resource/messages/account-disabled.template
New file
@@ -0,0 +1,4 @@
Your directory account has been disabled.
For further assistance, please contact a server administrator.
opends/resource/messages/account-enabled.template
New file
@@ -0,0 +1,4 @@
Your directory account has been re-enabled.
For further assistance, please contact a server administrator.
opends/resource/messages/account-expired.template
New file
@@ -0,0 +1,4 @@
Your directory account has expired and may no longer be used.
For further assistance, please contact a server administrator.
opends/resource/messages/account-idle-locked.template
New file
@@ -0,0 +1,5 @@
Your directory account has been locked because it has remained idle for
too long.
For further assistance, please contact a server administrator.
opends/resource/messages/account-permanently-locked.template
New file
@@ -0,0 +1,5 @@
Your directory account has been locked as a result of too many failed
authentication attempts.
Please contact an administrator to have your password reset.
opends/resource/messages/account-reset-locked.template
New file
@@ -0,0 +1,5 @@
Your directory account has been locked because you did not change your
password in a timely manner after it was reset by an administrator.
Please contact a server administrator to have the password reset again.
opends/resource/messages/account-temporarily-locked.template
New file
@@ -0,0 +1,6 @@
Your directory account has been temporarily locked as a result of too many
failed authentication attempts.  It will automatically be unlocked in
%%notification-property:time-until-unlock%%.
For further assistance, please contact a server administrator.
opends/resource/messages/account-unlocked.template
New file
@@ -0,0 +1,3 @@
Your directory account has been unlocked by a server administrator.  If
you have any further questions, please contact an administrator.
opends/resource/messages/password-changed.template
New file
@@ -0,0 +1,5 @@
Your directory password has been successfully updated.
If you did not request that your password be changed, then contact a
server administrator for further assistance.
opends/resource/messages/password-expired.template
New file
@@ -0,0 +1,3 @@
Your directory password has expired.  Please contact a server
administrator to have your password reset.
opends/resource/messages/password-expiring.template
New file
@@ -0,0 +1,7 @@
Your directory password will expire in %%notification-property:time-until-expiration%%.
Please change your password before %%notification-property:password-expiration-time%%
so that it does not expire.
For further assistance, please contact a directory administrator.
opends/resource/messages/password-reset.template
New file
@@ -0,0 +1,3 @@
Your directory password has been successfully reset by an administrator.
If you need further assistance, please contact a server administrator.
opends/resource/schema/02-config.ldif
@@ -1511,8 +1511,7 @@
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.448 NAME 'ds-cfg-recipient-address'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.449 NAME 'ds-cfg-message-subject'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
  X-ORIGIN 'OpenDS Directory Server' )
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.450 NAME 'ds-cfg-message-body'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
  X-ORIGIN 'OpenDS Directory Server' )
@@ -1577,6 +1576,16 @@
  NAME 'ds-cfg-backend-compact-encoding'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.476
  NAME 'ds-cfg-email-address-attribute-type'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.477
  NAME 'ds-cfg-send-notification-without-end-user-address'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.478
  NAME 'ds-cfg-message-template-file' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
  NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
  MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
@@ -2218,3 +2227,12 @@
  STRUCTURAL MUST ds-cfg-unique-attribute-type
  MAY ds-cfg-unique-attribute-base-dn
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.123
  NAME 'ds-cfg-smtp-account-status-notification-handler'
  SUP ds-cfg-account-status-notification-handler
  MUST ( ds-cfg-sender-address $
  ds-cfg-send-notification-without-end-user-address $
  ds-cfg-message-template-file ) MAY ( ds-cfg-email-address-attribute-type $
  ds-cfg-recipient-address $ ds-cfg-message-subject )
  X-ORIGIN 'OpenDS Directory Server' )
opends/src/admin/defn/org/opends/server/admin/std/SMTPAccountStatusNotificationHandlerConfiguration.xml
New file
@@ -0,0 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
! CDDL HEADER START
!
! The contents of this file are subject to the terms of the
! Common Development and Distribution License, Version 1.0 only
! (the "License").  You may not use this file except in compliance
! with the License.
!
! You can obtain a copy of the license at
! trunk/opends/resource/legal-notices/OpenDS.LICENSE
! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! When distributing Covered Code, include this CDDL HEADER in each
! file and include the License file at
! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
! add the following below this CDDL HEADER, with the fields enclosed
! by brackets "[]" replaced with your own identifying information:
!      Portions Copyright [yyyy] [name of copyright owner]
!
! CDDL HEADER END
!
!
!      Portions Copyright 2007 Sun Microsystems, Inc.
! -->
<adm:managed-object name="smtp-account-status-notification-handler"
                    plural-name="smtp-account-status-notification-handlers"
                    extends="account-status-notification-handler"
                    package="org.opends.server.admin.std"
                    xmlns:adm="http://www.opends.org/admin"
                    xmlns:ldap="http://www.opends.org/admin-ldap">
  <adm:synopsis>
    <adm:user-friendly-name />
    is an account status notification handler that can be used to send email
    messages to end users and/or administrators whenever an account status
    notification is generated.
  </adm:synopsis>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:oid>1.3.6.1.4.1.26027.1.2.123</ldap:oid>
      <ldap:name>
        ds-cfg-smtp-account-status-notification-handler
      </ldap:name>
      <ldap:superior>
        ds-cfg-account-status-notification-handler
      </ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="notification-handler-class">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.extensions.SMTPAccountStatusNotificationHandler
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property name="email-address-attribute-type" mandatory="false"
                multi-valued="true">
    <adm:synopsis>
      Specifies which attribute in user entries may be used to obtain the email
      address to use when notifying the end user.  Multiple attributes can be
      specified as separate values, and in that case all email addresses
      identified in all such values will receive the notification.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:alias>
        <adm:synopsis>
          If no email address attribute types are specified, then no attempt
          will be made to send email notification messages to end users.  Only
          those users specified in the set of additional recipient addresses
          will be sent the notification messages.
        </adm:synopsis>
      </adm:alias>
    </adm:default-behavior>
    <adm:syntax>
      <adm:attribute-type />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.476</ldap:oid>
        <ldap:name>ds-cfg-email-address-attribute-type</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="recipient-address" mandatory="false" multi-valued="true">
    <adm:synopsis>
      Specifies an email address to which notification messages will be sent,
      either instead of or in addition to the end user for whom the notification
      has been generated.  This may be used to ensure that server administrators
      also receive a copy of any notification messages that are generated.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:alias>
        <adm:synopsis>
          If no additional recipient addresses are specified, then only the end
          users that are the subjects of the account status notifications will
          receive the notification messages.
        </adm:synopsis>
      </adm:alias>
    </adm:default-behavior>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.448</ldap:oid>
        <ldap:name>ds-cfg-recipient-address</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="send-message-without-end-user-address" mandatory="true"
                multi-valued="false">
    <adm:synopsis>
      Indicates whether an email notification message should be generated and
      sent to the set of notification recipients even if the user entry does not
      contain any values for any of the email address attributes (and therefore
      it will not be possible to notify the end user).  This is only applicable
      if both one or more email address attribute types and one or more
      additional recipient addresses are specified.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          true
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:boolean />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.477</ldap:oid>
        <ldap:name>ds-cfg-send-message-without-end-user-address</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="sender-address" mandatory="true" multi-valued="false">
    <adm:synopsis>
      Specifies the e-mail address from which the message will be sent.  Note
      that this does not necessarily have to be a legitimate e-mail address.
    </adm:synopsis>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.447</ldap:oid>
        <ldap:name>ds-cfg-sender-address</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="message-subject" mandatory="true" multi-valued="true">
    <adm:synopsis>
      Specifies the subject that should be used for email messages generated by
      this account status notification handler.  The values for this property
      should begin with the name of an account status notification type followed
      by a colon and the subject that should be used for the associated
      notification message.  If an email message is generated for an account
      status notification type for which no subject is defined, then that
      message will be given a generic subject.
    </adm:synopsis>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.449</ldap:oid>
        <ldap:name>ds-cfg-message-subject</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="message-template-file" mandatory="true"
                multi-valued="true">
    <adm:synopsis>
      Specifies the path to the file containing the message template that is to
      be used to generate the email notification messages.  The values for this
      property should begin with the name of an account status notification type
      followed by a colon and the path to the template file that should be used
      for that notification type.  If an account status notification has a
      notification type that is not associated with a message template file,
      then no email message will be generated for that notification.
    </adm:synopsis>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.478</ldap:oid>
        <ldap:name>ds-cfg-message-template-file</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opends/src/messages/messages/extension.properties
@@ -1733,3 +1733,48 @@
 searchable and should not be included in otherwise unindexed search filters
MILD_ERR_HASSUBORDINATES_VATTR_NOT_SEARCHABLE_542=The %s attribute is not \
 searchable and should not be included in otherwise unindexed search filters
MILD_ERR_SMTP_ASNH_NO_MAIL_SERVERS_CONFIGURED_543=The SMTP account status \
 notification handler defined in configuration entry %s cannot be enabled \
 unless the Directory Server is with information about one or more SMTP servers
MILD_ERR_SMTP_ASNH_NO_RECIPIENTS_544=SMTP account status notification handler \
 configuration entry '%s' does not include any email address attribute types \
 or recipient addresses.  At least one of these must be provided
MILD_ERR_SMTP_ASNH_SUBJECT_NO_COLON_545=Unable to parse message subject value \
 '%s' from configuration entry '%s' because the value does not contain a \
 colon to separate the notification type from the subject
MILD_ERR_SMTP_ASNH_SUBJECT_INVALID_NOTIFICATION_TYPE_546=Unable to parse \
 message subject value '%s' from configuration entry '%s' because '%s' is not \
 a valid account status notification type
MILD_ERR_SMTP_ASNH_SUBJECT_DUPLICATE_TYPE_547=The message subject definitions \
 contained in configuration entry '%s' have multiple subjects defined for \
 notification type %s
MILD_ERR_SMTP_ASNH_TEMPLATE_NO_COLON_548=Unable to parse message template \
 file path value '%s' from configuration entry '%s' because the value does \
 not contain a colon to separate the notification type from the template file \
 path
MILD_ERR_SMTP_ASNH_TEMPLATE_INVALID_NOTIFICATION_TYPE_549=Unable to parse \
 message template file path value '%s' from configuration entry '%s' because \
 '%s' is not a valid account status notification type
MILD_ERR_SMTP_ASNH_TEMPLATE_DUPLICATE_TYPE_550=The message template file path \
 definitions contained in configuration entry '%s' have multiple template \
 file paths defined for notification type %s
MILD_ERR_SMTP_ASNH_TEMPLATE_NO_SUCH_FILE_551=The message template file '%s' \
 referenced in configuration entry '%s' does not exist
MILD_ERR_SMTP_ASNH_TEMPLATE_UNCLOSED_TOKEN_552=An unclosed token was found \
 starting at column %d of line %d
MILD_ERR_SMTP_ASNH_TEMPLATE_UNDEFINED_ATTR_TYPE_553=The \
 notification-user-attr token starting at column %d of line %d references \
 undefined attribute type %s
MILD_ERR_SMTP_ASNH_TEMPLATE_UNDEFINED_PROPERTY_554=The \
 notification-property token starting at column %d of line %d references \
 undefined notification property %s
MILD_ERR_SMTP_ASNH_TEMPLATE_UNRECOGNIZED_TOKEN_555=An unrecognized token %s \
 was found at column %d of line %d
MILD_ERR_SMTP_ASNH_TEMPLATE_CANNOT_PARSE_556=An error occurred while \
 attempting to parse message template file '%s' referenced in configuration \
 entry '%s':  %s
INFO_SMTP_ASNH_DEFAULT_SUBJECT_557=Directory Account Status Notification
SEVERE_ERR_SMTP_ASNH_CANNOT_SEND_MESSAGE_558=An error occurred while \
 attempting to send an account status notification message for notification \
 type %s for user entry %s:  %s
opends/src/server/org/opends/server/extensions/NotificationMessageNotificationMessageTemplateElement.java
New file
@@ -0,0 +1,62 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
/**
 * This class implements a notification message template element that will
 * generate a value that is the message for the account status notification.
 */
public class NotificationMessageNotificationMessageTemplateElement
       extends NotificationMessageTemplateElement
{
  /**
   * Creates a new notification message notification message template element.
   */
  public NotificationMessageNotificationMessageTemplateElement()
  {
    // No implementation is required.
  }
  /**
   * {@inheritDoc}
   */
  public void generateValue(MessageBuilder buffer,
                            AccountStatusNotification notification)
  {
    buffer.append(notification.getMessage());
  }
}
opends/src/server/org/opends/server/extensions/NotificationMessageTemplateElement.java
New file
@@ -0,0 +1,54 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
/**
 * This class defines the base class for elements that may be used to generate
 * an account status notification message.
 */
public abstract class NotificationMessageTemplateElement
{
  /**
   * Generates a value for this template element using the information contained
   * in the provided account status notification and appends it to the given
   * buffer.
   *
   * @param  buffer        The buffer to which the generated value should be
   *                       appended.
   * @param  notification  The account status notification to process.
   */
  public abstract void generateValue(MessageBuilder buffer,
                                     AccountStatusNotification notification);
}
opends/src/server/org/opends/server/extensions/NotificationPropertyNotificationMessageTemplateElement.java
New file
@@ -0,0 +1,78 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.List;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
import org.opends.server.types.AccountStatusNotificationProperty;
/**
 * This class implements a notification message template element that will
 * generate a value that is the value of a specified notification property.
 */
public class NotificationPropertyNotificationMessageTemplateElement
       extends NotificationMessageTemplateElement
{
  // The account status notification property for which to obtain the value.
  private AccountStatusNotificationProperty property;
  /**
   * Creates a new notification property notification message template element.
   *
   * @param  property  The notification property for which to obtain the value.
   */
  public NotificationPropertyNotificationMessageTemplateElement(
              AccountStatusNotificationProperty property)
  {
    this.property = property;
  }
  /**
   * {@inheritDoc}
   */
  public void generateValue(MessageBuilder buffer,
                            AccountStatusNotification notification)
  {
    List<String> propertyValues =
         notification.getNotificationProperty(property);
    if ((propertyValues != null) && (! propertyValues.isEmpty()))
    {
      buffer.append(propertyValues.get(0));
    }
  }
}
opends/src/server/org/opends/server/extensions/NotificationTypeNotificationMessageTemplateElement.java
New file
@@ -0,0 +1,62 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
/**
 * This class implements a notification message template element that will
 * generate a value that is the name of the account status notification type.
 */
public class NotificationTypeNotificationMessageTemplateElement
       extends NotificationMessageTemplateElement
{
  /**
   * Creates a new notification type notification message template element.
   */
  public NotificationTypeNotificationMessageTemplateElement()
  {
    // No implementation is required.
  }
  /**
   * {@inheritDoc}
   */
  public void generateValue(MessageBuilder buffer,
                            AccountStatusNotification notification)
  {
    buffer.append(notification.getNotificationType().getName());
  }
}
opends/src/server/org/opends/server/extensions/SMTPAccountStatusNotificationHandler.java
New file
@@ -0,0 +1,792 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.AccountStatusNotificationHandlerCfg;
import org.opends.server.admin.std.server.
            SMTPAccountStatusNotificationHandlerCfg;
import org.opends.server.api.AccountStatusNotificationHandler;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.AccountStatusNotification;
import org.opends.server.types.AccountStatusNotificationProperty;
import org.opends.server.types.AccountStatusNotificationType;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.Entry;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
import org.opends.server.util.EMailMessage;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class provides an implementation of an account status notification
 * handler that can send e-mail messages via SMTP to end users and/or
 * administrators whenever an account status notification occurs.  The e-mail
 * messages will be generated from template files, which contain the information
 * to use to create the message body.  The template files may contain plain
 * text, in addition to the following tokens:
 * <UL>
 *   <LI>%%notification-type%% -- Will be replaced with the name of the
 *       account status notification type for the notification.</LI>
 *   <LI>%%notification-message%% -- Will be replaced with the message for the
 *       account status notification.</LI>
 *   <LI>%%notification-user-dn%% -- Will be replaced with the string
 *       representation of the DN for the user that is the target of the
 *       account status notification.</LI>
 *   <LI>%%notification-user-attr:attrname%% -- Will be replaced with the value
 *       of the attribute specified by attrname from the user's entry.  If the
 *       specified attribute has multiple values, then the first value
 *       encountered will be used.  If the specified attribute does not have any
 *       values, then it will be replaced with an emtpy string.</LI>
 *   <LI>%%notification-property:propname%% -- Will be replaced with the value
 *       of the specified notification property from the account status
 *       notification.  If the specified property has multiple values, then the
 *       first value encountered will be used.  If the specified property does
 *       not have any values, then it will be replaced with an emtpy
 *       string.</LI>
 * </UL>
 */
public class SMTPAccountStatusNotificationHandler
       extends AccountStatusNotificationHandler
                    <SMTPAccountStatusNotificationHandlerCfg>
       implements ConfigurationChangeListener
                       <SMTPAccountStatusNotificationHandlerCfg>
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  // A mapping between the notification types and the message template.
  private HashMap<AccountStatusNotificationType,
                  List<NotificationMessageTemplateElement>> templateMap;
  // A mapping between the notification types and the message subject.
  private HashMap<AccountStatusNotificationType,String> subjectMap;
  // The current configuration for this account status notification handler.
  private SMTPAccountStatusNotificationHandlerCfg currentConfig;
  /**
   * Creates a new, uninitialized instance of this account status notification
   * handler.
   */
  public SMTPAccountStatusNotificationHandler()
  {
    super();
  }
  /**
   * {@inheritDoc}
   */
  public void initializeStatusNotificationHandler(
                   SMTPAccountStatusNotificationHandlerCfg configuration)
         throws ConfigException, InitializationException
  {
    currentConfig = configuration;
    currentConfig.addSMTPChangeListener(this);
    subjectMap  = parseSubjects(configuration);
    templateMap = parseTemplates(configuration);
    // Make sure that the Directory Server is configured with information about
    // one or more mail servers.
    List<Properties> propList = DirectoryServer.getMailServerPropertySets();
    if ((propList == null) || propList.isEmpty())
    {
      throw new ConfigException(ERR_SMTP_ASNH_NO_MAIL_SERVERS_CONFIGURED.get(
                                     configuration.dn().toString()));
    }
    // Make sure that either an explicit recipient list or a set of email
    // address attributes were provided.
    Set<AttributeType> mailAttrs = configuration.getEmailAddressAttributeType();
    Set<String> recipients = configuration.getRecipientAddress();
    if (((mailAttrs == null) || mailAttrs.isEmpty()) &&
        ((recipients == null) || recipients.isEmpty()))
    {
      throw new ConfigException(ERR_SMTP_ASNH_NO_RECIPIENTS.get(
                                     configuration.dn().toString()));
    }
  }
  /**
   * Examines the provided configuration and parses the message subject
   * information from it.
   *
   * @param  configuration  The configuration to be examined.
   *
   * @return  A mapping between the account status notification type and the
   *          subject that should be used for messages generated for
   *          notifications with that type.
   *
   * @throws  ConfigException  If a problem occurs while parsing the subject
   *                           configuration.
   */
  private HashMap<AccountStatusNotificationType,String> parseSubjects(
               SMTPAccountStatusNotificationHandlerCfg configuration)
          throws ConfigException
  {
    HashMap<AccountStatusNotificationType,String> map =
         new HashMap<AccountStatusNotificationType,String>();
    for (String s : configuration.getMessageSubject())
    {
      int colonPos = s.indexOf(':');
      if (colonPos < 0)
      {
        throw new ConfigException(ERR_SMTP_ASNH_SUBJECT_NO_COLON.get(s,
                                       configuration.dn().toString()));
      }
      String notificationTypeName = s.substring(0, colonPos).trim();
      AccountStatusNotificationType t =
           AccountStatusNotificationType.typeForName(notificationTypeName);
      if (t == null)
      {
        throw new ConfigException(
                       ERR_SMTP_ASNH_SUBJECT_INVALID_NOTIFICATION_TYPE.get(
                            s, configuration.dn().toString(),
                            notificationTypeName));
      }
      else if (map.containsKey(t))
      {
        throw new ConfigException(ERR_SMTP_ASNH_SUBJECT_DUPLICATE_TYPE.get(
                                       configuration.dn().toString(),
                                       notificationTypeName));
      }
      map.put(t, s.substring(colonPos+1).trim());
      if (debugEnabled())
      {
        TRACER.debugInfo("Subject for notification type " + t.getName() +
                         ":  " + map.get(t));
      }
    }
    return map;
  }
  /**
   * Examines the provided configuration and parses the message template
   * information from it.
   *
   * @param  configuration  The configuration to be examined.
   *
   * @return  A mapping between the account status notification type and the
   *          template that should be used to generate messages for
   *          notifications with that type.
   *
   * @throws  ConfigException  If a problem occurs while parsing the template
   *                           configuration.
   */
  private HashMap<AccountStatusNotificationType,
                  List<NotificationMessageTemplateElement>> parseTemplates(
               SMTPAccountStatusNotificationHandlerCfg configuration)
          throws ConfigException
  {
    HashMap<AccountStatusNotificationType,
            List<NotificationMessageTemplateElement>> map =
         new HashMap<AccountStatusNotificationType,
                      List<NotificationMessageTemplateElement>>();
    for (String s : configuration.getMessageTemplateFile())
    {
      int colonPos = s.indexOf(':');
      if (colonPos < 0)
      {
        throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_NO_COLON.get(s,
                                       configuration.dn().toString()));
      }
      String notificationTypeName = s.substring(0, colonPos).trim();
      AccountStatusNotificationType t =
           AccountStatusNotificationType.typeForName(notificationTypeName);
      if (t == null)
      {
        throw new ConfigException(
                       ERR_SMTP_ASNH_TEMPLATE_INVALID_NOTIFICATION_TYPE.get(
                            s, configuration.dn().toString(),
                            notificationTypeName));
      }
      else if (map.containsKey(t))
      {
        throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_DUPLICATE_TYPE.get(
                                       configuration.dn().toString(),
                                       notificationTypeName));
      }
      String path = s.substring(colonPos+1).trim();
      File f = new File(path);
      if (! f.exists())
      {
        throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_NO_SUCH_FILE.get(
                                       path, configuration.dn().toString()));
      }
      map.put(t, parseTemplateFile(f));
      if (debugEnabled())
      {
        TRACER.debugInfo("Decoded template elment list for type " +
                         t.getName());
      }
    }
    return map;
  }
  /**
   * Parses the specified template file into a list of notification message
   * template elements.
   *
   * @param  f  A reference to the template file to be parsed.
   *
   * @return  A list of notification message template elements parsed from the
   *          specified file.
   *
   * @throws  ConfigException  If error occurs while attempting to parse the
   *                           template file.
   */
  private List<NotificationMessageTemplateElement> parseTemplateFile(File f)
          throws ConfigException
  {
    LinkedList<NotificationMessageTemplateElement> elementList =
         new LinkedList<NotificationMessageTemplateElement>();
    BufferedReader reader = null;
    try
    {
      reader = new BufferedReader(new FileReader(f));
      int lineNumber = 0;
      while (true)
      {
        String line = reader.readLine();
        if (line == null)
        {
          break;
        }
        if (debugEnabled())
        {
          TRACER.debugInfo("Read message template line " + line);
        }
        lineNumber++;
        int startPos = 0;
        while (startPos < line.length())
        {
          int delimPos = line.indexOf("%%", startPos);
          if (delimPos < 0)
          {
            if (debugEnabled())
            {
              TRACER.debugInfo("No more tokens -- adding text " +
                               line.substring(startPos));
            }
            elementList.add(new TextNotificationMessageTemplateElement(
                                     line.substring(startPos)));
            break;
          }
          else
          {
            if (delimPos > startPos)
            {
              if (debugEnabled())
              {
                TRACER.debugInfo("Adding text before token " +
                                 line.substring(startPos));
              }
              elementList.add(new TextNotificationMessageTemplateElement(
                                       line.substring(startPos, delimPos)));
            }
            int closeDelimPos = line.indexOf("%%", delimPos+1);
            if (closeDelimPos < 0)
            {
              // There was an opening %% but not a closing one.
              throw new ConfigException(
                             ERR_SMTP_ASNH_TEMPLATE_UNCLOSED_TOKEN.get(
                                  delimPos, lineNumber));
            }
            else
            {
              String tokenStr = line.substring(delimPos+2, closeDelimPos);
              String lowerTokenStr = toLowerCase(tokenStr);
              if (lowerTokenStr.equals("notification-type"))
              {
                if (debugEnabled())
                {
                  TRACER.debugInfo("Found a notification type token " +
                                   tokenStr);
                }
                elementList.add(
                     new NotificationTypeNotificationMessageTemplateElement());
              }
              else if (lowerTokenStr.equals("notification-message"))
              {
                if (debugEnabled())
                {
                  TRACER.debugInfo("Found a notification message token " +
                                   tokenStr);
                }
                elementList.add(
                  new NotificationMessageNotificationMessageTemplateElement());
              }
              else if (lowerTokenStr.equals("notification-user-dn"))
              {
                if (debugEnabled())
                {
                  TRACER.debugInfo("Found a notification user DN token " +
                                   tokenStr);
                }
                elementList.add(
                     new UserDNNotificationMessageTemplateElement());
              }
              else if (lowerTokenStr.startsWith("notification-user-attr:"))
              {
                String attrName = lowerTokenStr.substring(23);
                AttributeType attrType =
                     DirectoryServer.getAttributeType(attrName, false);
                if (attrType == null)
                {
                  throw new ConfigException(
                                 ERR_SMTP_ASNH_TEMPLATE_UNDEFINED_ATTR_TYPE.get(
                                      delimPos, lineNumber, attrName));
                }
                else
                {
                  if (debugEnabled())
                  {
                    TRACER.debugInfo("Found a user attribute token for  " +
                                     attrType.getNameOrOID() + " -- " +
                                     tokenStr);
                  }
                  elementList.add(
                       new UserAttributeNotificationMessageTemplateElement(
                                attrType));
                }
              }
              else if (lowerTokenStr.startsWith("notification-property:"))
              {
                String propertyName = lowerTokenStr.substring(22);
                AccountStatusNotificationProperty property =
                     AccountStatusNotificationProperty.forName(propertyName);
                if (property == null)
                {
                  throw new ConfigException(
                                 ERR_SMTP_ASNH_TEMPLATE_UNDEFINED_PROPERTY.get(
                                      delimPos, lineNumber, propertyName));
                }
                else
                {
                  if (debugEnabled())
                  {
                    TRACER.debugInfo("Found a notification property token " +
                                     "for " + propertyName + " -- " + tokenStr);
                  }
                  elementList.add(
                    new NotificationPropertyNotificationMessageTemplateElement(
                          property));
                }
              }
              else
              {
                throw new ConfigException(
                               ERR_SMTP_ASNH_TEMPLATE_UNRECOGNIZED_TOKEN.get(
                                    tokenStr, delimPos, lineNumber));
              }
              startPos = closeDelimPos + 2;
            }
          }
        }
        // We need to put a CRLF at the end of the line, as per the SMTP spec.
        elementList.add(new TextNotificationMessageTemplateElement("\r\n"));
      }
      return elementList;
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw new ConfigException(ERR_SMTP_ASNH_TEMPLATE_CANNOT_PARSE.get(
                                     f.getAbsolutePath(),
                                     currentConfig.dn().toString(),
                                     getExceptionMessage(e)));
    }
    finally
    {
      try
      {
        if (reader != null)
        {
          reader.close();
        }
      } catch (Exception e) {}
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationAcceptable(
                      AccountStatusNotificationHandlerCfg
                           configuration,
                      List<Message> unacceptableReasons)
  {
    SMTPAccountStatusNotificationHandlerCfg config =
         (SMTPAccountStatusNotificationHandlerCfg) configuration;
    return isConfigurationChangeAcceptable(config, unacceptableReasons);
  }
  /**
   * {@inheritDoc}
   */
  public void handleStatusNotification(AccountStatusNotification notification)
  {
    SMTPAccountStatusNotificationHandlerCfg config = currentConfig;
    HashMap<AccountStatusNotificationType,String> subjects = subjectMap;
    HashMap<AccountStatusNotificationType,
            List<NotificationMessageTemplateElement>> templates = templateMap;
    // First, see if the notification type is one that we handle.  If not, then
    // return without doing anything.
    AccountStatusNotificationType notificationType =
         notification.getNotificationType();
    List<NotificationMessageTemplateElement> templateElements =
         templates.get(notificationType);
    if (templateElements == null)
    {
      if (debugEnabled())
      {
        TRACER.debugInfo("No message template for notification type " +
                         notificationType.getName());
      }
      return;
    }
    // It is a notification that should be handled, so we can start generating
    // the e-mail message.  First, check to see if there are any mail attributes
    // that would cause us to send a message to the end user.
    LinkedList<String> recipients = new LinkedList<String>();
    Set<AttributeType> addressAttrs = config.getEmailAddressAttributeType();
    Set<String> recipientAddrs = config.getRecipientAddress();
    if ((addressAttrs != null) && (! addressAttrs.isEmpty()))
    {
      Entry userEntry = notification.getUserEntry();
      for (AttributeType t : addressAttrs)
      {
        List<Attribute> attrList = userEntry.getAttribute(t);
        if (attrList != null)
        {
          for (Attribute a : attrList)
          {
            for (AttributeValue v : a.getValues())
            {
              if (debugEnabled())
              {
                TRACER.debugInfo("Adding end user recipient " +
                                 v.getStringValue() + " from attr " +
                                 a.getNameWithOptions());
              }
              recipients.add(v.getStringValue());
            }
          }
        }
      }
      if (recipients.isEmpty())
      {
        if ((recipientAddrs == null) || recipientAddrs.isEmpty())
        {
          // There are no recipients at all, so there's no point in generating
          // the message.  Return without doing anything.
          if (debugEnabled())
          {
            TRACER.debugInfo("No end user recipients, and no explicit " +
                             "recipients");
          }
          return;
        }
        else
        {
          if (! config.isSendMessageWithoutEndUserAddress())
          {
            // We can't send the message to the end user, and the handler is
            // configured to not send only to administrators, so we shouln't
            // do anything.
            if (debugEnabled())
            {
              TRACER.debugInfo("No end user recipients, and shouldn't send " +
                               "without end user recipients");
            }
            return;
          }
        }
      }
    }
    // Next, add any explicitly-defined recipients.
    if (recipientAddrs != null)
    {
      if (debugEnabled())
      {
        for (String s : recipientAddrs)
        {
          TRACER.debugInfo("Adding explicit recipient " + s);
        }
      }
      recipients.addAll(recipientAddrs);
    }
    // Get the message subject to use.  If none is defined, then use a generic
    // subject.
    String subject = subjects.get(notificationType);
    if (subject == null)
    {
      subject = INFO_SMTP_ASNH_DEFAULT_SUBJECT.get().toString();
      if (debugEnabled())
      {
        TRACER.debugInfo("Using default subject of " + subject);
      }
    }
    else if (debugEnabled())
    {
      TRACER.debugInfo("Using per-type subject of " + subject);
    }
    // Generate the message body.
    MessageBuilder messageBody = new MessageBuilder();
    for (NotificationMessageTemplateElement e : templateElements)
    {
      e.generateValue(messageBody, notification);
    }
    // Create and send the e-mail message.
    EMailMessage message = new EMailMessage(config.getSenderAddress(),
                                            recipients, subject);
    message.setBody(messageBody);
    if (debugEnabled())
    {
      TRACER.debugInfo("Set message body of " + messageBody.toString());
    }
    try
    {
      message.send();
      if (debugEnabled())
      {
        TRACER.debugInfo("Successfully sent the message");
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      logError(ERR_SMTP_ASNH_CANNOT_SEND_MESSAGE.get(notificationType.getName(),
                    notification.getUserDN().toString(),
                    getExceptionMessage(e)));
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationChangeAcceptable(
                      SMTPAccountStatusNotificationHandlerCfg configuration,
                      List<Message> unacceptableReasons)
  {
    boolean configAcceptable = true;
    // Make sure that the Directory Server is configured with information about
    // one or more mail servers.
    List<Properties> propList = DirectoryServer.getMailServerPropertySets();
    if ((propList == null) || propList.isEmpty())
    {
      unacceptableReasons.add(ERR_SMTP_ASNH_NO_MAIL_SERVERS_CONFIGURED.get(
                                   configuration.dn().toString()));
      configAcceptable = false;
    }
    // Make sure that either an explicit recipient list or a set of email
    // address attributes were provided.
    Set<AttributeType> mailAttrs = configuration.getEmailAddressAttributeType();
    Set<String> recipients = configuration.getRecipientAddress();
    if (((mailAttrs == null) || mailAttrs.isEmpty()) &&
        ((recipients == null) || recipients.isEmpty()))
    {
      unacceptableReasons.add(ERR_SMTP_ASNH_NO_RECIPIENTS.get(
                                   configuration.dn().toString()));
      configAcceptable = false;
    }
    try
    {
      parseSubjects(configuration);
    }
    catch (ConfigException ce)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }
      unacceptableReasons.add(ce.getMessageObject());
      configAcceptable = false;
    }
    try
    {
      parseTemplates(configuration);
    }
    catch (ConfigException ce)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }
      unacceptableReasons.add(ce.getMessageObject());
      configAcceptable = false;
    }
    return configAcceptable;
  }
  /**
   * {@inheritDoc}
   */
  public ConfigChangeResult applyConfigurationChange(
              SMTPAccountStatusNotificationHandlerCfg configuration)
  {
    try
    {
      HashMap<AccountStatusNotificationType,String> subjects =
           parseSubjects(configuration);
      HashMap<AccountStatusNotificationType,
              List<NotificationMessageTemplateElement>> templates =
           parseTemplates(configuration);
      currentConfig = configuration;
      subjectMap    = subjects;
      templateMap   = templates;
      return new ConfigChangeResult(ResultCode.SUCCESS, false);
    }
    catch (ConfigException ce)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }
      LinkedList<Message> messageList = new LinkedList<Message>();
      messageList.add(ce.getMessageObject());
      return new ConfigChangeResult(ResultCode.UNWILLING_TO_PERFORM, false,
                                    messageList);
    }
  }
}
opends/src/server/org/opends/server/extensions/TextNotificationMessageTemplateElement.java
New file
@@ -0,0 +1,70 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
/**
 * This class implements a notification message template element that will
 * generate a value using static text.
 */
public class TextNotificationMessageTemplateElement
       extends NotificationMessageTemplateElement
{
  // The static text associated with this element.
  private final String text;
  /**
   * Creates a new text notification message template element from the provided
   * string.
   *
   * @param  text  The string to use as the text for this element.
   */
  public TextNotificationMessageTemplateElement(String text)
  {
    this.text = text;
  }
  /**
   * {@inheritDoc}
   */
  public void generateValue(MessageBuilder buffer,
                            AccountStatusNotification notification)
  {
    buffer.append(text);
  }
}
opends/src/server/org/opends/server/extensions/UserAttributeNotificationMessageTemplateElement.java
New file
@@ -0,0 +1,90 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.List;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Entry;
/**
 * This class implements a notification message template element that will
 * generate a value that is the value of a specified attribute from the target
 * user's entry.
 */
public class UserAttributeNotificationMessageTemplateElement
       extends NotificationMessageTemplateElement
{
  // The attribute type for which to obtain the value.
  private AttributeType attributeType;
  /**
   * Creates a new user DN notification message template element.
   *
   * @param  attributeType  The attribute type for which to obtain the value.
   */
  public UserAttributeNotificationMessageTemplateElement(AttributeType
                                                              attributeType)
  {
    this.attributeType = attributeType;
  }
  /**
   * {@inheritDoc}
   */
  public void generateValue(MessageBuilder buffer,
                            AccountStatusNotification notification)
  {
    Entry userEntry = notification.getUserEntry();
    List<Attribute> attrList = userEntry.getAttribute(attributeType);
    if (attrList != null)
    {
      for (Attribute a : attrList)
      {
        for (AttributeValue v : a.getValues())
        {
          buffer.append(v.getStringValue());
          return;
        }
      }
    }
  }
}
opends/src/server/org/opends/server/extensions/UserDNNotificationMessageTemplateElement.java
New file
@@ -0,0 +1,62 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AccountStatusNotification;
/**
 * This class implements a notification message template element that will
 * generate a value that is the string representation of the target user's DN.
 */
public class UserDNNotificationMessageTemplateElement
       extends NotificationMessageTemplateElement
{
  /**
   * Creates a new user DN notification message template element.
   */
  public UserDNNotificationMessageTemplateElement()
  {
    // No implementation is required.
  }
  /**
   * {@inheritDoc}
   */
  public void generateValue(MessageBuilder buffer,
                            AccountStatusNotification notification)
  {
    buffer.append(notification.getUserDN().toString());
  }
}
opends/src/server/org/opends/server/types/AccountStatusNotification.java
@@ -180,6 +180,26 @@
  /**
   * Retrieves the set of values for the specified account status
   * notification property.
   *
   * @param  property  The account status notification property for
   *                   which to retrieve the associated values.
   *
   * @return  The set of values for the specified account status
   *          notification property, or {@code null} if the specified
   *          property is not defined for this account status
   *          notification.
   */
  public List<String> getNotificationProperty(
                           AccountStatusNotificationProperty property)
  {
    return notificationProperties.get(property);
  }
  /**
   * Creates a set of account status notification properties from the
   * provided information.
   *
@@ -259,7 +279,7 @@
                       (1000*timeToExpiration);
        propList = new ArrayList<String>(1);
        propList.add(new Date(expTime).toString());
        props.put(ACCOUNT_UNLOCK_TIME, propList);
        props.put(PASSWORD_EXPIRATION_TIME, propList);
    }
    if ((oldPasswords != null) && (! oldPasswords.isEmpty()))
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -3526,11 +3526,6 @@
            else if (pwPolicyState.shouldWarn())
            {
              int numSeconds = pwPolicyState.getSecondsUntilExpiration();
              Message timeToExpiration = secondsToTimeString(numSeconds);
              Message message = INFO_BIND_PASSWORD_EXPIRING.get(
                      timeToExpiration);
              localOp.appendErrorMessage(message);
              if (pwPolicyWarningType == null)
              {
@@ -3785,7 +3780,7 @@
                int numSeconds = pwPolicyState.getSecondsUntilExpiration();
                Message timeToExpiration = secondsToTimeString(numSeconds);
                Message message = INFO_BIND_PASSWORD_EXPIRING.get(
                Message message = WARN_BIND_PASSWORD_EXPIRING.get(
                        timeToExpiration);
                pwPolicyState.generateAccountStatusNotification(
@@ -4164,11 +4159,6 @@
              else if (pwPolicyState.shouldWarn())
              {
                int numSeconds = pwPolicyState.getSecondsUntilExpiration();
                Message timeToExpiration = secondsToTimeString(numSeconds);
                Message message = INFO_BIND_PASSWORD_EXPIRING.get(
                        timeToExpiration);
                localOp.appendErrorMessage(message);
                if (pwPolicyWarningType == null)
                {
@@ -4204,7 +4194,7 @@
                int numSeconds = pwPolicyState.getSecondsUntilExpiration();
                Message timeToExpiration = secondsToTimeString(numSeconds);
                Message message = INFO_BIND_PASSWORD_EXPIRING.get(
                Message message = WARN_BIND_PASSWORD_EXPIRING.get(
                        timeToExpiration);
                pwPolicyState.generateAccountStatusNotification(