//Warning: This code has been marked up for HTML

/**************************************************************************
*  Novell Software Developer Kit
*
*  Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
*  THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
*  USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
*  ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
*  PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
*  ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
*  PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
*  DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
*  PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
*  CUSTOMERS WITH RESPECT TO THIS CODE.
*
* $name:         ModifyTimeStamp.java
* $description:  Description: ModifyTimeStamp.java shows how to modify an
*                attribute's value of LDAP Timestamp format.
*
*                LDAP Timestamp is in the form of "yyyymmddhhmmssZ". The
*                date and time specified in LDAP Timestamp is based on the
*                Coordinated Universal Time (UTC). The date and time
*                "Mon Jul 30 17:42:00 2001"  is represented in LDAP Time-
*                stamp as "20010730174200Z".
*
*                ModifyTimeStamp.java takes modifying an user's passwordExpira-
*                tionTime attribute for example. It first displays user's
*                passwordExpirationTime, then modifys user's passwordExpira-
*                tionTime attribute, finally displays newly modified
*                passwordExpirationTime.
*
*                Before running this sample, the passwordExpirationTime
*                attribute should be initialized.
*
*                The last parameter to this sample is a integer to be used
*                to extend the user's passwordExpirationTime. It can be a
*                positive, a zero, or a negative value.
******************************************************************************/
import java.util.Hashtable;
import java.util.Date;
import java.util.Calendar;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.ModificationItem;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;

class ModifyTimeStamp {
    public static void main(String[] args) {

    String expTime;

    if (args.length != 5) {
       usage();
    }

    String hostURL  = args[0];
    String loginDN  = args[1];
    String password = args[2];
    String userDN   = args[3];
    int    days     = Integer.parseInt( args[4]);

    try {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                      "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, hostURL);
        env.put( Context.SECURITY_PRINCIPAL, loginDN );
        env.put( Context.SECURITY_CREDENTIALS, password );

       // create the initial directory context

        DirContext ctx = new InitialDirContext(env);

        System.out.println( "\n    Entry DN: " + userDN );
        System.out.println( "    Day Extension: " + days + "\n" );

       // get user's passwordExpirationTime value

        if ( (expTime = GetTime( ctx, userDN )) == null )
        System.out.println("\n    passwordExpirationTime was not"
                               + " initialized.");
        else {
        System.out.println( "        Old passwordExpirationTime: "
                            + expTime + " (UTC)");
        printTime(expTime);

       // update passwordExpirationTime value

        String newExpTime = extendTime( expTime, days );

       // construct the ModificationItem

        ModificationItem[] mod = new ModificationItem[1];

       // prepare to modify passwordExpirationTime

        Attribute modPwdExpTime = new BasicAttribute(
                      "passwordExpirationTime", newExpTime);
        mod[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE,
                                 modPwdExpTime);

       // modify passwordExpiration attribute

        System.out.println();
        System.out.println( "    Modifying passwordExpirationTime..." );
        ctx.modifyAttributes(userDN, mod);
        System.out.println( "    Modification was successful." );

       // display user's new passwordExpiratioTime value

        if ( (newExpTime = GetTime( ctx, userDN )) == null )
            System.out.println("\n    Failed to get"
                       + " passwordExpirationTime value.");
        else {
            System.out.println( "\n        New"
            + " passwordExpirationTime: " + newExpTime + " (UTC)");
            printTime(newExpTime);
        }
        }
       // close the context

        ctx.close();
    }
    catch (NamingException e) {
        System.err.println("ModifyTimeStamp example failed.");
        e.printStackTrace();
    }
    finally {
        System.exit(0);
    }
    }

   // getTime() returns the passwordExpirationTime in LDAP Timestamp format.

    public static String GetTime(DirContext ctx, String entryDN) {

    String attrValue = null;
    String returnAttr[] = { "passwordExpirationTime" };

    try {
       // get entryDN's passwordExpirationTime attributes

        Attributes attrs = ctx.getAttributes( entryDN, returnAttr );

       // get Enumeration of returned attributes

        NamingEnumeration enu = attrs.getAll();

       // get passwordExpirationTime attributes value

        while ( enu.hasMore() ) {
        Attribute attr = (Attribute)enu.next();

       // get Enumeration of the attribute values

        NamingEnumeration attrValues = attr.getAll();
        attrValue = (String)attrValues.next();
        }
    }
    catch( NamingException e ) {
        System.out.println( "\n    Failed to read: " + entryDN );
        System.out.println( "\n    Error: " + e.toString() );
        System.exit(1);
    }
    return attrValue;
    }

   // printTime() takes utc as input and prints it in text format

    public static void printTime( String utc ) {
   // setup x.208 generalized time formatter

    DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss'Z'");

    try {
       // parse utc into Date

        Date date = formatter.parse( utc );
        System.out.print( "                                    ");
        System.out.println( date + " (UTC)");
    }
    catch(ParseException pe) {
        System.out.println( "\nError: " + pe.toString() );
    }
    }

   // extendTime() takes utc and days as input and returns updated utc

    public static String extendTime( String utc, int days ) {
   // utc is in the form of "20010706080000Z". get year,

   // month, day, hour, minute, and second from the utc

    int year   = Integer.parseInt( utc.substring(  0, 4  ));
    int mon    = Integer.parseInt( utc.substring(  4, 6  ));
    int day    = Integer.parseInt( utc.substring(  6, 8  ));
    int hour   = Integer.parseInt( utc.substring(  8, 10 ));
    int minute = Integer.parseInt( utc.substring( 10, 12 ));
    int second = Integer.parseInt( utc.substring( 12, 14 ));

    Calendar utcTime = Calendar.getInstance();
   // set calendar to the time

    utcTime.set( year, mon-1 , day, hour, minute, second );
   // add days to the expiration Time

    utcTime.add(Calendar.DAY_OF_MONTH, days );
    Date date = utcTime.getTime();
    DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
   // format date into LDAP Timestamp

    return formatter.format( date );
    }

    public static void usage() {
        System.err.println("\n Usage:   java ModifyTimeStamp <host URL> "
            + "<login dn> <password>\n          <user dn> <day extension>\n");
        System.err.println(" Example: java ModifyTimeStamp ldap://Acme.com:"
            + "389 \"cn=Admin,o=Acme\"\n          secret \"cn=JSmith,ou=sales,"
            + "o=Acme\" 90");
        System.exit(1);
    }
}