+DEFUN ("ldap-add", Fldap_add, 3, 3, 0, /*
+Add an entry to an LDAP directory.
+LDAP is an LDAP connection object created with `ldap-open'.
+DN is the distinguished name of the entry to add.
+ENTRY is an entry specification, i.e., a list of cons cells
+containing attribute/value string pairs.
+*/
+ (ldap, dn, entry))
+{
+ LDAP *ld;
+ LDAPMod *ldap_mods, **ldap_mods_ptrs;
+ struct berval *bervals;
+ int rc;
+ int i, j;
+ size_t len;
+
+ Lisp_Object current = Qnil;
+ Lisp_Object values = Qnil;
+ struct gcpro gcpro1, gcpro2;
+
+ GCPRO2 (current, values);
+
+ /* Do all the parameter checking */
+ CHECK_LIVE_LDAP (ldap);
+ ld = XLDAP (ldap)->ld;
+
+ /* Check the DN */
+ CHECK_STRING (dn);
+
+ /* Check the entry */
+ CHECK_CONS (entry);
+ if (NILP (entry))
+ signal_simple_error ("Cannot add void entry", entry);
+
+ /* Build the ldap_mods array */
+ len = XINT (Flength (entry));
+ ldap_mods = alloca_array (LDAPMod, len);
+ ldap_mods_ptrs = alloca_array (LDAPMod *, 1 + len);
+ i = 0;
+ EXTERNAL_LIST_LOOP (entry, entry)
+ {
+ current = XCAR (entry);
+ CHECK_CONS (current);
+ CHECK_STRING (XCAR (current));
+ ldap_mods_ptrs[i] = &(ldap_mods[i]);
+ LISP_STRING_TO_EXTERNAL (XCAR (current), ldap_mods[i].mod_type, Qnative);
+ ldap_mods[i].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
+ values = XCDR (current);
+ if (CONSP (values))
+ {
+ len = XINT (Flength (values));
+ bervals = alloca_array (struct berval, len);
+ ldap_mods[i].mod_vals.modv_bvals =
+ alloca_array (struct berval *, 1 + len);
+ j = 0;
+ EXTERNAL_LIST_LOOP (values, values)
+ {
+ current = XCAR (values);
+ CHECK_STRING (current);
+ ldap_mods[i].mod_vals.modv_bvals[j] = &(bervals[j]);
+ TO_EXTERNAL_FORMAT (LISP_STRING, current,
+ ALLOCA, (bervals[j].bv_val,
+ bervals[j].bv_len),
+ Qnative);
+ j++;
+ }
+ ldap_mods[i].mod_vals.modv_bvals[j] = NULL;
+ }
+ else
+ {
+ CHECK_STRING (values);
+ bervals = alloca_array (struct berval, 1);
+ ldap_mods[i].mod_vals.modv_bvals = alloca_array (struct berval *, 2);
+ ldap_mods[i].mod_vals.modv_bvals[0] = &(bervals[0]);
+ TO_EXTERNAL_FORMAT (LISP_STRING, values,
+ ALLOCA, (bervals[0].bv_val,
+ bervals[0].bv_len),
+ Qnative);
+ ldap_mods[i].mod_vals.modv_bvals[1] = NULL;
+ }
+ i++;
+ }
+ ldap_mods_ptrs[i] = NULL;
+ rc = ldap_add_s (ld, (char *) XSTRING_DATA (dn), ldap_mods_ptrs);
+ if (rc != LDAP_SUCCESS)
+ signal_ldap_error (ld, NULL, rc);
+
+ UNGCPRO;
+ return Qnil;
+}
+
+DEFUN ("ldap-modify", Fldap_modify, 3, 3, 0, /*
+Add an entry to an LDAP directory.
+LDAP is an LDAP connection object created with `ldap-open'.
+DN is the distinguished name of the entry to modify.
+MODS is a list of modifications to apply.
+A modification is a list of the form (MOD-OP ATTR VALUE1 VALUE2 ...)
+MOD-OP and ATTR are mandatory, VALUEs are optional depending on MOD-OP.
+MOD-OP is the type of modification, one of the symbols `add', `delete'
+or `replace'. ATTR is the LDAP attribute type to modify.
+*/
+ (ldap, dn, mods))
+{
+ LDAP *ld;
+ LDAPMod *ldap_mods, **ldap_mods_ptrs;
+ struct berval *bervals;
+ int i, j, rc;
+ Lisp_Object mod_op;
+ size_t len;
+
+ Lisp_Object current = Qnil;
+ Lisp_Object values = Qnil;
+ struct gcpro gcpro1, gcpro2;
+
+ /* Do all the parameter checking */
+ CHECK_LIVE_LDAP (ldap);
+ ld = XLDAP (ldap)->ld;
+
+ /* Check the DN */
+ CHECK_STRING (dn);
+
+ /* Check the entry */
+ CHECK_CONS (mods);
+ if (NILP (mods))
+ return Qnil;
+
+ /* Build the ldap_mods array */
+ len = XINT (Flength (mods));
+ ldap_mods = alloca_array (LDAPMod, len);
+ ldap_mods_ptrs = alloca_array (LDAPMod *, 1 + len);
+ i = 0;
+
+ GCPRO2 (current, values);
+ EXTERNAL_LIST_LOOP (mods, mods)
+ {
+ current = XCAR (mods);
+ CHECK_CONS (current);
+ CHECK_SYMBOL (XCAR (current));
+ mod_op = XCAR (current);
+ ldap_mods_ptrs[i] = &(ldap_mods[i]);
+ ldap_mods[i].mod_op = LDAP_MOD_BVALUES;
+ if (EQ (mod_op, Qadd))
+ ldap_mods[i].mod_op |= LDAP_MOD_ADD;
+ else if (EQ (mod_op, Qdelete))
+ ldap_mods[i].mod_op |= LDAP_MOD_DELETE;
+ else if (EQ (mod_op, Qreplace))
+ ldap_mods[i].mod_op |= LDAP_MOD_REPLACE;
+ else
+ signal_simple_error ("Invalid LDAP modification type", mod_op);
+ current = XCDR (current);
+ CHECK_STRING (XCAR (current));
+ LISP_STRING_TO_EXTERNAL (XCAR (current), ldap_mods[i].mod_type, Qnative);
+ values = XCDR (current);
+ len = XINT (Flength (values));
+ bervals = alloca_array (struct berval, len);
+ ldap_mods[i].mod_vals.modv_bvals =
+ alloca_array (struct berval *, 1 + len);
+ j = 0;
+ EXTERNAL_LIST_LOOP (values, values)
+ {
+ current = XCAR (values);
+ CHECK_STRING (current);
+ ldap_mods[i].mod_vals.modv_bvals[j] = &(bervals[j]);
+ TO_EXTERNAL_FORMAT (LISP_STRING, current,
+ ALLOCA, (bervals[j].bv_val,
+ bervals[j].bv_len),
+ Qnative);
+ j++;
+ }
+ ldap_mods[i].mod_vals.modv_bvals[j] = NULL;
+ i++;
+ }
+ ldap_mods_ptrs[i] = NULL;
+ rc = ldap_modify_s (ld, (char *) XSTRING_DATA (dn), ldap_mods_ptrs);
+ if (rc != LDAP_SUCCESS)
+ signal_ldap_error (ld, NULL, rc);
+
+ UNGCPRO;
+ return Qnil;
+}
+
+
+DEFUN ("ldap-delete", Fldap_delete, 2, 2, 0, /*
+Delete an entry to an LDAP directory.
+LDAP is an LDAP connection object created with `ldap-open'.
+DN is the distinguished name of the entry to delete.
+*/
+ (ldap, dn))
+{
+ LDAP *ld;
+ int rc;
+
+ /* Check parameters */
+ CHECK_LIVE_LDAP (ldap);
+ ld = XLDAP (ldap)->ld;
+ CHECK_STRING (dn);
+
+ rc = ldap_delete_s (ld, (char *) XSTRING_DATA (dn));
+ if (rc != LDAP_SUCCESS)
+ signal_ldap_error (ld, NULL, rc);
+
+ return Qnil;
+}