You will need the following files to compile the program:
 libldap.a (At least ldap v3.2)
 liblber.a (At least ldap v3.2)
 ldap.h
 lber.h
 ldapconfig.h
 TCL8.0 (TK8.0 optional)

All files (except tclAppInit.c) go in the "generic" directory.
The tclAppInit.c file goes in your platform-specific directory.
(i.e. unix, win, mac, vax, etc., etc., ad nauseum.)

You will need to make the following changes to the Makefile
in your platform-specific Makefile (or equivalent):

LIBS: (add)
 -lldap -llber

GENERIC_OBJS: (add)
tclLdapBind.o tclLdapDel.o tclLdapModRDN.o tclLdapSearch.o \
tclLdapUnBind.o tclLdapModify.o

GENERIC_SRCS: (add)
        $(GENERIC_DIR)/tclLdapBind.c \
        $(GENERIC_DIR)/tclLdapUnBind.c \
        $(GENERIC_DIR)/tclLdapDel.c \
        $(GENERIC_DIR)/tclLdapModRDN.c \
        $(GENERIC_DIR)/tclLdapSearch.c \
        $(GENERIC_DIR)/tclLdapModify.c \

# Object files used on all Unix systems: (add)
tclLdapBind.o: $(GENERIC_DIR)/tclLdapBind.c
        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLdapBind.c -llber -lldap

tclLdapUnBind.o: $(GENERIC_DIR)/tclLdapUnBind.c
        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLdapUnBind.c -llber -lldap

tclLdapDel.o: $(GENERIC_DIR)/tclLdapDel.c
        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLdapDel.c -llber -lldap

tclLdapModRDN.o: $(GENERIC_DIR)/tclLdapModRDN.c
        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLdapModRDN.c -llber -lldap

tclLdapSearch.o: $(GENERIC_DIR)/tclLdapSearch.c
        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLdapSearch.c -llber -lldap

tclLdapModify.o: $(GENERIC_DIR)/tclLdapModify.c
        $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLdapModify.c -llber -lldap

ALSO! ADD the LIBS to the tk8.0 Makefile if you want these functions in your
wish programs!!!

then, all you should have to do is re-compile the tclsh binary and then
re-compile the wish binary (you only need to re-compile the wish binary if
you want to have these functions available in tk).


FUNCTIONS PROVIDED:
The code that I ported into tcl/tk is actually the tools code built by the
University of Michigan stripped down and squashed into a standard tcl
function.  Some of the functionality in the tool code has been removed in
oder to simplify the conversion process.  (Also, things like sorting a search
really aren't necessary since I return the results as a list. (You can use
lsort to sort the results))

I will be putting the source code onto the TCL archives. 

The LdapBind command currently supports a maximum of 1024 simultaneous
connections to various LDAP servers.  This limitation is controlled by
an array called "ldprime".  The current number of connections is stored
in a variable called "ldcnt".  Both of these variables are global to all
of the LDAP tcl functions.  To change the maximum connections you must
change the array value of ldprime in ALL of the source files.  You must
also change the tclLdapBind.c file line "if (ldcnt > 1023) {" to reflect
your new maximum (minus 1).  WARNING! There is currently NO means of
reclaiming freed connection slots.  (It should be simple to do, I just
haven't gotten around to it yet.)  But with over 1000 connections to use
before you have to re-start the tclsh, it should be sufficient for most
needs.

/******************************************************************************/
Command:   LdapBind
Arguments: Host Port BindDN Password
Where:     Host = Hostname or IP address of the LDAP server
           Port = IP port the LDAP server is listening on (ex: 389)
         BindDN = Manager's (or whoever's) DN
       Password = Password for the BindDN
Results:
      data: Returns an integer number identifying the established connection.
    errors: Too many connections!
            Cannot connect to host
            Invalid name or password
  messages: None
Return codes:
  success: TCL_OK
  failure: TCL_ERROR
Note: Each argument to the LdapBind command can be a variable.
      Multiple connections can be established to the same or different hosts.
      Each LdapBind call will return a unique number associated with the
      connection that identifies the connection to the other Ldap commands.
Example:
set connection [LdapBind host1 389 "cn=mgr,o=org1,c=us" "mgrpwd"]
or
set connection [LdapBind $host $port $mgr $mgrpwd]
/******************************************************************************/

/******************************************************************************/
Command:   LdapUnBind
Arguments: ConnID
Where:   ConnID = Connection number returned from previous LdapBind
Results:
      data: None
    errors: Invalid connection number!
  messages: None
Return codes:
  success: TCL_OK
  failure: TCL_ERROR
Note: Each argument to the LdapUnBind command can be a variable.
      This command will close a connection made with a previous LdapBind.
Example:
LdapUnBind 0
or
LdapUnBind $connection
/******************************************************************************/

/******************************************************************************/
Command:   LdapDelete
Arguments: ConnectionID DN-to-delete
Where:   ConnID = Connection number returned from previous LdapBind
   DN-to-delete = kind of self-explanatory isn't it?
Results:
      data: None
    errors: Invalid connection number!
            Unable to delete entry
  messages: Entry deleted
Return codes:
  success: TCL_OK
  failure: TCL_ERROR
Note: Each argument to the LdapDelete command can be a variable.
Example:
LdapDelete 0 "cn=Joe Doe,ou=org2,o=org1,c=us"
or
LdapDelete $connection $dn
/******************************************************************************/

/******************************************************************************/
Command:   LdapModRDN
Arguments: ConnID DN RDN ReplaceFlag(1=replace,0=add)
Where:   ConnID = Connection number returned from previous LdapBind
             DN = FULL DN of original entry
            RDN = RELATIVE dn of new name
    ReplaceFlag = replace or add new name (1=replace, 0=add)
Results:  
      data: None
    errors: Invalid connection number!
            Unable to rename entry
  messages: Entry renamed
Return codes:
  success: TCL_OK
  failure: TCL_ERROR
Note: Each argument to the LdapModRDN command can be a variable.
Example:
LdapModRDN 0 "cn=Joe Doe,ou=org2,o=org1,c=us" "cn=Joseph Doe" 1
or
LdapModRDN $connection $dn $rdn $flag
/******************************************************************************/

/******************************************************************************/
Command:   LdapModify/LdapAdd
Arguments: ConnID DN [LIST of attr=value pairs]
Where:   ConnID = Connection number returned from previous LdapBind
             DN = FULL DN of entry to change/add
     Attributes = A tcl LIST of attr=value pairs (This MUST be a list!)
Results:  
      data: None
    errors: Invalid connection number!
            No LIST argument passed
            Problem with data
            Unable to add entry (FOR THE ADD SUB-FUNCTION)
            Unable to change entry
  messages: None
Return codes:
  success: TCL_OK
  failure: TCL_ERROR
Note: Each argument to the LdapModify/LdapAdd command can be a variable.
Example:
LdapModify 0 "cn=Joe Doe,ou=org2,o=org1,c=us" [list "sn=Jones" "telephoneNumber=+1 999 555 1212"]
or
set attrs [list "sn=Jones" "telephoneNumber=+1 999 555 1212"]
LdapModify $connection $dn $attrs
----
LdapAdd 0 "cn=Joe Doe,ou=org2,o=org1,c=us" [list "sn=Jones" "telephoneNumber=+1 999 555 1212"]
or
set attrs [list "sn=Jones" "telephoneNumber=+1 999 555 1212"]
LdapAdd $connection $dn $attrs

P.S. For the LdapModify command, if you place a minus "-" sign in front of an
attr=value pair, the LdapModify command will delete that attr=value.
(i.e. [list "-telephoneNumber=+1 999 555 1212"] will delete the phone number).
/******************************************************************************/

/******************************************************************************/
Command:   LdapSearch
Arguments: ConnID Scope Deref BaseDN Filter [LIST of Attrs to return (optional)]
Where:   ConnID = Connection number returned from previous LdapBind
          Scope = One of "base, one, or sub" (default is subtree)
          Deref = One of "never, search, find, or always" (default is never)
         BaseDN = DN of the starting point for the search
         Filter = Standard LDAP-style search filter
     Attributes = A tcl LIST of attribute NAMES (This MUST be a list! If this
                  option is left off, ALL attributes will be returned.)
Results:
      data: A tcl LIST of attr=value pairs.
            (If more than one ENTRY is returned, then the sets of attr=value
            pairs are still returned as ONE list with a NULL list element
            separating the entries.)
    errors: Invalid connection number!
            No LIST argument passed!
            Search failed
            Search failed to find anything
  messages: None
Return codes:
  success: TCL_OK
  failure: TCL_ERROR
Note: Each argument to the LdapSearch command can be a variable.
Example:
LdapSearch 0 sub never "o=org1,c=us" "cn=Joseph Doe" [list "sn" "telephoneNumber"]
or
set attrs [list "sn" "telephoneNumber"]
LdapSearch $connection $scope $deref $base $filter $attrs
(The above search would do a subtree search starting in the o=org1,c=us
 directory using the filter cn=Joseph Doe and return the
 attributes "sn" and "telephoneNumber")
(The same search without the "$attrs" would automatically return everything.)
/******************************************************************************/

ENJOY!

please send any suggestions/code enhancements to:
tmurray@ix.netcom.com
(Tony Murray)
